mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix(translator): drop Codex image_generation tool in Responses→Chat (#2950)
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
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<string, unknown>;
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user