Skip to content

Commit f8bfcd3

Browse files
committed
fix(copilot): keep model activity outcomes authoritative
1 parent b23f548 commit f8bfcd3

3 files changed

Lines changed: 40 additions & 8 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ describe('ToolCallItem', () => {
128128
/>
129129
)
130130

131-
expect(markup).toContain('Failed: Stopped checking invoices')
131+
expect(markup).toContain('Failed checking invoices')
132+
expect(markup).not.toContain('Stopped checking invoices')
132133
})
133134

134135
it('defensively applies the completed verb for every successful tool row', () => {

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,3 +843,25 @@ describe('normalizeToolActivityDescription', () => {
843843
expect(normalizeToolActivityDescription('🧪'.repeat(161))).toBeUndefined()
844844
})
845845
})
846+
847+
describe('model-authored activity outcomes', () => {
848+
it.each([
849+
['success', 'Checking invoices', 'Checked invoices'],
850+
['success', 'Check invoices', 'Completed: Check invoices'],
851+
['success', 'Reconciling invoices', 'Completed: Reconciling invoices'],
852+
['success', 'Revisando facturas', 'Completed: Revisando facturas'],
853+
['success', 'Stopped checking invoices', 'Completed checking invoices'],
854+
['success', 'Completed: Check invoices', 'Completed: Check invoices'],
855+
['error', 'Failed: Fetching invoices', 'Failed: Fetching invoices'],
856+
['error', 'Stopped checking invoices', 'Failed checking invoices'],
857+
['error', 'Completed checking invoices', 'Failed checking invoices'],
858+
['rejected', 'Failed checking invoices', 'Failed checking invoices'],
859+
['cancelled', 'Stopped reading notes', 'Stopped reading notes'],
860+
['interrupted', 'Completed: Check invoices', 'Stopped: Check invoices'],
861+
['skipped', 'Failed: Checking invoices', 'Skipped: Checking invoices'],
862+
])('projects %s once onto "%s"', (status, description, expected) => {
863+
const title = getToolStatusDisplayTitle('Fallback', status, 'read', description)
864+
expect(title).toBe(expected)
865+
expect(getToolStatusDisplayTitle(title, status, 'read', description)).toBe(expected)
866+
})
867+
})

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,11 +1408,8 @@ const COMPLETED_VERB_REWRITES: Record<string, string> = {
14081408
/**
14091409
* Rewrite a resolved display title to its past-tense form for a successfully
14101410
* completed tool call (e.g. "Querying logs for X" -> "Queried logs for X").
1411-
* Operates on the already-resolved title so enriched and persisted titles both
1412-
* work. Returns undefined when the title has no leading gerund rewrite — the
1413-
* caller keeps the original. Integration gateway descriptions are base-form
1414-
* verb phrases ("Read recent emails") whose first word never matches a gerund
1415-
* key, so they intentionally pass through unchanged.
1411+
* Returns undefined when no leading gerund rewrite is known; status formatting
1412+
* handles the fallback for model-authored and legacy titles.
14161413
*/
14171414
export function getToolCompletedTitle(title: string): string | undefined {
14181415
const spaceIndex = title.indexOf(' ')
@@ -1447,11 +1444,18 @@ function statesTerminalOutcome(title: string): boolean {
14471444
/** Apply one terminal outcome prefix while preserving already-resolved titles. */
14481445
function getToolOutcomeTitle(
14491446
title: string,
1450-
outcome: 'Failed' | 'Stopped' | 'Skipped',
1447+
outcome: 'Completed' | 'Failed' | 'Stopped' | 'Skipped',
14511448
preserveExistingOutcome: boolean
14521449
): string {
14531450
if (preserveExistingOutcome && statesTerminalOutcome(title)) return title
14541451
const firstWord = firstWordOf(title)
1452+
const statedOutcome = firstWord.replace(/:$/, '')
1453+
if (
1454+
!preserveExistingOutcome &&
1455+
(TERMINAL_TITLE_PREFIXES.has(statedOutcome) || statedOutcome === 'Completed')
1456+
) {
1457+
return outcome + title.slice(statedOutcome.length)
1458+
}
14551459
if (COMPLETED_VERB_REWRITES[firstWord]) {
14561460
return `${outcome} ${firstWord.charAt(0).toLowerCase()}${firstWord.slice(1)}${title.slice(firstWord.length)}`
14571461
}
@@ -1475,7 +1479,12 @@ export function getToolStatusDisplayTitle(
14751479
if (status === 'success' && toolName === 'browser_request_takeover') {
14761480
return 'Resumed browser control'
14771481
}
1478-
if (status === 'success') return getToolCompletedTitle(title) ?? title
1482+
if (status === 'success') {
1483+
return (
1484+
getToolCompletedTitle(title) ??
1485+
(description ? getToolOutcomeTitle(title, 'Completed', false) : title)
1486+
)
1487+
}
14791488
if (status === 'error' || status === 'rejected') {
14801489
return getToolOutcomeTitle(title, 'Failed', !description)
14811490
}

0 commit comments

Comments
 (0)