Skip to content

Commit aeec08a

Browse files
authored
fix(activity): simplify outcome summaries and show three actions (#7866)
1 parent 22c149a commit aeec08a

3 files changed

Lines changed: 78 additions & 34 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/activity-stream.test.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,24 +157,50 @@ describe.each(['mothership', 'workflow', 'browser', 'deploy'])('%s activity', (a
157157
render([tool('first'), tool('second')])
158158
advance(100)
159159
render([tool('first'), tool('second', status)])
160-
const outcome =
160+
const label =
161161
status === 'error' || status === 'rejected'
162-
? 'failed'
163-
: status === 'skipped'
164-
? 'skipped'
165-
: 'stopped'
166-
expect(header()?.textContent).toBe(`Reading first · 1 ${outcome}`)
162+
? 'Reading first'
163+
: `Reading first · 1 ${status === 'skipped' ? 'skipped' : 'stopped'}`
164+
expect(header()?.textContent).toBe(label)
167165
expect(container.querySelector('[class*="shimmer"]')).not.toBeNull()
168166
advance(1000)
169-
expect(header()?.textContent).toBe(`Reading first · 1 ${outcome}`)
167+
expect(header()?.textContent).toBe(label)
170168
}
171169
)
172170

173-
it('surfaces an earlier parallel failure while the latest call keeps working', () => {
171+
it('keeps earlier parallel failures in history without a summary badge', () => {
174172
render([tool('first'), tool('second')])
175173
advance(100)
176174
render([tool('first', 'error'), tool('second')])
177-
expect(header()?.textContent).toBe('Reading second · 1 failed')
175+
expect(header()?.textContent).toBe('Reading second')
176+
const trigger = container.querySelector<HTMLElement>('[role="button"]')!
177+
act(() => trigger.click())
178+
expect(container.querySelector('[data-state="open"]')?.textContent).toBe(
179+
'Failed reading firstReading second'
180+
)
181+
render([tool('first', 'error'), tool('second', 'success')], false)
182+
expect(header()?.textContent).toBe('Read files')
183+
expect(container.querySelector('[data-state="open"]')?.textContent).toBe(
184+
'Failed reading firstRead second'
185+
)
186+
})
187+
188+
it('shows three distinct actions and keeps the complete history available', () => {
189+
render(
190+
[
191+
tool('first', 'success'),
192+
{ ...tool('second', 'success'), toolName: 'grep' },
193+
{ ...tool('third', 'success'), toolName: 'terminal_run' },
194+
{ ...tool('fourth', 'success'), toolName: 'run_workflow' },
195+
],
196+
false
197+
)
198+
expect(header()?.textContent).toBe('Read files, searched files, ran commands +1 more')
199+
const trigger = container.querySelector<HTMLElement>('[role="button"]')!
200+
act(() => trigger.click())
201+
expect(container.querySelector('[data-state="open"]')?.textContent).toBe(
202+
'Read firstRead secondRead thirdRead fourth'
203+
)
178204
})
179205

180206
it('keeps narration from prematurely completing an open lane', () => {

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-activity-group.test.ts

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ function tool(toolName: string, status: ToolCallStatus = 'success'): ToolCallDat
1212
describe('getToolActivitySummary', () => {
1313
it('caps distinct actions in order and counts the remaining categories, not repeated calls', () => {
1414
expect(
15-
getToolActivitySummary([tool('read'), tool('terminal_run'), tool('read'), tool('grep')])
16-
).toBe('Read files, ran commands +1 more')
15+
getToolActivitySummary([
16+
tool('read'),
17+
tool('terminal_run'),
18+
tool('read'),
19+
tool('grep'),
20+
tool('browser_navigate'),
21+
])
22+
).toBe('Read files, ran commands, searched files +1 more')
1723
})
1824

1925
it('summarizes browser navigation and interactions without repeating actions', () => {
@@ -24,13 +30,16 @@ describe('getToolActivitySummary', () => {
2430
tool('browser_type'),
2531
tool('browser_navigate'),
2632
])
27-
).toBe('Navigated, read pages +1 more')
33+
).toBe('Navigated, read pages, entered text')
2834
})
2935

3036
it.each([
3137
[['browser_navigate', 'browser_read_text'], 'Navigated, read pages'],
3238
[['browser_read_text', 'browser_navigate'], 'Read, navigated pages'],
33-
[['browser_navigate', 'browser_read_text', 'browser_scroll'], 'Navigated, read pages +1 more'],
39+
[
40+
['browser_navigate', 'browser_read_text', 'browser_scroll'],
41+
'Navigated, read, scrolled pages',
42+
],
3443
[['browser_navigate', 'browser_type'], 'Navigated pages, entered text'],
3544
[['browser_navigate', 'browser_navigate'], 'Navigated pages'],
3645
[['read', 'browser_read_text'], 'Read files, read pages'],
@@ -46,7 +55,7 @@ describe('getToolActivitySummary', () => {
4655
tool('terminal_run', 'cancelled'),
4756
tool('browser_type', 'rejected'),
4857
])
49-
).toBe('Read files · 2 failed · 1 stopped')
58+
).toBe('Read files · 1 stopped')
5059
})
5160

5261
it('does not invent actions when all calls failed or were stopped', () => {
@@ -55,7 +64,22 @@ describe('getToolActivitySummary', () => {
5564
tool('apply_file_edit', 'error'),
5665
tool('terminal_run', 'interrupted'),
5766
])
58-
).toBe('Tool activity · 1 failed · 1 stopped')
67+
).toBe('Tool activity · 1 stopped')
68+
})
69+
70+
it('uses a neutral summary when every call failed', () => {
71+
expect(
72+
getToolActivitySummary([tool('run_workflow', 'error'), tool('terminal', 'rejected')])
73+
).toBe('Tool activity')
74+
})
75+
76+
it('does not infer tool failures from workflow results', () => {
77+
expect(
78+
getToolActivitySummary([
79+
tool('read'),
80+
{ ...tool('run_workflow'), result: { success: false, error: 'Workflow run failed' } },
81+
])
82+
).toBe('Read files, ran workflows')
5983
})
6084

