diff --git a/ts/provider.ollama.ts b/ts/provider.ollama.ts index 2a58bdf..8c92292 100644 --- a/ts/provider.ollama.ts +++ b/ts/provider.ollama.ts @@ -345,9 +345,9 @@ export class OllamaProvider extends MultiModalModel { const timeout = optionsArg.timeout || this.defaultTimeout; const modelOptions = { ...this.defaultOptions, ...optionsArg.options }; - // Format history messages with optional images and reasoning + // Format history messages with optional images, reasoning, and tool_calls const historyMessages = optionsArg.messageHistory.map((msg) => { - const formatted: { role: string; content: string; images?: string[]; reasoning?: string } = { + const formatted: { role: string; content: string; images?: string[]; reasoning?: string; tool_calls?: any[] } = { role: msg.role, content: msg.content, }; @@ -357,6 +357,11 @@ export class OllamaProvider extends MultiModalModel { if (msg.reasoning) { formatted.reasoning = msg.reasoning; } + // CRITICAL: Include tool_calls in history for native tool calling + // Without this, the model doesn't know it already called a tool and may call it again + if ((msg as any).tool_calls && Array.isArray((msg as any).tool_calls)) { + formatted.tool_calls = (msg as any).tool_calls; + } return formatted; }); @@ -494,7 +499,7 @@ export class OllamaProvider extends MultiModalModel { const timeout = optionsArg.timeout || this.defaultTimeout; const modelOptions = { ...this.defaultOptions, ...optionsArg.options }; - // Format history messages with optional images, reasoning, and tool role + // Format history messages with optional images, reasoning, tool_calls, and tool role const historyMessages = optionsArg.messageHistory.map((msg) => { // Handle tool result messages if ((msg as any).role === 'tool') { @@ -505,7 +510,7 @@ export class OllamaProvider extends MultiModalModel { }; } - const formatted: { role: string; content: string; images?: string[]; reasoning?: string } = { + const formatted: { role: string; content: string; images?: string[]; reasoning?: string; tool_calls?: any[] } = { role: msg.role, content: msg.content, }; @@ -515,6 +520,11 @@ export class OllamaProvider extends MultiModalModel { if (msg.reasoning) { formatted.reasoning = msg.reasoning; } + // CRITICAL: Include tool_calls in history for native tool calling + // Without this, the model doesn't know it already called a tool and may call it again + if ((msg as any).tool_calls && Array.isArray((msg as any).tool_calls)) { + formatted.tool_calls = (msg as any).tool_calls; + } return formatted; });