fix(assistant): a step that searched the web and called a tool no longer sends ChatGPT an answer to the search, which it refused

This commit is contained in:
Maurice
2026-10-24 09:41:02 +02:00
parent 42c73738af
commit c00a1309e5
2 changed files with 21 additions and 1 deletions
+3 -1
View File
@@ -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',
@@ -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']);
});
});