Skip to content

Commit 4437b39

Browse files
committed
improvement(chat): name the query in the knowledge search row and list a reply's sources densely
1 parent 63f0159 commit 4437b39

6 files changed

Lines changed: 61 additions & 51 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/message-sources/message-sources.tsx

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,24 @@ const STRIP_FADE_CLASSES =
1515

1616
interface MessageSourcesProps {
1717
sources: readonly SourceTagData[]
18-
/** The question the reply answers; its terms are bolded in result cards. */
19-
query?: string
20-
/** Asks the agent about one cited document, when the surface can send a message. */
21-
onSummarize?: (prompt: string) => void
2218
}
2319

2420
/**
2521
* Footer listing every document a reply cited, once each. Sources that carry
26-
* a snippet — a search answer — are laid out as result cards; otherwise one
22+
* a title — a search answer — are laid out as one dense row per document, the
23+
* prose above having already cited each claim inline; otherwise one
2724
* horizontally scrolling row of {@link SourceChip}s that fades out at the
2825
* right edge instead of wrapping, so a long list stays a single quiet line
2926
* under the answer.
3027
*/
31-
export function MessageSources({ sources, query, onSummarize }: MessageSourcesProps) {
28+
export function MessageSources({ sources }: MessageSourcesProps) {
3229
if (sources.length === 0) return null
3330

3431
if (sources.some((source) => source.snippet)) {
3532
return (
36-
<div className='flex flex-col gap-0.5'>
33+
<div className='flex flex-col'>
3734
{sources.map((source) => (
38-
<SourceCard
39-
key={source.url}
40-
source={source}
41-
query={query}
42-
onSummarize={
43-
onSummarize
44-
? (cited) => onSummarize(`Summarize "${cited.title ?? cited.url}" (${cited.url})`)
45-
: undefined
46-
}
47-
/>
35+
<SourceCard key={source.url} source={source} dense />
4836
))}
4937
</div>
5038
)

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/source-card/source-card.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ interface SourceCardProps {
111111
query?: string
112112
/** Offers a Summarize action that asks the agent about this document. */
113113
onSummarize?: (source: SourceTagData) => void
114+
/**
115+
* One line per document: the mark, the title, and where it lives, with no
116+
* snippet. For a list under a reply whose prose already cites each claim.
117+
*/
118+
dense?: boolean
114119
}
115120

116121
/**
@@ -119,9 +124,9 @@ interface SourceCardProps {
119124
* who it is from, and when it last changed, and the passage that matched with
120125
* the query terms in bold. Actions stay out of the way until the row is
121126
* hovered or its title focused. The same row serves the composer's search
122-
* results and the footer of a reply that cited its sources with a snippet.
127+
* results and, in its dense form, the footer of a reply that cited sources.
123128
*/
124-
export function SourceCard({ source, query, onSummarize }: SourceCardProps) {
129+
export function SourceCard({ source, query, onSummarize, dense = false }: SourceCardProps) {
125130
const hostname = externalLinkHostname(source.url)
126131
const ConnectorIcon = source.connectorType
127132
? BRAND_ICON_BY_BASE_TYPE.get(source.connectorType)
@@ -133,20 +138,48 @@ export function SourceCard({ source, query, onSummarize }: SourceCardProps) {
133138
updatedAt ? formatDate(updatedAt) : null,
134139
].filter((part): part is string => Boolean(part))
135140

141+
const mark = ConnectorIcon ? (
142+
<BrandIcon icon={ConnectorIcon} className='size-[16px]' />
143+
) : hostname ? (
144+
<img
145+
src={faviconUrl(hostname, 32)}
146+
alt=''
147+
className='size-[16px] rounded-[3px]'
148+
onError={hideBrokenFavicon}
149+
/>
150+
) : null
151+
152+
if (dense) {
153+
return (
154+
<div className={cn(SOURCE_ROW_CLASSES, 'items-center py-1')}>
155+
<span className={chipIconSlotClass}>{mark}</span>
156+
<a
157+
href={source.url}
158+
target='_blank'
159+
rel='noopener noreferrer'
160+
data-source-link=''
161+
onClick={(event) => handleExternalLinkClick(event, source.url)}
162+
className='min-w-0 flex-1 text-[var(--text-primary)] text-sm no-underline underline-offset-2 hover:underline'
163+
>
164+
<OverflowText
165+
label={source.title?.trim() || sourceLabel(source)}
166+
focusTarget='nearest-interactive'
167+
/>
168+
</a>
169+
<OverflowText
170+
label={meta.join(' · ')}
171+
className='max-w-[40%] shrink-0 text-[var(--text-muted)] text-caption'
172+
/>
173+
<div className='flex flex-shrink-0 items-center opacity-0 transition-opacity group-focus-within/source:opacity-100 group-hover/source:opacity-100 [@media(hover:none)]:opacity-100'>
174+
<CopyLinkAction url={source.url} />
175+
</div>
176+
</div>
177+
)
178+
}
179+
136180
return (
137181
<div className={SOURCE_ROW_CLASSES}>
138-
<span className={SOURCE_ROW_MARK_CLASSES}>
139-
{ConnectorIcon ? (
140-
<BrandIcon icon={ConnectorIcon} className='size-[16px]' />
141-
) : hostname ? (
142-
<img
143-
src={faviconUrl(hostname, 32)}
144-
alt=''
145-
className='size-[16px] rounded-[3px]'
146-
onError={hideBrokenFavicon}
147-
/>
148-
) : null}
149-
</span>
182+
<span className={SOURCE_ROW_MARK_CLASSES}>{mark}</span>
150183
<div className='flex min-w-0 flex-1 flex-col gap-0.5'>
151184
<a
152185
href={source.url}

apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -834,8 +834,6 @@ interface MessageContentProps {
834834
onOptionSelect?: (id: string) => void
835835
onQuestionDismiss?: () => void
836836
onPhaseChange?: (phase: MessagePhase) => void
837-
/** The user message this reply answers, for the result cards' highlighting. */
838-
userQuery?: string
839837
/**
840838
* The message's actions row (copy/thumbs). Rendered here, in the thinking
841839
* slot's position, so at settle the shimmer and the actions trade places in
@@ -856,7 +854,6 @@ function MessageContentInner({
856854
credentialSubmission,
857855
credentialAbandoned,
858856
onOptionSelect,
859-
userQuery,
860857
onQuestionDismiss,
861858
onPhaseChange,
862859
actions,
@@ -1032,7 +1029,7 @@ function MessageContentInner({
10321029
})}
10331030
{sources.length > 0 && (
10341031
<div className={isStreaming ? 'animate-stream-fade-in' : undefined}>
1035-
<MessageSources sources={sources} query={userQuery} onSummarize={onOptionSelect} />
1032+
<MessageSources sources={sources} />
10361033
</div>
10371034
)}
10381035
</div>

apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ interface AssistantMessageRowProps {
204204
prepareContentForCopy: (content: string) => ClipboardContent
205205
isStreaming: boolean
206206
isLast: boolean
207-
precedingUserContent?: string
208207
/** Transcript-derived answers for this message's question card (renders the recap). */
209208
questionAnswers?: string[]
210209
/** Transcript-derived status payload for this message's credential card. */
@@ -221,7 +220,6 @@ const AssistantMessageRow = memo(function AssistantMessageRow({
221220
prepareContentForCopy,
222221
isStreaming,
223222
isLast,
224-
precedingUserContent,
225223
questionAnswers,
226224
credentialSubmission,
227225
credentialAbandoned,
@@ -297,7 +295,6 @@ const AssistantMessageRow = memo(function AssistantMessageRow({
297295
credentialSubmission={credentialSubmission}
298296
credentialAbandoned={credentialAbandoned}
299297
onOptionSelect={onOptionSelect}
300-
userQuery={precedingUserContent}
301298
onQuestionDismiss={handleQuestionDismiss}
302299
onPhaseChange={setPhase}
303300
actions={
@@ -307,7 +304,6 @@ const AssistantMessageRow = memo(function AssistantMessageRow({
307304
getCopyContent={getCopyContent}
308305
hasCopyContent={Boolean(getOrchestratorMessageText(blocks, message.content).trim())}
309306
prepareContentForCopy={prepareContentForCopy}
310-
userQuery={precedingUserContent}
311307
requestId={message.requestId}
312308
messageId={message.id}
313309
/>
@@ -556,16 +552,6 @@ export function MothershipChat({
556552
return out
557553
}, [messages])
558554

559-
const precedingUserContentByIndex = useMemo(() => {
560-
const out: Array<string | undefined> = []
561-
let lastUserContent: string | undefined
562-
for (const [index, message] of messages.entries()) {
563-
out[index] = lastUserContent
564-
if (message.role === 'user') lastUserContent = message.content
565-
}
566-
return out
567-
}, [messages])
568-
569555
/**
570556
* Pairs each assistant question/credential card with the user message that
571557
* completed it. The paired user message is hidden — the answered card IS the
@@ -810,7 +796,6 @@ export function MothershipChat({
810796
prepareContentForCopy={prepareContentForCopy}
811797
isStreaming={isStreamActive && isLast}
812798
isLast={isLast}
813-
precedingUserContent={precedingUserContentByIndex[index]}
814799
questionAnswers={interactionPairing.answersByIndex[index]}
815800
credentialSubmission={interactionPairing.credentialSubmissionByIndex[index]}
816801
credentialAbandoned={interactionPairing.credentialAbandonedByIndex[index]}

apps/sim/lib/copilot/tools/tool-display.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,12 @@ describe('getToolDisplayTitle for operation-driven tools', () => {
378378
expect(getToolDisplayTitle('manage_knowledge_base', { operation: 'query' })).toBe(
379379
'Searching knowledge base'
380380
)
381+
expect(
382+
getToolDisplayTitle('manage_knowledge_base', {
383+
operation: 'query',
384+
args: { query: 'volvo delivery process' },
385+
})
386+
).toBe('Searching knowledge base for volvo delivery process')
381387
expect(getToolDisplayTitle('manage_knowledge_base', { operation: 'sync_connector' })).toBe(
382388
'Syncing knowledge base connector'
383389
)

apps/sim/lib/copilot/tools/tool-display.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,11 @@ function knowledgeBaseTitle(args: ToolArgs): string {
301301
'file'
302302
)
303303

304+
const query = stringArg(operationArgs, 'query')
304305
const titles: Record<string, string> = {
305306
create: `Creating ${name || 'knowledge base'}`,
306307
get: 'Reading knowledge base',
307-
query: 'Searching knowledge base',
308+
query: query ? `Searching knowledge base for ${query}` : 'Searching knowledge base',
308309
add_file: `Adding ${fileTarget} to knowledge base`,
309310
update: 'Updating knowledge base',
310311
delete: `Deleting ${countedResourceTarget(operationArgs, 'knowledgeBaseIds', 'knowledge base', 'knowledge bases')}`,

0 commit comments

Comments
 (0)