- Force or forbid tools per turn with
tool_choice(auto,any,tool,none). - Cap fan-out with
disable_parallel_tool_useso each agent step stays deterministic. - Flip choice between the tool turn and the final answer turn so loops stop wandering.
Default tool use lets Claude decide whether to call a tool, which tool, and how many in one response. That flexibility is fine for chat. For coding agents and multi-step harnesses it shows up as skipped lookups, surprise parallel calls, or a prose answer when you needed a structured tool_use block.
Why it matters
Agent loops break when a turn returns text instead of a tool call, or returns three tool calls your runner was not ready to execute. The Messages API gives you an explicit control plane: tool_choice. Use {"type":"any"} when any tool must run, {"type":"tool","name":"..."} when one named tool must run, {"type":"none"} when tools must stay off, and leave {"type":"auto"} only when the model should decide. Put disable_parallel_tool_use: true inside that same object to force at most one call (auto) or exactly one call (any / tool). Pin the choice per phase of the loop, not once for the whole conversation.
How to pin tool choice
- 1. Keep your tool definitions stable across turns (same names and schemas).
- 2. On the action turn, set
tool_choicetoanyor a namedtool, and adddisable_parallel_tool_use: trueif your runner handles one call at a time. - 3. After you append
tool_resultblocks, either keepautofor more work or switch tononefor a prose wrap-up with no further calls. - 4. Expect
stop_reason: "tool_use"when a tool was forced. Parsetool_useblocks; do not wait for explanatory text first.
#!/usr/bin/env bash
set -euo pipefail
: "${ANTHROPIC_API_KEY:?Set ANTHROPIC_API_KEY in your environment}"
curl -sS https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: ${ANTHROPIC_API_KEY}" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5",
"max_tokens": 512,
"tools": [
{
"name": "search_repo",
"description": "Keyword search across the indexed tree before answering.",
"input_schema": {
"type": "object",
"properties": { "query": { "type": "string" } },
"required": ["query"]
}
},
{
"name": "read_file",
"description": "Read a repo file by path after search returns candidates.",
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
}
],
"tool_choice": { "type": "tool", "name": "search_repo", "disable_parallel_tool_use": true },
"messages": [
{ "role": "user", "content": "Where is prompt caching documented in this repo?" }
]
}'
Gotchas
- Forced
any/toolprefills the assistant turn. Claude will not emit natural-language preamble before thetool_useblock, even if you ask for one. - Manual extended thinking (
thinking: {"type":"enabled"}) rejects forced tool use. Useautoornonewith that setting. Adaptive thinking on models such as Claude Opus 5 can still force tools. - Claude Fable 5.1 and Claude Mythos 5.1 return 400 for
any/tool. Stay onauto(optionally withstrict: trueon tools) or use structured outputs when you need a fixed JSON shape. disable_parallel_tool_uselives insidetool_choice, not as a top-level field. Set it on the request that producestool_useblocks.- Changing
tool_choicebetween cached turns can invalidate cached message blocks (tools and system can still hit). Keep choice stable when you care about cache hits, or accept a miss on phase changes.
Recommended AI prompt
Copy this paragraph into ChatGPT, Claude, Gemini, Grok, or whatever you use.
Review my Claude Messages API agent loop and propose a per-turn tool_choice map: which turns should use auto, any, named tool, or none, where to set disable_parallel_tool_use: true, and how to recover if a forced call returns 400 on Fable 5.1 / Mythos 5.1 or with manual extended thinking. Return a short checklist I can paste next to each loop phase.
Sources: Define tools · Parallel tool use · Tool use overview