mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 00:52:18 +03:00
fix(translator): preserve functionCall id in Gemini to OpenAI request translation (#11365)
Merged via consolidated batch validation. Fixes geminiToOpenAIRequest discarding functionCall.id in favor of a random generated id, causing multi-turn tool-call id mismatches against OpenAI-compatible upstreams. Own test passes.
This commit is contained in:
@@ -137,7 +137,7 @@ function convertGeminiContent(content) {
|
||||
|
||||
if (part.functionCall) {
|
||||
toolCalls.push({
|
||||
id: `call_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
||||
id: part.functionCall.id || `call_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
||||
type: "function",
|
||||
function: {
|
||||
name: part.functionCall.name,
|
||||
|
||||
@@ -100,10 +100,7 @@ test("Gemini -> OpenAI maps a thought:true part to reasoning_content instead of
|
||||
contents: [
|
||||
{
|
||||
role: "model",
|
||||
parts: [
|
||||
{ thought: true, text: "internal reasoning" },
|
||||
{ text: "final answer" },
|
||||
],
|
||||
parts: [{ thought: true, text: "internal reasoning" }, { text: "final answer" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -116,9 +113,7 @@ test("Gemini -> OpenAI maps a thought:true part to reasoning_content instead of
|
||||
assert.equal(assistant.reasoning_content, "internal reasoning");
|
||||
// The visible content must not contain the thought text.
|
||||
const visibleText =
|
||||
typeof assistant.content === "string"
|
||||
? assistant.content
|
||||
: JSON.stringify(assistant.content);
|
||||
typeof assistant.content === "string" ? assistant.content : JSON.stringify(assistant.content);
|
||||
assert.doesNotMatch(visibleText, /internal reasoning/);
|
||||
assert.match(visibleText, /final answer/);
|
||||
});
|
||||
@@ -172,3 +167,73 @@ test("Gemini -> OpenAI converts function responses into tool messages", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("Gemini -> OpenAI preserves functionCall id when present", () => {
|
||||
const result = geminiToOpenAIRequest(
|
||||
"gpt-4o",
|
||||
{
|
||||
contents: [
|
||||
{
|
||||
role: "model",
|
||||
parts: [
|
||||
{
|
||||
functionCall: {
|
||||
id: "call_custom_id_999",
|
||||
name: "get_weather",
|
||||
args: { city: "Tokyo" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
assert.equal(result.messages.length, 1);
|
||||
assert.equal(result.messages[0].role, "assistant");
|
||||
assert.equal(result.messages[0].tool_calls[0].id, "call_custom_id_999");
|
||||
assert.equal(result.messages[0].tool_calls[0].function.name, "get_weather");
|
||||
});
|
||||
|
||||
test("Gemini -> OpenAI maintains matching IDs across multi-turn tool call and response", () => {
|
||||
const result = geminiToOpenAIRequest(
|
||||
"gpt-4o",
|
||||
{
|
||||
contents: [
|
||||
{
|
||||
role: "model",
|
||||
parts: [
|
||||
{
|
||||
functionCall: {
|
||||
id: "call_calc_456",
|
||||
name: "calculator",
|
||||
args: { expr: "2 + 2" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
parts: [
|
||||
{
|
||||
functionResponse: {
|
||||
id: "call_calc_456",
|
||||
name: "calculator",
|
||||
response: { result: 4 },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
assert.equal(result.messages.length, 2);
|
||||
const assistantCallId = result.messages[0].tool_calls[0].id;
|
||||
const toolResponseCallId = result.messages[1].tool_call_id;
|
||||
assert.equal(assistantCallId, "call_calc_456");
|
||||
assert.equal(toolResponseCallId, "call_calc_456");
|
||||
assert.equal(assistantCallId, toolResponseCallId);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user