diff --git a/open-sse/translator/request/openai-responses.ts b/open-sse/translator/request/openai-responses.ts index 45beee74b0..97c0b77a27 100644 --- a/open-sse/translator/request/openai-responses.ts +++ b/open-sse/translator/request/openai-responses.ts @@ -77,13 +77,21 @@ export function openaiResponsesToOpenAIRequest( } } - if (root.background) { - throw unsupportedFeature( - "Unsupported Responses API feature: background mode is not supported by omniroute" - ); - } - const result: JsonRecord = { ...root }; + + // background: true requests a deferred Responses API run (the upstream + // returns 202 with response_id and the client polls GET /responses/). + // OmniRoute is a forward proxy that streams responses synchronously — + // implementing the queue/poll contract would require persistence and a + // separate retrieval surface. Degrade silently: strip the flag and run + // synchronously. The client receives the full response in one round-trip + // with status=completed. Clients that set background=true opportunistically + // (Capy Captain Pro, Codex agents) work unchanged. Clients that strictly + // require the async contract still observe a completed response on the + // first poll and can adapt. + if (result.background !== undefined) { + delete result.background; + } const messages: JsonRecord[] = []; result.messages = messages; diff --git a/tests/unit/translator-openai-responses-req.test.ts b/tests/unit/translator-openai-responses-req.test.ts index e66c4c7469..68863af30b 100644 --- a/tests/unit/translator-openai-responses-req.test.ts +++ b/tests/unit/translator-openai-responses-req.test.ts @@ -110,7 +110,7 @@ test("Responses -> Chat filters orphan tool outputs and supports role-based mess }); }); -test("Responses -> Chat rejects unsupported built-in tools and background mode", () => { +test("Responses -> Chat rejects unsupported built-in tools", () => { assert.throws( () => openaiResponsesToOpenAIRequest( @@ -124,20 +124,26 @@ test("Responses -> Chat rejects unsupported built-in tools and background mode", ), (error: any) => error.statusCode === 400 && error.errorType === "unsupported_feature" ); +}); - assert.throws( - () => - openaiResponsesToOpenAIRequest( - "gpt-4o", - { - input: [], - background: true, - }, - false, - null - ), - (error: any) => error.statusCode === 400 && error.errorType === "unsupported_feature" +test("Responses -> Chat strips background flag and degrades to synchronous execution", () => { + // Previously this threw 400 unsupported_feature. OmniRoute is a forward proxy + // and cannot host the deferred run + poll contract, so background=true is + // silently dropped and the request runs synchronously. Clients that set the + // flag opportunistically (Capy Captain Pro, Codex agents) work unchanged. + const result = openaiResponsesToOpenAIRequest( + "gpt-5.5", + { + input: [{ role: "user", content: [{ type: "input_text", text: "hi" }] }], + background: true, + }, + true, + null ); + const r = result as Record; + assert.equal(r.background, undefined, "background flag must be stripped from output"); + assert.ok(Array.isArray(r.messages), "translation must complete and produce messages"); + assert.equal((r.messages as unknown[]).length, 1, "user message must be preserved"); }); test("Chat -> Responses converts messages, tool calls, tool outputs, tools and pass-through params", () => {