Skip to content

Ollama models emit tool calls as plain text instead of ToolUseBlock when routed through the SDK/CLI (works fine against Ollama's raw API) #1154

Description

@vrun-s

Ollama models emit tool calls as plain text instead of ToolUseBlock when routed through the SDK/CLI (works fine against Ollama's raw API)

Environment:
SDK: claude-agent-sdk-python
SDK version: Version: 0.2.128
CLI version bundled: 2.1.220 (Claude Code)
Ollama (version: 0.32.5) + models tested: qwen3:8b, llama3.1:8b, mistral-nemo:12b
OS: Windows

Summary:
When configured to use a local Ollama model as the provider, tool-enabled prompts never produce a structured ToolUseBlock. The model instead writes the tool call as plain assistant text (e.g. {"input": {"tool": "rag_query", "query": "..."}}), or in one case names an entirely different registered tool by name in prose. This happens even on maximally explicit prompts ("call the rag_query tool now").
NOTE: The same models correctly emit proper tool calls when queried directly against Ollama's native API/tool format, outside the SDK/CLI — which suggests the issue is in how the SDK/CLI frames tool-enabled requests for local providers, not a capability limit of the models themselves.

Repro steps:
Configure ClaudeAgentOptions (or equivalent) with an Ollama-backed provider and register N tools (mine: 3 : rag_query, write_ship30_essay, generate_artifact).
Send an escalating sequence of prompts against the same session/tool config:
a bare natural-language question with no tool hint
an explicit "use the rag_query tool" instruction
single-tool-allowed + a forceful "call it now" instruction
Inspect the returned message stream for ToolUseBlock.

Expected:
At least the most forceful prompt (step 3) should produce a ToolUseBlock that the SDK/harness can execute, consistent with Anthropic-model behavior.

Actual:
No ToolUseBlock at any step, for any of the three models tested. The model output is either:
a plain-text JSON object shaped like the expected tool-call payload, or
prose naming a tool by name without invoking it.
results.citations (my execution logging) stays empty across all steps — zero real tool executions.

Isolating evidence:
Identical harness, tool definitions, and system prompt against Anthropic → ToolUseBlock produced reliably, on the first, least forceful prompt.
Same three Ollama models, queried directly against Ollama's own endpoint/tool format (bypassing the SDK/CLI) → tool calls work correctly.
A 12B model Ollama itself tags as tools-capable (mistral-nemo:12b) failed identically to two smaller 8B models, and degraded into the plain-text fakeout with less prompting pressure than the 8B models needed — inconsistent with a pure model-capability explanation, since a larger tools-tagged model performing worse points away from "model too small/undertrained" and toward something in the request framing common to all three.

Feel free to request for any additional requirements. :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions