feat(ollama): pass tool_name in tool result messages per native API spec (#11828)

Ollama's native /api/chat spec accepts tool_name on tool result messages
to help models associate results with the originating tool call. Extract
toolName from SDK toolResult messages and forward it to improve tool
calling reliability, especially on smaller models (e.g. 4B).
This commit is contained in:
BrokenFinger98
2026-02-10 20:44:46 +09:00
committed by Peter Steinberger
parent 150b2429c4
commit 74b173063e
2 changed files with 24 additions and 2 deletions

View File

@@ -63,6 +63,19 @@ describe("convertToOllamaMessages", () => {
expect(result).toEqual([{ role: "tool", content: "command output here" }]);
});
it("includes tool_name from SDK toolResult messages", () => {
const messages = [{ role: "toolResult", content: "file contents here", toolName: "read" }];
const result = convertToOllamaMessages(messages);
expect(result).toEqual([{ role: "tool", content: "file contents here", tool_name: "read" }]);
});
it("omits tool_name when not provided in toolResult", () => {
const messages = [{ role: "toolResult", content: "output" }];
const result = convertToOllamaMessages(messages);
expect(result).toEqual([{ role: "tool", content: "output" }]);
expect(result[0]).not.toHaveProperty("tool_name");
});
it("handles empty messages array", () => {
const result = convertToOllamaMessages([]);
expect(result).toEqual([]);

View File

@@ -25,6 +25,7 @@ interface OllamaChatMessage {
content: string;
images?: string[];
tool_calls?: OllamaToolCall[];
tool_name?: string;
}
interface OllamaTool {
@@ -140,9 +141,17 @@ export function convertToOllamaMessages(
});
} else if (role === "tool" || role === "toolResult") {
// SDK uses "toolResult" (camelCase) for tool result messages.
// Ollama API expects "tool" role.
// Ollama API expects "tool" role with tool_name per the native spec.
const text = extractTextContent(msg.content);
result.push({ role: "tool", content: text });
const toolName =
typeof (msg as { toolName?: unknown }).toolName === "string"
? (msg as { toolName?: string }).toolName
: undefined;
result.push({
role: "tool",
content: text,
...(toolName ? { tool_name: toolName } : {}),
});
}
}