diff --git a/src/agents/ollama-stream.test.ts b/src/agents/ollama-stream.test.ts index ded8064ea19..f1bc9a5330a 100644 --- a/src/agents/ollama-stream.test.ts +++ b/src/agents/ollama-stream.test.ts @@ -54,6 +54,32 @@ describe("convertToOllamaMessages", () => { ]); }); + it("parses stringified JSON arguments from OpenAI-compat tool calls", () => { + const messages = [ + { + role: "assistant", + content: [ + { type: "toolCall", id: "call_2", name: "bash", arguments: '{"command":"ls -la"}' }, + ], + }, + ]; + const result = convertToOllamaMessages(messages); + expect(result[0].tool_calls).toEqual([ + { function: { name: "bash", arguments: { command: "ls -la" } } }, + ]); + }); + + it("handles malformed JSON string arguments gracefully", () => { + const messages = [ + { + role: "assistant", + content: [{ type: "toolCall", id: "call_3", name: "bash", arguments: "not-json" }], + }, + ]; + const result = convertToOllamaMessages(messages); + expect(result[0].tool_calls).toEqual([{ function: { name: "bash", arguments: {} } }]); + }); + it("converts tool result messages with 'tool' role", () => { const messages = [{ role: "tool", content: "file1.txt\nfile2.txt" }]; const result = convertToOllamaMessages(messages); diff --git a/src/agents/ollama-stream.ts b/src/agents/ollama-stream.ts index f332ad1fd83..3be518e3d5a 100644 --- a/src/agents/ollama-stream.ts +++ b/src/agents/ollama-stream.ts @@ -246,6 +246,25 @@ function extractOllamaImages(content: unknown): string[] { .map((part) => part.data); } +/** Parse arguments that may arrive as a JSON string (OpenAI-compat endpoints) into an object. */ +function ensureArgsObject(args: unknown): Record { + if (typeof args === "string") { + try { + const parsed = JSON.parse(args); + if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) { + return parsed as Record; + } + } catch { + // Malformed JSON – return empty args so the call can still proceed. + } + return {}; + } + if (args && typeof args === "object" && !Array.isArray(args)) { + return args as Record; + } + return {}; +} + function extractToolCalls(content: unknown): OllamaToolCall[] { if (!Array.isArray(content)) { return []; @@ -254,9 +273,9 @@ 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 } }); + result.push({ function: { name: part.name, arguments: ensureArgsObject(part.arguments) } }); } else if (part.type === "tool_use") { - result.push({ function: { name: part.name, arguments: part.input } }); + result.push({ function: { name: part.name, arguments: ensureArgsObject(part.input) } }); } } return result;