SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
5.3 KB

# Programmatic tool calling (allowed_callers, caller)

Status: DOCUMENTED · LIVE_VERIFIED 2026-09-18 (g1 pause + g2 resume on claude-sonnet-4-6 ≈ $0.021; g3 haiku 400; g4 tool_choice 400; k28 strict 400). GA since 2026-02-17 (beta 2025-11-24 with advanced-tool-use-2025-11-20). Sources: Programmatic tool calling · Tool reference — allowed_callers · Server tools — mixed turns · Code execution. Last verified: 2026-09-18.

# Setup

json
"tools": [
  {"type": "code_execution_20260120", "name": "code_execution"},                 // or code_execution_20260521 (interchangeable for callers)
  {"name": "query_database", "description": "Execute a SQL query. Returns a JSON array of row objects.",
   "input_schema": {"type":"object","properties":{"sql":{"type":"string"}},"required":["sql"]},
   "allowed_callers": ["code_execution_20260120"]}                                // ["direct"] default | ["direct","code_execution_20260120"] both
]

Inside the sandbox each such tool is an async Python function taking one dict and returning the tool_result string: rows = json.loads(await query_database({"sql": "…"})); parallel via asyncio.gather. Describe the output format precisely in description.

Models: Fable 5.1, Mythos 5.1, Fable 5, Mythos 5, Opus 5, 4.8, 4.7, 4.6, 4.5, Sonnet 5, 4.6, 4.5. Not Haiku 4.5 — live g3: 400 'claude-haiku-4-5-20251001' does not support programmatic tool calling. The following tools have allowed_callers that require it: query_database. Explicitly set allowed_callers=["direct"]… (same message for web_search_20260209). Platforms: Claude API, Claude Platform on AWS, Foundry Hosted-on-Anthropic. Not ZDR.

# Flow (live g1 → g2)

  1. Request as above (sonnet 4.6, prompt "Use code to call query_database with sql 'SELECT 1 AS one'…").
  2. Response stop_reason: tool_use, top-level container: {id, expires_at}, content:
json
{"type":"server_tool_use","id":"srvtoolu_01XRkMSA5mTTPpoGGMHeLMyb","name":"code_execution","input":{"code":"\nimport json\nresult = await query_database({\"sql\": \"SELECT 1 AS one\"})\nparsed = json.loads(result)\nprint(parsed)\n"}}
{"type":"tool_use","id":"toolu_013BmH2TKXHokC4S8i6XKJ5V","name":"query_database","input":{"sql":"SELECT 1 AS one"},"caller":{"type":"code_execution_20260120","tool_id":"srvtoolu_01XRkMSA5mTTPpoGGMHeLMyb"}}

caller.tool_id = the cell that made the call. Direct calls carry caller: {"type":"direct"}. The caller type is always tagged code_execution_20260120 even if you declared _20260521. 3. Reply: same tools, top-level "container": "<id>" (required, 400 otherwise), user message containing only tool_result blocks (string or text content; no image/document, no trailing text):

json
{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_013BmH2…","content":"[{\"one\": 1}]"}]}
  1. The cell resumes; either another pause (repeat step 3 for every pending programmatic call in one message) or completion:
json
{"type":"code_execution_tool_result","tool_use_id":"srvtoolu_01XRk…","content":{"type":"code_execution_result","stdout":"[{'one': 1}]\n","stderr":"","return_code":0,"content":[],"abort_reason":null}}
{"type":"text","text":"The value of `one` is **1**."}

Timeouts: your result must arrive within ≈4 minutes (TimeoutError: Calling tool ['query_database'] timed out (no response after 270s) in stderr, Claude usually retries); idle containers reclaimed after ≈5 min; watch expires_at. Each REPL cell has a 90 s wall-clock limit (disclosed by _20260521).

# Restrictions (live 400 messages)

Case Message
tool_choice naming a code-only tool (g4) tool_choice.name 'query_database' cannot be used because this tool only allows calls from ['code_execution_20260120']. Tools specified in tool_choice must allow 'direct' calls from the model.
strict: true on such a tool (k28) tools.1.custom: Tools with strict=true cannot have code_execution callers in allowed_callers.
model without PTC (g3, c2) see above
recursive $ref schema (docs) Circular $ref detected
Also: disable_parallel_tool_use: true unsupported; MCP tools and the computer/browser toolsets cannot be called programmatically (toolsets accept only ["direct"]); allowed_callers is guidance, not a hard block — still handle a direct tool_use for every tool; validate tool results (code may exec/parse them).

# Token economics

Programmatic tool results never enter Claude's context (not billed as input); only the final cell output and text count. Anthropic reports ≈38 % fewer billed input tokens on a 75-tool agent benchmark, 20–40 % typical savings for 10–49 tool definitions, ≈8 % more cost on strictly sequential single-call workflows (τ²-bench). Pricing = code execution pricing (free with web_*_20260209+). Live: g1 3,147 + g2 3,262 input tokens.

Examples: examples/anthropic/tools/programmatic-tool-calling/basic.{sh,py,ts} (sh performs both steps); test test_programmatic_tool_calling_caller (expensive).