From c00a1309e591ea9e23cdfc069c2ebaecb1f0b60e Mon Sep 17 00:00:00 2001 From: Maurice Date: Sat, 24 Oct 2026 09:41:02 +0200 Subject: [PATCH] fix(assistant): a step that searched the web and called a tool no longer sends ChatGPT an answer to the search, which it refused --- server/src/nest/assistant/assistant-agent.ts | 4 +++- .../nest/assistant/assistant-agent.test.ts | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/server/src/nest/assistant/assistant-agent.ts b/server/src/nest/assistant/assistant-agent.ts index 07ec0bd4e..9835529f0 100644 --- a/server/src/nest/assistant/assistant-agent.ts +++ b/server/src/nest/assistant/assistant-agent.ts @@ -476,7 +476,9 @@ async function carryOn( const { text, calls, images } = answer; turn.history.push({ role: 'assistant', text, toolCalls: calls, providerState: step.providerState }); for (const part of step.parts) { - if (part.type !== 'tool-call') continue; + // A web search is the provider's own record, kept in the provider state; an answer to it would + // name a call the provider never made, and it refuses the next step over that. + if (part.type !== 'tool-call' || part.toolName === ASSISTANT_WEB_SEARCH_STEP) continue; const seen = images.get(part.toolCallId); turn.history.push({ role: 'tool', diff --git a/server/tests/unit/nest/assistant/assistant-agent.test.ts b/server/tests/unit/nest/assistant/assistant-agent.test.ts index 179520b87..14a0dc9a1 100644 --- a/server/tests/unit/nest/assistant/assistant-agent.test.ts +++ b/server/tests/unit/nest/assistant/assistant-agent.test.ts @@ -858,4 +858,22 @@ describe('runAgentLoop', () => { await runAgentLoop(unable.deps, unable.input, unable.writer, new AbortController().signal); expect(unable.requests[0]?.webSearch).toBe(false); }); + + it('ASTAGT-041: a step that searched the web and called a read answers only the read, never the search', async () => { + const t = setup( + [ + [ + { type: 'web-search', query: 'Mount Takao trails' }, + { type: 'tool-call', call: { id: 'call_1', name: 'list_places', args: { tripId: 1 } } }, + { type: 'finish', reason: 'tool-calls' }, + ], + [{ type: 'text-delta', delta: 'Trail 1 up, trail 6 down.' }], + ], + { webSearch: true }, + true, + ); + await runAgentLoop(t.deps, t.input, t.writer, new AbortController().signal); + const answers = t.requests[1].messages.filter((m) => m.role === 'tool'); + expect(answers.map((m) => (m as { toolCallId: string }).toolCallId)).toEqual(['call_1']); + }); });