fix(ollama): normalize tool call arguments from string to object

When OpenAI-compatible APIs return tool calls, arguments are serialized
as a JSON string. Ollama expects an object for function.arguments and
fails parsing: 'Value looks like object, but can't find closing }'.

This fix ensures arguments are always parsed to an object in two places:
1. extractToolCalls() - when processing input content
2. buildAssistantMessage() - when building output tool calls

Fixes #50713
This commit is contained in:
Yaohua-Leo 2026-03-20 08:52:13 +08:00
parent 003ca0123d
commit 1ce0a6f025

View File

@ -254,9 +254,21 @@ function extractToolCalls(content: unknown): OllamaToolCall[] {
const result: OllamaToolCall[] = [];
for (const part of parts) {
if (part.type === "toolCall") {
result.push({ function: { name: part.name, arguments: part.arguments } });
// Ensure arguments are always an object, not a string (OpenAI format passes JSON string)
const args = part.arguments;
let parsedArgs: Record<string, unknown>;
if (typeof args === "string") {
try {
parsedArgs = JSON.parse(args);
} catch {
parsedArgs = {};
}
} else {
parsedArgs = args ?? {};
}
result.push({ function: { name: part.name, arguments: parsedArgs } });
} else if (part.type === "tool_use") {
result.push({ function: { name: part.name, arguments: part.input } });
result.push({ function: { name: part.name, arguments: part.input ?? {} } });
}
}
return result;
@ -351,11 +363,17 @@ export function buildAssistantMessage(
const toolCalls = response.message.tool_calls;
if (toolCalls && toolCalls.length > 0) {
for (const tc of toolCalls) {
// Normalize arguments: ensure it's always an object, not a string
const rawArgs = tc.function.arguments;
const normalizedArgs =
typeof rawArgs === "string"
? (JSON.parse(rawArgs) as Record<string, unknown>)
: (rawArgs ?? {});
content.push({
type: "toolCall",
id: `ollama_call_${randomUUID()}`,
name: tc.function.name,
arguments: tc.function.arguments,
arguments: normalizedArgs,
});
}
}