mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 14:52:09 +03:00
fix: translate tool_choice object format between Responses and Chat APIs
This commit is contained in:
@@ -244,6 +244,20 @@ export function openaiResponsesToOpenAIRequest(
|
||||
return true;
|
||||
});
|
||||
|
||||
// Translate tool_choice object format: Responses {type,name} → Chat {type,function:{name}}
|
||||
if (result.tool_choice && typeof result.tool_choice === "object" && !Array.isArray(result.tool_choice)) {
|
||||
const tc = toRecord(result.tool_choice);
|
||||
const tcType = toString(tc.type);
|
||||
if (tcType === "function" && tc.name !== undefined && !tc.function) {
|
||||
result.tool_choice = { type: "function", function: { name: tc.name } };
|
||||
} else if (tcType && tcType !== "function" && tcType !== "allowed_tools") {
|
||||
// Built-in tool types (web_search_preview, file_search, etc.) have no Chat equivalent
|
||||
throw unsupportedFeature(
|
||||
`Unsupported Responses API feature: tool_choice type '${tcType}' is not supported by omniroute`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup Responses API specific fields
|
||||
// Note: prompt_cache_key is intentionally preserved — it is used by Codex and other
|
||||
// providers as a cache-affinity signal. Stripping it breaks prompt caching (#517).
|
||||
@@ -440,6 +454,23 @@ export function openaiToOpenAIResponsesRequest(
|
||||
});
|
||||
}
|
||||
|
||||
// Translate tool_choice: Chat {type,function:{name}} → Responses {type,name}
|
||||
if (root.tool_choice !== undefined) {
|
||||
if (typeof root.tool_choice === "string") {
|
||||
result.tool_choice = root.tool_choice;
|
||||
} else if (typeof root.tool_choice === "object" && !Array.isArray(root.tool_choice)) {
|
||||
const tc = toRecord(root.tool_choice);
|
||||
if (tc.type === "function" && tc.function) {
|
||||
const fn = toRecord(tc.function);
|
||||
result.tool_choice = { type: "function", name: fn.name };
|
||||
} else {
|
||||
result.tool_choice = root.tool_choice;
|
||||
}
|
||||
} else {
|
||||
result.tool_choice = root.tool_choice;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass through relevant fields
|
||||
if (root.service_tier !== undefined) result.service_tier = root.service_tier;
|
||||
if (root.temperature !== undefined) result.temperature = root.temperature;
|
||||
|
||||
@@ -158,3 +158,59 @@ test("Chat→Responses: file content part converted to input_file", () => {
|
||||
assert.equal(filePart.file_id, "file-abc");
|
||||
assert.equal(filePart.filename, "data.csv");
|
||||
});
|
||||
|
||||
test("Responses→Chat: tool_choice {type:'function', name} wrapped to {type:'function', function:{name}}", () => {
|
||||
const body = {
|
||||
model: "gpt-4",
|
||||
input: "hello",
|
||||
tool_choice: { type: "function", name: "get_weather" },
|
||||
tools: [{ type: "function", name: "get_weather", parameters: {} }],
|
||||
};
|
||||
const result = openaiResponsesToOpenAIRequest(null, body, null, null);
|
||||
assert.deepEqual(result.tool_choice, {
|
||||
type: "function",
|
||||
function: { name: "get_weather" },
|
||||
});
|
||||
});
|
||||
|
||||
test("Chat→Responses: tool_choice {type:'function', function:{name}} unwrapped to {type:'function', name}", () => {
|
||||
const body = {
|
||||
model: "gpt-4",
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
tool_choice: { type: "function", function: { name: "get_weather" } },
|
||||
tools: [{ type: "function", function: { name: "get_weather", parameters: {} } }],
|
||||
};
|
||||
const result = openaiToOpenAIResponsesRequest("gpt-4", body, true, null);
|
||||
assert.deepEqual(result.tool_choice, {
|
||||
type: "function",
|
||||
name: "get_weather",
|
||||
});
|
||||
});
|
||||
|
||||
test("Responses→Chat: string tool_choice passes through unchanged", () => {
|
||||
const body = { model: "gpt-4", input: "hello", tool_choice: "auto" };
|
||||
const result = openaiResponsesToOpenAIRequest(null, body, null, null);
|
||||
assert.equal(result.tool_choice, "auto");
|
||||
});
|
||||
|
||||
test("Chat→Responses: string tool_choice passes through unchanged", () => {
|
||||
const body = {
|
||||
model: "gpt-4",
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
tool_choice: "required",
|
||||
};
|
||||
const result = openaiToOpenAIResponsesRequest("gpt-4", body, true, null);
|
||||
assert.equal(result.tool_choice, "required");
|
||||
});
|
||||
|
||||
test("Responses→Chat: built-in tool_choice type throws unsupported error", () => {
|
||||
const body = {
|
||||
model: "gpt-4",
|
||||
input: "hello",
|
||||
tool_choice: { type: "web_search_preview" },
|
||||
};
|
||||
assert.throws(
|
||||
() => openaiResponsesToOpenAIRequest(null, body, null, null),
|
||||
(err) => err.message.includes("web_search_preview")
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user