From b5d03ed3f2ca88407d7633d813b30e1285375e12 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Sun, 31 May 2026 01:02:38 -0300 Subject: [PATCH] =?UTF-8?q?fix(translator):=20drop=20Codex=20image=5Fgener?= =?UTF-8?q?ation=20tool=20in=20Responses=E2=86=92Chat=20(#2950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex Desktop injects an image_generation hosted tool into every Responses API request (even text-only ones). The tool-type validator threw unsupportedFeature() (400) for it, breaking every Codex Desktop request. Mirror the tool_search handling: add IMAGE_GENERATION_TOOL_TYPES, allow it past the validator guard, and drop it from the tools array before forwarding to Chat Completions. Closes #2950 --- CHANGELOG.md | 5 ++ .../translator/request/openai-responses.ts | 11 +++- .../translator-openai-responses-req.test.ts | 50 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c98dbf799..4080cf0bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,11 @@ `claude-opus-4.6`) instead of the Responses API, which Copilot does not serve for non-OpenAI models (returned `[400]`). Native OpenAI `gpt-*` models keep the Responses API. (#2911) +- **translator/responses:** Codex Desktop injects an `image_generation` hosted + tool into every Responses API request (even text-only ones), which OmniRoute + rejected with `[400] image_generation tool type is not supported`. It is now + treated like `tool_search`: allowed past the tool-type validator and dropped + silently from the tools array before forwarding to Chat Completions. (#2950) ### ✨ New Features diff --git a/open-sse/translator/request/openai-responses.ts b/open-sse/translator/request/openai-responses.ts index 9c26c0084f..6ca8d927d2 100644 --- a/open-sse/translator/request/openai-responses.ts +++ b/open-sse/translator/request/openai-responses.ts @@ -18,6 +18,9 @@ const WEB_SEARCH_TOOL_TYPES = /^web_search/; // tool_search is a Responses API built-in sent by newer Codex clients; it has no Chat Completions // equivalent and must be silently dropped (not rejected with 400). const TOOL_SEARCH_TOOL_TYPES = /^tool_search/; +// image_generation is a Responses API hosted tool that Codex Desktop injects into every request +// (even text-only ones); it has no Chat Completions equivalent and must be silently dropped (#2950). +const IMAGE_GENERATION_TOOL_TYPES = /^image_generation/; function toRecord(value: unknown): JsonRecord { return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {}; @@ -85,6 +88,7 @@ export function openaiResponsesToOpenAIRequest( toolType !== "namespace" && !WEB_SEARCH_TOOL_TYPES.test(toolType) && !TOOL_SEARCH_TOOL_TYPES.test(toolType) && + !IMAGE_GENERATION_TOOL_TYPES.test(toolType) && !tool.function ) { throw unsupportedFeature( @@ -267,8 +271,11 @@ export function openaiResponsesToOpenAIRequest( .filter((toolValue) => { const tool = toRecord(toolValue); const toolType = toString(tool.type); - // tool_search has no Chat Completions equivalent; drop it silently (issue #2766). - return !TOOL_SEARCH_TOOL_TYPES.test(toolType); + // tool_search (#2766) and image_generation (#2950) are Responses API built-ins + // with no Chat Completions equivalent; drop them silently. + return ( + !TOOL_SEARCH_TOOL_TYPES.test(toolType) && !IMAGE_GENERATION_TOOL_TYPES.test(toolType) + ); }) .map((toolValue) => { const tool = toRecord(toolValue); diff --git a/tests/unit/translator-openai-responses-req.test.ts b/tests/unit/translator-openai-responses-req.test.ts index af898ccf52..a29b117a5a 100644 --- a/tests/unit/translator-openai-responses-req.test.ts +++ b/tests/unit/translator-openai-responses-req.test.ts @@ -747,3 +747,53 @@ test("Responses -> Chat: tool_search is stripped from output tools array (issue assert.equal(tools[0].type, "function"); assert.equal(tools[0].function.name, "foo"); }); + +// --- Issue #2950: image_generation built-in should be silently dropped --- + +test("Responses -> Chat: image_generation does not throw (issue #2950)", () => { + // Codex Desktop injects an image_generation hosted tool into every Responses + // request, even text-only ones. It has no Chat Completions equivalent and must + // be dropped silently, not rejected with 400. + assert.doesNotThrow(() => + openaiResponsesToOpenAIRequest( + "gpt-4o", + { + input: [{ role: "user", content: [{ type: "input_text", text: "hi" }] }], + tools: [{ type: "image_generation", output_format: "png" }], + }, + false, + null + ) + ); +}); + +test("Responses -> Chat: image_generation is stripped from output tools array (issue #2950)", () => { + const result = openaiResponsesToOpenAIRequest( + "gpt-4o", + { + input: [{ role: "user", content: [{ type: "input_text", text: "hello" }] }], + tools: [ + { type: "image_generation", output_format: "png" }, + { + type: "function", + name: "foo", + description: "A function", + parameters: { type: "object" }, + }, + ], + }, + false, + null + ) as Record; + + const tools = result.tools as any[]; + assert.ok(Array.isArray(tools), "tools array must be present"); + assert.equal( + tools.some((t) => t.type === "image_generation"), + false, + "image_generation must be stripped from output" + ); + assert.equal(tools.length, 1, "only the function tool must remain"); + assert.equal(tools[0].type, "function"); + assert.equal(tools[0].function.name, "foo"); +});