From c98f418bff310a11cb1e27c4f269d043e2cea6c0 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 26 Sep 2026 12:34:14 -0700 Subject: [PATCH 1/2] fix(slack-search): stop recovered tool failures from flagging the whole reply --- apps/sim/lib/slack-search/assistant-stream.test.ts | 4 ++-- apps/sim/lib/slack-search/assistant-stream.ts | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/sim/lib/slack-search/assistant-stream.test.ts b/apps/sim/lib/slack-search/assistant-stream.test.ts index 1ce1bb11cbb..9094cdddf75 100644 --- a/apps/sim/lib/slack-search/assistant-stream.test.ts +++ b/apps/sim/lib/slack-search/assistant-stream.test.ts @@ -355,7 +355,7 @@ describe('Slack tool progress', () => { expect(api.start).toHaveBeenCalledOnce() }) - it('reports failed tools without exposing arguments, account labels, or backend errors', async () => { + it('completes recovered tool failures without exposing arguments, account labels, or backend errors', async () => { const { stream } = setup() await stream.start() const call = toolCall() @@ -373,7 +373,7 @@ describe('Slack tool progress', () => { }, }) const chunks = deliveredChunks() - expect(chunks[1]).toEqual({ ...chunks[0], status: 'error' }) + expect(chunks[1]).toEqual({ ...chunks[0], status: 'complete' }) expect(JSON.stringify(chunks)).not.toContain('private') }) diff --git a/apps/sim/lib/slack-search/assistant-stream.ts b/apps/sim/lib/slack-search/assistant-stream.ts index c41c34975ae..14b9c09a108 100644 --- a/apps/sim/lib/slack-search/assistant-stream.ts +++ b/apps/sim/lib/slack-search/assistant-stream.ts @@ -237,13 +237,11 @@ export class SlackSearchAssistantStream { if (!existing || existing.chunk.status !== 'in_progress') return if (existing.toolName !== payload.toolName) throw new Error('Slack tool progress identity changed') - chunk = { - ...existing.chunk, - status: - payload.success && (!payload.status || payload.status === 'success') - ? 'complete' - : 'error', - } + /** + * The agent recovers from individual tool failures, and Slack collapses a timeline with any + * errored task under "Something went wrong"; only an interrupted answer reports an error. + */ + chunk = { ...existing.chunk, status: 'complete' } } this.toolProgress.set(payload.toolCallId, { toolName: payload.toolName, chunk }) /** Existing task updates can be delivered without waiting for preceding answer text. */ From 4cb1ad8f4357776ea7bb3216fd181f5ff8bae875 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 26 Sep 2026 12:44:30 -0700 Subject: [PATCH 2/2] test(slack-search): cover reply completing after a failed tool call --- .../sim/lib/slack-search/assistant-stream.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/sim/lib/slack-search/assistant-stream.test.ts b/apps/sim/lib/slack-search/assistant-stream.test.ts index 9094cdddf75..546ade764c4 100644 --- a/apps/sim/lib/slack-search/assistant-stream.test.ts +++ b/apps/sim/lib/slack-search/assistant-stream.test.ts @@ -372,8 +372,21 @@ describe('Slack tool progress', () => { output: { accountLabel: 'private account' }, }, }) + await stream.onEvent(toolCall('search_workspace', 'tool-2')) + await stream.onEvent(toolResult('search_workspace', 'tool-2')) + await stream.onEvent({ type: 'text', payload: { channel: 'assistant', text: 'Answer.' } }) + await stream.finish(result) const chunks = deliveredChunks() - expect(chunks[1]).toEqual({ ...chunks[0], status: 'complete' }) + const tasks = chunks.filter((chunk) => chunk.type === 'task_update') + expect(tasks.map((chunk) => chunk.status)).toEqual([ + 'in_progress', + 'complete', + 'in_progress', + 'complete', + ]) + expect(deliveredText()).toBe('Answer.') + expect(api.stop.mock.calls[0][5]).toEqual([]) + expect(api.stop.mock.calls[0][6]).toEqual([]) expect(JSON.stringify(chunks)).not.toContain('private') })