6185
it('keeps an individual tool’s descriptive title', () => {
@@ -91,10 +115,10 @@ describe('getToolActivitySummary', () => {
91115
tool('deploy_as_api'),
92116
tool('table_rows'),
93117
])
94-
).toBe('Navigated pages, filled forms +5 more')
118+
).toBe('Navigated pages, filled forms, entered text +4 more')
95119
})
96120

97-
it('keeps failure and interruption counts visible when action categories are capped', () => {
121+
it('keeps interruption counts without failure badges when action categories are capped', () => {
98122
expect(
99123
getToolActivitySummary([
100124
tool('read'),
@@ -105,14 +129,14 @@ describe('getToolActivitySummary', () => {
105129
tool('wait', 'interrupted'),
106130
tool('browser_type', 'skipped'),
107131
])
108-
).toBe('Read files, searched files +2 more · 1 failed · 1 stopped · 1 skipped')
132+
).toBe('Read files, searched files, used the terminal +1 more · 1 stopped · 1 skipped')
109133
})
110134

111-
it('uses the same outcome wording for rejected individual and grouped calls', () => {
135+
it('keeps individual failures explicit without adding aggregate failure badges', () => {
112136
const rejected = { ...tool('terminal', 'rejected'), displayTitle: 'Running checks' }
113137
expect(getToolActivitySummary([rejected])).toBe('Failed running checks')
114138
expect(getToolActivitySummary([rejected, tool('read', 'skipped')])).toBe(
115-
'Tool activity · 1 failed · 1 skipped'
139+
'Tool activity · 1 skipped'
116140
)
117141
})
118142

@@ -124,7 +148,7 @@ describe('getToolActivitySummary', () => {
124148
{ ...tool('deploy_as_mcp'), params: { action: 'undeploy' } },
125149
tool('read'),
126150
])
127-
).toBe('Deployed workflows, undeployed workflows +1 more')
151+
).toBe('Deployed workflows, undeployed workflows, read files')
128152
})
129153

130154
it('describes terminal runs from their operation', () => {

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-activity-group.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { getActivityAttentionKey } from '@/app/workspace/[workspaceId]/home/comp
1010
import { getToolIcon } from '@/app/workspace/[workspaceId]/home/components/message-content/utils'
1111
import { type ToolCallData, ToolCallStatus } from '@/app/workspace/[workspaceId]/home/types'
1212

13-
const MAX_SUMMARY_ACTIONS = 2
13+
const MAX_SUMMARY_ACTIONS = 3
1414

1515
/** Summarize completed actions without describing failed or skipped work as successful. */
1616
export function getToolActivitySummary(tools: ToolCallData[]): string {
@@ -31,35 +31,29 @@ export function getToolActivitySummary(tools: ToolCallData[]): string {
3131
const summaryLabel = summary ? summary[0].toUpperCase() + summary.slice(1) : 'Tool activity'
3232
return [
3333
additionalActions > 0 ? `${summaryLabel} +${additionalActions} more` : summaryLabel,
34-
...getToolActivityOutcomes(tools),
34+
...getToolActivityInterruptions(tools),
3535
].join(' · ')
3636
}
3737

38-
function getToolActivityOutcomes(tools: ToolCallData[]): string[] {
39-
let failed = 0
38+
function getToolActivityInterruptions(tools: ToolCallData[]): string[] {
4039
let stopped = 0
4140
let skipped = 0
4241
for (const tool of tools) {
43-
if (tool.status === ToolCallStatus.error || tool.status === ToolCallStatus.rejected) failed++
44-
else if (tool.status === ToolCallStatus.cancelled || tool.status === ToolCallStatus.interrupted)
42+
if (tool.status === ToolCallStatus.cancelled || tool.status === ToolCallStatus.interrupted)
4543
stopped++
4644
else if (tool.status === ToolCallStatus.skipped) skipped++
4745
}
48-
return [
49-
...(failed ? [`${failed} failed`] : []),
50-
...(stopped ? [`${stopped} stopped`] : []),
51-
...(skipped ? [`${skipped} skipped`] : []),
52-
]
46+
return [...(stopped ? [`${stopped} stopped`] : []), ...(skipped ? [`${skipped} skipped`] : [])]
5347
}
5448

55-
/** Keep earlier parallel failures visible while the latest action continues. */
49+
/** Keep earlier interruptions visible while the latest action continues. */
5650
export function getActiveToolActivityTitle(
5751
label: string,
5852
tool: ToolCallData,
5953
tools: ToolCallData[]
6054
): string {
6155
return tool.status === ToolCallStatus.executing || tool.status === ToolCallStatus.success
62-
? [label, ...getToolActivityOutcomes(tools)].join(' · ')
56+
? [label, ...getToolActivityInterruptions(tools)].join(' · ')
6357
: label
6458
}
6559

0 commit comments

Comments
 (0)