From 9e2f4216f94de0224291fb431b1e2d2cd000ce70 Mon Sep 17 00:00:00 2001 From: AveryanAlex Date: Sun, 29 Mar 2026 00:16:59 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20reject=20all=20non-function=20tool=20typ?= =?UTF-8?q?es=20in=20Responses=E2=86=92Chat=20translation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../translator/request/openai-responses.ts | 10 ++-- .../unit/responses-translation-fixes.test.mjs | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/open-sse/translator/request/openai-responses.ts b/open-sse/translator/request/openai-responses.ts index 357c6e6c..5c9147a2 100644 --- a/open-sse/translator/request/openai-responses.ts +++ b/open-sse/translator/request/openai-responses.ts @@ -10,8 +10,6 @@ import { generateToolCallId } from "../helpers/toolCallHelper.ts"; type JsonRecord = Record; -const UNSUPPORTED_TOOLS = ["file_search", "code_interpreter", "web_search_preview"]; - function toRecord(value: unknown): JsonRecord { return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {}; } @@ -47,14 +45,16 @@ export function openaiResponsesToOpenAIRequest( const root = toRecord(body); if (root.input === undefined) return body; - // Validate unsupported features - return clear errors instead of silent failure + // Validate tool types — only function tools can be translated to Chat Completions const tools = toArray(root.tools); if (tools.length > 0) { for (const toolValue of tools) { const tool = toRecord(toolValue); - if (UNSUPPORTED_TOOLS.includes(toString(tool.type))) { + const toolType = toString(tool.type); + // Allow: function tools, and tools already in Chat format (have .function property) + if (toolType && toolType !== "function" && !tool.function) { throw unsupportedFeature( - `Unsupported Responses API feature: ${toString(tool.type)} tool type is not supported by omniroute` + `Unsupported Responses API feature: ${toolType} tool type is not supported by omniroute` ); } } diff --git a/tests/unit/responses-translation-fixes.test.mjs b/tests/unit/responses-translation-fixes.test.mjs index 129fc3ce..76df1146 100644 --- a/tests/unit/responses-translation-fixes.test.mjs +++ b/tests/unit/responses-translation-fixes.test.mjs @@ -214,3 +214,50 @@ test("Responses→Chat: built-in tool_choice type throws unsupported error", () (err) => err.message.includes("web_search_preview") ); }); + +test("Responses→Chat: web_search tool type throws unsupported error", () => { + const body = { + model: "gpt-4", + input: "search for cats", + tools: [{ type: "web_search", search_context_size: "medium" }], + }; + assert.throws( + () => openaiResponsesToOpenAIRequest(null, body, null, null), + (err) => err.message.includes("web_search") + ); +}); + +test("Responses→Chat: computer tool type throws unsupported error", () => { + const body = { + model: "gpt-4", + input: "click button", + tools: [{ type: "computer" }], + }; + assert.throws( + () => openaiResponsesToOpenAIRequest(null, body, null, null), + (err) => err.message.includes("computer") + ); +}); + +test("Responses→Chat: mcp tool type throws unsupported error", () => { + const body = { + model: "gpt-4", + input: "hello", + tools: [{ type: "mcp", server_label: "test", server_url: "https://example.com" }], + }; + assert.throws( + () => openaiResponsesToOpenAIRequest(null, body, null, null), + (err) => err.message.includes("mcp") + ); +}); + +test("Responses→Chat: function tool type passes through", () => { + const body = { + model: "gpt-4", + input: "hello", + tools: [{ type: "function", name: "greet", parameters: {} }], + }; + const result = openaiResponsesToOpenAIRequest(null, body, null, null); + assert.equal(result.tools.length, 1); + assert.equal(result.tools[0].type, "function"); +});