From ddf7e9593e467aef53dab7d2fb52b82c4d1ab901 Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 13 Aug 2026 00:50:23 +0200 Subject: [PATCH] fix(ai): handle statusless hosted search completions --- packages/ai/src/providers/openai-shared.ts | 2 +- .../openai-responses-stream-terminal.test.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/ai/src/providers/openai-shared.ts b/packages/ai/src/providers/openai-shared.ts index ad110bcd0..e6daa1348 100644 --- a/packages/ai/src/providers/openai-shared.ts +++ b/packages/ai/src/providers/openai-shared.ts @@ -3064,7 +3064,7 @@ export async function processResponsesStream( } closeOpenItem(event.output_index, item.id, entry, item.call_id, prefixedFunctionCallItemKey(item.call_id)); stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output }); - } else if (item.type === "web_search_call" && item.status === "completed") { + } else if (item.type === "web_search_call" && (item.status === undefined || item.status === "completed")) { // A completed provider-hosted web search is progress evidence even when // the model never surfaced an answer; the agent loop continues from it. sawCompletedWebSearchCall = true; diff --git a/packages/ai/test/openai-responses-stream-terminal.test.ts b/packages/ai/test/openai-responses-stream-terminal.test.ts index 0343611fb..b4bb0ba95 100644 --- a/packages/ai/test/openai-responses-stream-terminal.test.ts +++ b/packages/ai/test/openai-responses-stream-terminal.test.ts @@ -673,6 +673,28 @@ describe("processResponsesStream: terminal events", () => { expect(output.stopDetails).toEqual({ type: "pause_turn" }); }); + test("pauses a status-less hosted web search done item that has no visible assistant output", async () => { + const output = makeOutput(); + const stream = { push: () => {}, end: () => {} } as never; + + await processResponsesStream( + makeStream([ + { + type: "response.output_item.done", + output_index: 1, + item: { type: "web_search_call", id: "ws_1", action: { type: "search" } }, + }, + { type: "response.completed", response: { id: "resp_search", status: "completed" } }, + ]), + output, + stream, + makeModel(), + ); + + expect(output.stopReason).toBe("stop"); + expect(output.stopDetails).toEqual({ type: "pause_turn" }); + }); + test("finishes a hosted web search when the response includes visible output", async () => { const output = makeOutput(); const stream = { push: () => {}, end: () => {} } as never;