From 77deaff4808cfa00b7a81c8545da2854ae57c0d8 Mon Sep 17 00:00:00 2001 From: Ege Arhan Date: Wed, 4 Nov 2026 17:30:58 +0300 Subject: [PATCH] fix(web-search): strip responses-lite header from OpenAI sidecar requests --- src/web-search/executor.ts | 8 ++++--- tests/web-search/web-search.test.ts | 37 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/web-search/executor.ts b/src/web-search/executor.ts index 6a1e11acf81..6e2a74e5ab2 100644 --- a/src/web-search/executor.ts +++ b/src/web-search/executor.ts @@ -1,5 +1,5 @@ import type { OcxProviderConfig } from "../types"; -import { mergeCodexSelectedHeaders } from "../codex/forward-transport-headers"; +import { CODEX_RESPONSES_LITE_HEADER, mergeCodexSelectedHeaders } from "../codex/forward-transport-headers"; import { signalWithTimeout, cancelBodyOnAbort } from "../lib/abort"; import { redactSecretString } from "../lib/redact"; import { sidecarEnter } from "../lib/sidecar-tracker"; @@ -84,9 +84,11 @@ export async function runWebSearch( if (settings.reserveCompatibility && settings.model === NATIVE_RESERVE_MODEL) { return { text: "", sources: [], error: "Luna Reserve compatibility is only available as a conversation model, not a search helper. Choose another search helper model." }; } - const headers = Object.fromEntries(mergeCodexSelectedHeaders( + const mergedHeaders = mergeCodexSelectedHeaders( { "Content-Type": "application/json", ...forwardProvider.headers }, selectedForwardHeaders, - )); + ); + mergedHeaders.delete(CODEX_RESPONSES_LITE_HEADER); + const headers = Object.fromEntries(mergedHeaders); const body = { model: settings.model, instructions: settings.describeImages ? BASE_INSTRUCTION + IMAGE_INSTRUCTION : BASE_INSTRUCTION, diff --git a/tests/web-search/web-search.test.ts b/tests/web-search/web-search.test.ts index 4e8a86920b9..a50b52ed2b8 100644 --- a/tests/web-search/web-search.test.ts +++ b/tests/web-search/web-search.test.ts @@ -725,6 +725,43 @@ test("OpenAI web-search execution uses the pinned canonical URL and selected cre expect(observedProtocol).toBe("http1.1"); }); +test("issue #8160 - OpenAI search helper strips responses-lite marker from merged headers", async () => { + const originalFetch = globalThis.fetch; + let capturedHeaders: Headers | undefined; + globalThis.fetch = (async (_url: any, init: any) => { + capturedHeaders = new Headers(init?.headers); + return new Response( + 'data: ' + JSON.stringify({ type: "response.completed", response: { status: "completed", output: [] } }) + '\n\n', + { headers: { "content-type": "text/event-stream" } }, + ); + }) as typeof fetch; + + try { + await runOpenAiWebSearch( + "synthetic query", + { type: "web_search" }, + { + adapter: "openai-responses", + authMode: "forward", + baseUrl: "https://chatgpt.com/backend-api/codex", + headers: { "x-openai-internal-codex-responses-lite": "true", "x-custom-test": "forwarded" }, + } as any, + new Headers({ + "x-openai-internal-codex-responses-lite": "true", + "chatgpt-account-id": "test-account", + }), + { model: "gpt-6.1-sol", reasoning: "low", timeoutMs: 1_000 }, + ); + + expect(capturedHeaders).toBeDefined(); + expect(capturedHeaders!.has("x-openai-internal-codex-responses-lite")).toBe(false); + expect(capturedHeaders!.get("chatgpt-account-id")).toBe("test-account"); + expect(capturedHeaders!.get("x-custom-test")).toBe("forwarded"); + } finally { + globalThis.fetch = originalFetch; + } +}); + async function collectSse(stream: ReadableStream): Promise<{ event?: string; data: Record }[]> { const reader = stream.getReader(); const decoder = new TextDecoder();