SPB Git

Repository Public

programmatic-tool-calling.md 60.4 KB 1,570 lines markdown

1---2title: Programmatic tool calling3url: https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling4description: Let Claude call your tools from code in the code execution container, cutting model round trips and token use in multi-tool workflows.5---67## Compatibility8- [ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention): not eligible9- Supported models: `claude-fable-5-1`, `claude-mythos-5-1`, `claude-fable-5`, `claude-mythos-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5-20251101`, `claude-sonnet-5`, `claude-sonnet-4-6`, `claude-sonnet-4-5-20250929`10- Platforms: Claude API, Claude Platform on AWS, Microsoft Foundry [1]; not available on Amazon Bedrock, Google Cloud11- Programmatic tool calling requires the code execution tool with the `code_execution_20260120` or later [tool version](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#tool-versions).12- Claude Haiku 4.5 accepts the `code_execution_20260120` and later tool versions but doesn't support programmatic tool calling.131. On [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), programmatic tool calling requires a [Hosted on Anthropic deployment](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).1415Programmatic tool calling allows Claude to write code that calls your tools programmatically within a [code execution](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) container, rather than requiring round trips through the model for each tool invocation. This reduces latency for multi-tool workflows and decreases token consumption by allowing Claude to filter or process data before it reaches the model's context window. On agentic search benchmarks like [BrowseComp](https://arxiv.org/abs/2504.12516) and [DeepSearchQA](https://github.com/google-deepmind/deepsearchqa), which test multistep web research and complex information retrieval, adding programmatic tool calling on top of basic search tools improved performance by an average of 11% while using 24% fewer input tokens (see [Improved web search with dynamic filtering](https://claude.com/blog/improved-web-search-with-dynamic-filtering)).1617Consider checking budget compliance across 20 employees: the traditional approach requires 20 separate model round-trips, pulling thousands of expense line items into the context along the way. With programmatic tool calling, a single script runs all 20 lookups, filters the results, and returns only the employees who exceeded their limits, shrinking what Claude needs to reason over from hundreds of kilobytes down to a handful of lines.1819<Tip>20  For a deeper look at the inference and context costs that programmatic tool calling addresses, see [Advanced tool use](https://www.anthropic.com/engineering/advanced-tool-use).21</Tip>2223Programmatic tool calling requires the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) with tool version `code_execution_20260120` or later.2425## Quick start2627Here's an example where Claude programmatically queries a database multiple times and aggregates results. Adding `allowed_callers: ["code_execution_20260120"]` to a tool definition is what makes that tool callable from within code execution (see [The `allowed_callers` field](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#the-allowed-callers-field)):2829<CodeGroup>30  ```bash cURL31  curl https://api.anthropic.com/v1/messages \32      --header "x-api-key: $ANTHROPIC_API_KEY" \33      --header "anthropic-version: 2023-06-01" \34      --header "content-type: application/json" \35      --data '{36          "model": "claude-opus-5",37          "max_tokens": 4096,38          "messages": [39              {40                  "role": "user",41                  "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"42              }43          ],44          "tools": [45              {46                  "type": "code_execution_20260120",47                  "name": "code_execution"48              },49              {50                  "name": "query_database",51                  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",52                  "input_schema": {53                      "type": "object",54                      "properties": {55                          "sql": {56                              "type": "string",57                              "description": "SQL query to execute"58                          }59                      },60                      "required": ["sql"]61                  },62                  "allowed_callers": ["code_execution_20260120"]63              }64          ]65      }'66  ```6768  ```bash CLI69  ant messages create <<'YAML'70  model: claude-opus-571  max_tokens: 409672  messages:73    - role: user74      content: >-75        Query sales data for the West, East, and Central regions, then76        tell me which region had the highest revenue77  tools:78    - type: code_execution_2026012079      name: code_execution80    - name: query_database81      description: >-82        Execute a SQL query against the sales database. Returns a list83        of rows as JSON objects.84      input_schema:85        type: object86        properties:87          sql:88            type: string89            description: SQL query to execute90        required:91          - sql92      allowed_callers:93        - code_execution_2026012094  YAML95  ```9697  ```python Python98  client = anthropic.Anthropic()99100  response = client.messages.create(101      model="claude-opus-5",102      max_tokens=4096,103      messages=[104          {105              "role": "user",106              "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue",107          }108      ],109      tools=[110          {"type": "code_execution_20260120", "name": "code_execution"},111          {112              "name": "query_database",113              "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",114              "input_schema": {115                  "type": "object",116                  "properties": {117                      "sql": {"type": "string", "description": "SQL query to execute"}118                  },119                  "required": ["sql"],120              },121              "allowed_callers": ["code_execution_20260120"],122          },123      ],124  )125126  print(response)127  ```128129  ```typescript TypeScript130  const client = new Anthropic();131132  const response = await client.messages.create({133    model: "claude-opus-5",134    max_tokens: 4096,135    messages: [136      {137        role: "user",138        content:139          "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"140      }141    ],142    tools: [143      {144        type: "code_execution_20260120",145        name: "code_execution"146      },147      {148        name: "query_database",149        description:150          "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",151        input_schema: {152          type: "object" as const,153          properties: {154            sql: {155              type: "string",156              description: "SQL query to execute"157            }158          },159          required: ["sql"]160        },161        allowed_callers: ["code_execution_20260120"]162      }163    ]164  });165166  console.log(response);167  ```168169  ```csharp C#170  AnthropicClient client = new();171172  var parameters = new MessageCreateParams173  {174      Model = Model.ClaudeOpus5,175      MaxTokens = 4096,176      Messages = [177          new() {178              Role = Role.User,179              Content = "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"180          }181      ],182      Tools = [183          new CodeExecutionTool20260120(),184          new ToolUnion(new Tool()185          {186              Name = "query_database",187              Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",188              InputSchema = new InputSchema()189              {190                  Properties = new Dictionary<string, JsonElement>191                  {192                      ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),193                  },194                  Required = ["sql"],195              },196              AllowedCallers = ["code_execution_20260120"]197          }),198      ]199  };200201  var message = await client.Messages.Create(parameters);202  Console.WriteLine(message);203  ```204205  ```go Go206  client := anthropic.NewClient()207208  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{209  	Model:     anthropic.ModelClaudeOpus5,210  	MaxTokens: 4096,211  	Messages: []anthropic.MessageParam{212  		anthropic.NewUserMessage(anthropic.NewTextBlock("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")),213  	},214  	Tools: []anthropic.ToolUnionParam{215  		{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},216  		{OfTool: &anthropic.ToolParam{217  			Name:        "query_database",218  			Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),219  			InputSchema: anthropic.ToolInputSchemaParam{220  				Properties: map[string]any{221  					"sql": map[string]any{222  						"type":        "string",223  						"description": "SQL query to execute",224  					},225  				},226  				Required: []string{"sql"},227  			},228  			AllowedCallers: []string{"code_execution_20260120"},229  		}},230  	},231  })232  if err != nil {233  	log.Fatal(err)234  }235  fmt.Println(response.RawJSON())236  ```237238  ```java Java239  import com.anthropic.models.messages.CodeExecutionTool20260120;240  // ...241242  void main() {243      AnthropicClient client = AnthropicOkHttpClient.fromEnv();244245      MessageCreateParams params = MessageCreateParams.builder()246          .model(Model.CLAUDE_OPUS_5)247          .maxTokens(4096L)248          .addUserMessage("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")249          .addTool(CodeExecutionTool20260120.builder().build())250          .addTool(Tool.builder()251              .name("query_database")252              .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")253              .inputSchema(InputSchema.builder()254                  .properties(JsonValue.from(Map.of(255                      "sql", Map.of(256                          "type", "string",257                          "description", "SQL query to execute"258                      )259                  )))260                  .putAdditionalProperty("required", JsonValue.from(List.of("sql")))261                  .build())262              .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))263              .build())264          .build();265266      Message response = client.messages().create(params);267      IO.println(response);268  }269  ```270271  ```php PHP272  $client = new Client();273274  $message = $client->messages->create(275      maxTokens: 4096,276      messages: [277          ['role' => 'user', 'content' => 'Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue'],278      ],279      model: 'claude-opus-5',280      tools: [281          [282              'type' => 'code_execution_20260120',283              'name' => 'code_execution',284          ],285          [286              'name' => 'query_database',287              'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',288              'input_schema' => [289                  'type' => 'object',290                  'properties' => [291                      'sql' => [292                          'type' => 'string',293                          'description' => 'SQL query to execute',294                      ],295                  ],296                  'required' => ['sql'],297              ],298              'allowed_callers' => ['code_execution_20260120'],299          ],300      ],301  );302303  echo $message;304  ```305306  ```ruby Ruby307  client = Anthropic::Client.new308309  message = client.messages.create(310    model: "claude-opus-5",311    max_tokens: 4096,312    messages: [313      {314        role: "user",315        content: "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"316      }317    ],318    tools: [319      {320        type: "code_execution_20260120",321        name: "code_execution"322      },323      {324        name: "query_database",325        description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",326        input_schema: {327          type: "object",328          properties: {329            sql: {330              type: "string",331              description: "SQL query to execute"332            }333          },334          required: ["sql"]335        },336        allowed_callers: ["code_execution_20260120"]337      }338    ]339  )340341  puts message342  ```343</CodeGroup>344345The response stops with `stop_reason: "tool_use"`, a `container` ID, and a `tool_use` block for `query_database` whose `caller` field identifies the code execution run that called it. Return the result as shown in [Step 3 of the example workflow](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#step-3-provide-tool-result) so the code can finish.346347## How programmatic tool calling works348349When you configure a tool to be callable from code execution and Claude determines that tool is needed:3503511. Claude writes Python code that invokes the tool as a function, potentially including multiple tool calls and pre/post-processing logic3522. Claude runs this code in a sandboxed container through code execution3533. When a tool function is called, code execution pauses and the API returns a `tool_use` block3544. You provide the tool result, and code execution continues (intermediate results are not loaded into Claude's context window)3555. Once all code execution completes, Claude receives the final output and continues working on the task356357This approach is particularly useful for:358359* **Large data processing:** Filter or aggregate tool results before they reach Claude's context360* **Multistep workflows:** Save tokens and latency by calling tools serially or in a loop without sampling Claude in-between tool calls361* **Conditional logic:** Make decisions based on intermediate tool results362363<Note>364  Tools that allow a code execution caller are exposed to Claude's code as async Python functions, so Claude can run them in parallel with `asyncio.gather`. Each function takes a single dict of arguments and returns a string: the text of the `tool_result` you send back. Claude's code awaits these functions with top-level `await` and parses results that it needs as structured data, for example `rows = json.loads(await query_database({"sql": "<sql>"}))`.365</Note>366367## Core concepts368369### The `allowed_callers` field370371The `allowed_callers` field specifies which contexts can invoke a tool:372373```json374{375  "name": "query_database",376  "description": "Execute a SQL query against the database",377  "input_schema": {378    // ...379  },380  "allowed_callers": ["code_execution_20260120"]381}382```383384**Possible values:**385386* `["direct"]` - Claude is guided to call this tool directly (default if omitted)387* `["code_execution_20260120"]` - Claude is guided to call this tool only from within code execution388* `["direct", "code_execution_20260120"]` - Claude may call this tool directly or from within code execution389390Both `"code_execution_20260120"` and `"code_execution_20260521"` are accepted in `allowed_callers` and are interchangeable: a request using either code-execution tool version satisfies tools that list either caller. Response blocks always tag the caller as `code_execution_20260120` regardless of which version the request declared.391392<Tip>393  Choose either `["direct"]` or `["code_execution_20260120"]` for each tool rather than enabling both, as this provides clearer guidance to Claude for how best to use the tool.394</Tip>395396<Note>397  `allowed_callers` controls how the tool is presented to Claude and is validated against `tool_choice`, but it is not a hard API-level block on direct invocation. Claude is strongly guided to respect it, but your client should still be prepared to handle a direct `tool_use` for any tool it defines. Do not rely on `allowed_callers` as a security boundary.398</Note>399400### The `caller` field in responses401402Every tool use block includes a `caller` field indicating how it was invoked:403404**Direct invocation (traditional tool use):**405406```json407{408  "type": "tool_use",409  "id": "toolu_abc123",410  "name": "query_database",411  "input": { "sql": "<sql>" },412  "caller": { "type": "direct" }413}414```415416**Programmatic invocation:**417418```json419{420  "type": "tool_use",421  "id": "toolu_xyz789",422  "name": "query_database",423  "input": { "sql": "<sql>" },424  "caller": {425    "type": "code_execution_20260120",426    "tool_id": "srvtoolu_abc123"427  }428}429```430431The `tool_id` is the `id` of the code execution `server_tool_use` block that made the call, so you can match each programmatic `tool_use` to the code execution run that produced it.432433### Container lifecycle434435Programmatic tool calling uses the same containers as code execution:436437* **Container creation:** A new container is created for each request unless you reuse an existing one438* **Container ID:** Returned in responses in the `container` field, along with an `expires_at` timestamp439* **Reuse:** Pass the container ID back on the next request to keep state. While a programmatic tool call is waiting for your result, the container ID is required on that request, not optional: the API rejects the request without it.440* **Expiration:** `expires_at` tells you how long the container has left. Idle containers are currently reclaimed after about 5 minutes, and no container can be reused more than 30 days after it was created.441442<Warning>443  While Claude's code is waiting for a programmatic tool result, the pending call times out after about 4 minutes and raises a `TimeoutError` inside the code. Return each tool result well before the `expires_at` timestamp on the paused response. See [Container expiration during tool call](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#container-expiration-during-tool-call).444</Warning>445446## Example workflow447448Here's how a complete programmatic tool calling flow works:449450### Step 1: Initial request451452Send a request with code execution and a tool that allows programmatic calling. To enable programmatic calling, add the `allowed_callers` field to your tool definition.453454<Note>455  Provide detailed descriptions of your tool's output format in the tool description. If you specify that the tool returns JSON, Claude attempts to deserialize and process the result in code. The more detail you provide about the output schema, the better Claude can handle the response programmatically.456</Note>457458The request shape is identical to the [Quick start](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#quick-start) example: include `code_execution` in your tools list, add `allowed_callers: ["code_execution_20260120"]` to any tool you want Claude to invoke from code, and send your user message. The remaining steps in this workflow use the user message `"Query customer purchase history from the last quarter and identify our top 5 customers by revenue"`.459460### Step 2: API response with tool call461462Claude writes code that calls your tool. The API pauses and returns:463464```json Output465{466  "role": "assistant",467  "content": [468    {469      "type": "text",470      "text": "I'll query the purchase history and analyze the results."471    },472    {473      "type": "server_tool_use",474      "id": "srvtoolu_abc123",475      "name": "code_execution",476      "input": {477        "code": "import json\n\nrows = json.loads(await query_database({'sql': '<sql>'}))\ntop_customers = sorted(rows, key=lambda x: x['revenue'], reverse=True)[:5]\nprint(f'Top 5 customers: {top_customers}')"478      }479    },480    {481      "type": "tool_use",482      "id": "toolu_def456",483      "name": "query_database",484      "input": { "sql": "<sql>" },485      "caller": {486        "type": "code_execution_20260120",487        "tool_id": "srvtoolu_abc123"488      }489    }490  ],491  "container": {492    "id": "container_xyz789",493    "expires_at": "2026-01-20T14:30:00Z"494  },495  "stop_reason": "tool_use"496}497```498499### Step 3: Provide tool result500501Send the full conversation history plus your tool result. Three details matter on this request:502503* The user message that carries your result can contain only `tool_result` blocks. See [Message formatting restrictions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#message-formatting-restrictions).504* Pass the `container` ID from the paused response. The API rejects a continuation that has pending programmatic tool calls but no container ID.505* Send the same `tools` array as the original request. The code execution tool must still be present for the paused code to resume, and the tools you send on this request are the definitions Claude and the running code can use for the rest of the turn.506507<CodeGroup>508  ```bash cURL509  curl https://api.anthropic.com/v1/messages \510      --header "x-api-key: $ANTHROPIC_API_KEY" \511      --header "anthropic-version: 2023-06-01" \512      --header "content-type: application/json" \513      --data '{514          "model": "claude-opus-5",515          "max_tokens": 4096,516          "container": "container_xyz789",517          "messages": [518              {519                  "role": "user",520                  "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"521              },522              {523                  "role": "assistant",524                  "content": [525                      {526                          "type": "text",527                          "text": "I'\''ll query the purchase history and analyze the results."528                      },529                      {530                          "type": "server_tool_use",531                          "id": "srvtoolu_abc123",532                          "name": "code_execution",533                          "input": {"code": "..."}534                      },535                      {536                          "type": "tool_use",537                          "id": "toolu_def456",538                          "name": "query_database",539                          "input": {"sql": "<sql>"},540                          "caller": {541                              "type": "code_execution_20260120",542                              "tool_id": "srvtoolu_abc123"543                          }544                      }545                  ]546              },547              {548                  "role": "user",549                  "content": [550                      {551                          "type": "tool_result",552                          "tool_use_id": "toolu_def456",553                          "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}]"554                      }555                  ]556              }557          ],558          "tools": [559              {560                  "type": "code_execution_20260120",561                  "name": "code_execution"562              },563              {564                  "name": "query_database",565                  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",566                  "input_schema": {567                      "type": "object",568                      "properties": {569                          "sql": {570                              "type": "string",571                              "description": "SQL query to execute"572                          }573                      },574                      "required": ["sql"]575                  },576                  "allowed_callers": ["code_execution_20260120"]577              }578          ]579      }'580  ```581582  ```bash CLI583  ant messages create <<'YAML'584  model: claude-opus-5585  max_tokens: 4096586  container: container_xyz789587  messages:588    - role: user589      content: >-590        Query customer purchase history from the last quarter and identify our591        top 5 customers by revenue592    - role: assistant593      content:594        - type: text595          text: I'll query the purchase history and analyze the results.596        - type: server_tool_use597          id: srvtoolu_abc123598          name: code_execution599          input:600            code: "..."601        - type: tool_use602          id: toolu_def456603          name: query_database604          input:605            sql: "<sql>"606          caller:607            type: code_execution_20260120608            tool_id: srvtoolu_abc123609    - role: user610      content:611        - type: tool_result612          tool_use_id: toolu_def456613          content: >-614            [{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2",615            "revenue": 38000}, ...]616  # Same tools array as the original request617  tools:618    - type: code_execution_20260120619      name: code_execution620    - name: query_database621      description: >-622        Execute a SQL query against the sales database. Returns a list623        of rows as JSON objects.624      input_schema:625        type: object626        properties:627          sql:628            type: string629            description: SQL query to execute630        required:631          - sql632      allowed_callers:633        - code_execution_20260120634  YAML635  ```636637  ```python Python638  response = client.messages.create(639      model="claude-opus-5",640      max_tokens=4096,641      container="container_xyz789",  # Reuse the container642      messages=[643          {644              "role": "user",645              "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue",646          },647          {648              "role": "assistant",649              "content": [650                  {651                      "type": "text",652                      "text": "I'll query the purchase history and analyze the results.",653                  },654                  {655                      "type": "server_tool_use",656                      "id": "srvtoolu_abc123",657                      "name": "code_execution",658                      "input": {"code": "..."},659                  },660                  {661                      "type": "tool_use",662                      "id": "toolu_def456",663                      "name": "query_database",664                      "input": {"sql": "<sql>"},665                      "caller": {666                          "type": "code_execution_20260120",667                          "tool_id": "srvtoolu_abc123",668                      },669                  },670              ],671          },672          {673              "role": "user",674              "content": [675                  {676                      "type": "tool_result",677                      "tool_use_id": "toolu_def456",678                      "content": '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',679                  }680              ],681          },682      ],683      # Same tools array as the original request684      tools=[685          {"type": "code_execution_20260120", "name": "code_execution"},686          {687              "name": "query_database",688              "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",689              "input_schema": {690                  "type": "object",691                  "properties": {692                      "sql": {"type": "string", "description": "SQL query to execute"}693                  },694                  "required": ["sql"],695              },696              "allowed_callers": ["code_execution_20260120"],697          },698      ],699  )700701  print(response)702  ```703704  ```typescript TypeScript705  const response = await client.messages.create({706    model: "claude-opus-5",707    max_tokens: 4096,708    container: "container_xyz789", // Reuse the container709    messages: [710      {711        role: "user",712        content:713          "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"714      },715      {716        role: "assistant",717        content: [718          { type: "text", text: "I'll query the purchase history and analyze the results." },719          {720            type: "server_tool_use",721            id: "srvtoolu_abc123",722            name: "code_execution",723            input: { code: "..." }724          },725          {726            type: "tool_use",727            id: "toolu_def456",728            name: "query_database",729            input: { sql: "<sql>" },730            caller: {731              type: "code_execution_20260120",732              tool_id: "srvtoolu_abc123"733            }734          }735        ]736      },737      {738        role: "user",739        content: [740          {741            type: "tool_result",742            tool_use_id: "toolu_def456",743            content:744              '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'745          }746        ]747      }748    ],749    // Same tools array as the original request750    tools: [751      {752        type: "code_execution_20260120",753        name: "code_execution"754      },755      {756        name: "query_database",757        description:758          "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",759        input_schema: {760          type: "object" as const,761          properties: {762            sql: {763              type: "string",764              description: "SQL query to execute"765            }766          },767          required: ["sql"]768        },769        allowed_callers: ["code_execution_20260120"]770      }771    ]772  });773774  console.log(response);775  ```776777  ```csharp C#778  AnthropicClient client = new();779780  var parameters = new MessageCreateParams781  {782      Model = Model.ClaudeOpus5,783      MaxTokens = 4096,784      Container = "container_xyz789",785      Messages =786      [787          new()788          {789              Role = Role.User,790              Content = "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"791          },792          new()793          {794              Role = Role.Assistant,795              Content = new ContentBlock[]796              {797                  new TextBlock { Text = "I'll query the purchase history and analyze the results." },798                  new ServerToolUseBlock799                  {800                      Id = "srvtoolu_abc123",801                      Name = "code_execution",802                      Input = new { code = "..." }803                  },804                  new ToolUseBlock805                  {806                      Id = "toolu_def456",807                      Name = "query_database",808                      Input = new { sql = "<sql>" },809                      Caller = new ToolCaller810                      {811                          Type = "code_execution_20260120",812                          ToolId = "srvtoolu_abc123"813                      }814                  }815              }816          },817          new()818          {819              Role = Role.User,820              Content = new ContentBlockParam[]821              {822                  new ToolResultBlockParam823                  {824                      ToolUseID = "toolu_def456",825                      Content = "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]"826                  }827              }828          }829      ],830      // Same tools array as the original request831      Tools = [832          new CodeExecutionTool20260120(),833          new ToolUnion(new Tool()834          {835              Name = "query_database",836              Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",837              InputSchema = new InputSchema()838              {839                  Properties = new Dictionary<string, JsonElement>840                  {841                      ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),842                  },843                  Required = ["sql"],844              },845              AllowedCallers = ["code_execution_20260120"]846          }),847      ]848  };849850  var message = await client.Messages.Create(parameters);851  Console.WriteLine(message);852  ```853854  ```go Go855  client := anthropic.NewClient()856857  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{858  	Model:     anthropic.ModelClaudeOpus5,859  	MaxTokens: 4096,860  	Container: anthropic.MessageCreateParamsContainerUnion{861  		OfString: anthropic.String("container_xyz789"),862  	},863  	Messages: []anthropic.MessageParam{864  		anthropic.NewUserMessage(anthropic.NewTextBlock("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")),865  		{866  			Role: anthropic.MessageParamRoleAssistant,867  			Content: []anthropic.ContentBlockParamUnion{868  				anthropic.NewTextBlock("I'll query the purchase history and analyze the results."),869  				{OfServerToolUse: &anthropic.ServerToolUseBlockParam{870  					ID:    "srvtoolu_abc123",871  					Name:  anthropic.ServerToolUseBlockParamNameCodeExecution,872  					Input: map[string]any{"code": "..."},873  				}},874  				{OfToolUse: &anthropic.ToolUseBlockParam{875  					ID:    "toolu_def456",876  					Name:  "query_database",877  					Input: map[string]any{"sql": "<sql>"},878  					Caller: anthropic.ServerToolUseBlockParamCallerUnion{879  						OfCodeExecution20260120: &anthropic.ServerToolCaller20260120Param{880  							ToolID: "srvtoolu_abc123",881  						},882  					},883  				}},884  			},885  		},886  		{887  			Role: anthropic.MessageParamRoleUser,888  			Content: []anthropic.ContentBlockParamUnion{889  				{OfToolResult: &anthropic.ToolResultBlockParam{890  					ToolUseID: "toolu_def456",891  					Content: []anthropic.ToolResultBlockParamContentUnion{892  						{OfText: &anthropic.TextBlockParam{893  							Text: `[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]`,894  						}},895  					},896  				}},897  			},898  		},899  	},900  	// Same tools array as the original request901  	Tools: []anthropic.ToolUnionParam{902  		{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},903  		{OfTool: &anthropic.ToolParam{904  			Name:        "query_database",905  			Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),906  			InputSchema: anthropic.ToolInputSchemaParam{907  				Properties: map[string]any{908  					"sql": map[string]any{909  						"type":        "string",910  						"description": "SQL query to execute",911  					},912  				},913  				Required: []string{"sql"},914  			},915  			AllowedCallers: []string{"code_execution_20260120"},916  		}},917  	},918  })919  if err != nil {920  	log.Fatal(err)921  }922  fmt.Println(response.RawJSON())923  ```924925  ```java Java926  import com.anthropic.models.messages.CodeExecutionTool20260120;927  // ...928929  void main() {930      AnthropicClient client = AnthropicOkHttpClient.fromEnv();931932      MessageCreateParams params = MessageCreateParams.builder()933          .model(Model.CLAUDE_OPUS_5)934          .maxTokens(4096L)935          .container("container_xyz789")936          .addUserMessage("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")937          .addAssistantMessageOfBlockParams(List.of(938              ContentBlockParam.ofText(939                  TextBlockParam.builder()940                      .text("I'll query the purchase history and analyze the results.")941                      .build()),942              ContentBlockParam.ofServerToolUse(943                  ServerToolUseBlockParam.builder()944                      .id("srvtoolu_abc123")945                      .name("code_execution")946                      .input(JsonValue.from(Map.of("code", "...")))947                      .build()),948              ContentBlockParam.ofToolUse(949                  ToolUseBlockParam.builder()950                      .id("toolu_def456")951                      .name("query_database")952                      .input(JsonValue.from(Map.of("sql", "<sql>")))953                      .codeExecution20260120Caller("srvtoolu_abc123")954                      .build())955          ))956          .addUserMessageOfBlockParams(List.of(957              ContentBlockParam.ofToolResult(958                  ToolResultBlockParam.builder()959                      .toolUseId("toolu_def456")960                      .content("[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]")961                      .build())962          ))963          // Same tools array as the original request964          .addTool(CodeExecutionTool20260120.builder().build())965          .addTool(Tool.builder()966              .name("query_database")967              .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")968              .inputSchema(InputSchema.builder()969                  .properties(JsonValue.from(Map.of(970                      "sql", Map.of(971                          "type", "string",972                          "description", "SQL query to execute"973                      )974                  )))975                  .putAdditionalProperty("required", JsonValue.from(List.of("sql")))976                  .build())977              .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))978              .build())979          .build();980981      Message response = client.messages().create(params);982      IO.println(response);983  }984  ```985986  ```php PHP987  $client = new Client();988989  $message = $client->messages->create(990      maxTokens: 4096,991      messages: [992          [993              'role' => 'user',994              'content' => 'Query customer purchase history from the last quarter and identify our top 5 customers by revenue',995          ],996          [997              'role' => 'assistant',998              'content' => [999                  [1000                      'type' => 'text',1001                      'text' => "I'll query the purchase history and analyze the results.",1002                  ],1003                  [1004                      'type' => 'server_tool_use',1005                      'id' => 'srvtoolu_abc123',1006                      'name' => 'code_execution',1007                      'input' => ['code' => '...'],1008                  ],1009                  [1010                      'type' => 'tool_use',1011                      'id' => 'toolu_def456',1012                      'name' => 'query_database',1013                      'input' => ['sql' => '<sql>'],1014                      'caller' => [1015                          'type' => 'code_execution_20260120',1016                          'tool_id' => 'srvtoolu_abc123',1017                      ],1018                  ],1019              ],1020          ],1021          [1022              'role' => 'user',1023              'content' => [1024                  [1025                      'type' => 'tool_result',1026                      'tool_use_id' => 'toolu_def456',1027                      'content' => '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',1028                  ],1029              ],1030          ],1031      ],1032      model: 'claude-opus-5',1033      container: 'container_xyz789',1034      // Same tools array as the original request1035      tools: [1036          [1037              'type' => 'code_execution_20260120',1038              'name' => 'code_execution',1039          ],1040          [1041              'name' => 'query_database',1042              'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',1043              'input_schema' => [1044                  'type' => 'object',1045                  'properties' => [1046                      'sql' => [1047                          'type' => 'string',1048                          'description' => 'SQL query to execute',1049                      ],1050                  ],1051                  'required' => ['sql'],1052              ],1053              'allowed_callers' => ['code_execution_20260120'],1054          ],1055      ],1056  );10571058  echo $message;1059  ```10601061  ```ruby Ruby1062  require "anthropic"10631064  client = Anthropic::Client.new10651066  message = client.messages.create(1067    model: "claude-opus-5",1068    max_tokens: 4096,1069    container: "container_xyz789",1070    messages: [1071      {1072        role: "user",1073        content: "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"1074      },1075      {1076        role: "assistant",1077        content: [1078          {1079            type: "text",1080            text: "I'll query the purchase history and analyze the results."1081          },1082          {1083            type: "server_tool_use",1084            id: "srvtoolu_abc123",1085            name: "code_execution",1086            input: { code: "..." }1087          },1088          {1089            type: "tool_use",1090            id: "toolu_def456",1091            name: "query_database",1092            input: { sql: "<sql>" },1093            caller: {1094              type: "code_execution_20260120",1095              tool_id: "srvtoolu_abc123"1096            }1097          }1098        ]1099      },1100      {1101        role: "user",1102        content: [1103          {1104            type: "tool_result",1105            tool_use_id: "toolu_def456",1106            content: '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'1107          }1108        ]1109      }1110    ],1111    # Same tools array as the original request1112    tools: [1113      {1114        type: "code_execution_20260120",1115        name: "code_execution"1116      },1117      {1118        name: "query_database",1119        description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",1120        input_schema: {1121          type: "object",1122          properties: {1123            sql: {1124              type: "string",1125              description: "SQL query to execute"1126            }1127          },1128          required: ["sql"]1129        },1130        allowed_callers: ["code_execution_20260120"]1131      }1132    ]1133  )11341135  puts message1136  ```1137</CodeGroup>11381139### Step 4: Next tool call or completion11401141The code picks up where it paused and processes your result. Each continuation response either pauses again with more programmatic `tool_use` blocks, or completes the code execution and lets Claude continue the turn (Step 5). Check `stop_reason` and each `tool_use` block's `caller` to tell the two apart: a response that pauses for you has `stop_reason: "tool_use"` and a `tool_use` block whose `caller` names a code execution version, and you repeat Step 3 with a `tool_result` for every pending programmatic call in one user message.11421143### Step 5: Final response11441145Once the code execution completes, Claude provides the final response:11461147```json Output1148{1149  "content": [1150    {1151      "type": "code_execution_tool_result",1152      "tool_use_id": "srvtoolu_abc123",1153      "content": {1154        "type": "code_execution_result",1155        "stdout": "Top 5 customers: [{'customer_id': 'C1', 'revenue': 45000}, {'customer_id': 'C2', 'revenue': 38000}, {'customer_id': 'C5', 'revenue': 32000}, {'customer_id': 'C8', 'revenue': 28500}, {'customer_id': 'C3', 'revenue': 24000}]",1156        "stderr": "",1157        "return_code": 0,1158        "content": []1159      }1160    },1161    {1162      "type": "text",1163      "text": "I've analyzed the purchase history from last quarter. Your top 5 customers generated $167,500 in total revenue, with Customer C1 leading at $45,000."1164    }1165  ],1166  "stop_reason": "end_turn"1167}1168```11691170## Advanced patterns11711172### Batch processing with loops11731174Claude can write code that processes multiple items efficiently:11751176```python1177regions = ["West", "East", "Central", "North", "South"]1178results = {}1179for region in regions:1180    rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))1181    results[region] = sum(row["revenue"] for row in rows)11821183# Process results programmatically1184top_region = max(results.items(), key=lambda x: x[1])1185print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")1186```11871188This pattern:11891190* Reduces model round-trips from N (one per region) to 11191* Processes large result sets programmatically before returning to Claude1192* Saves tokens by only returning aggregated conclusions instead of raw data11931194### Early termination11951196Claude can stop processing as soon as success criteria are met:11971198```python1199endpoints = ["us-east", "eu-west", "apac"]1200for endpoint in endpoints:1201    status = await check_health({"endpoint": endpoint})1202    if status == "healthy":1203        print(f"Found healthy endpoint: {endpoint}")1204        break  # Stop early, don't check remaining1205```12061207### Conditional tool selection12081209```python1210path = "/tmp/example.txt"1211file_info = json.loads(await get_file_info({"path": path}))1212if file_info["size"] < 10000:1213    content = await read_full_file({"path": path})1214else:1215    content = await read_file_summary({"path": path})1216print(content)1217```12181219### Data filtering12201221```python1222server_id = "srv-01"1223log_text = await fetch_logs({"server_id": server_id})1224errors = [line for line in log_text.splitlines() if "ERROR" in line]1225print(f"Found {len(errors)} errors")1226for error in errors[-10:]:  # Only return last 10 errors1227    print(error)1228```12291230## Response format12311232### Programmatic tool call12331234When code execution calls a tool:12351236```json1237{1238  "type": "tool_use",1239  "id": "toolu_abc123",1240  "name": "query_database",1241  "input": { "sql": "<sql>" },1242  "caller": {1243    "type": "code_execution_20260120",1244    "tool_id": "srvtoolu_xyz789"1245  }1246}1247```12481249### Tool result handling12501251Your tool result is passed back to the running code:12521253```json1254{1255  "role": "user",1256  "content": [1257    {1258      "type": "tool_result",1259      "tool_use_id": "toolu_abc123",1260      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000, \"orders\": 23}, {\"customer_id\": \"C2\", \"revenue\": 38000, \"orders\": 18}, ...]"1261    }1262  ]1263}1264```12651266### Code execution completion12671268When all tool calls are satisfied and code completes:12691270```json1271{1272  "type": "code_execution_tool_result",1273  "tool_use_id": "srvtoolu_xyz789",1274  "content": {1275    "type": "code_execution_result",1276    "stdout": "Analysis complete. Top 5 customers identified from 847 total records.",1277    "stderr": "",1278    "return_code": 0,1279    "content": []1280  }1281}1282```12831284## Error handling12851286### Common errors12871288| Error                                      | Where it appears                                                             | Description                                                                    | Solution                                                                                                                         |1289| ------------------------------------------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |1290| `invalid_tool_input`                       | `error_code` on the `code_execution_tool_result` error block in the response | Invalid parameters were passed to the code execution tool                      | See the [code execution tool errors](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#errors)   |1291| `invalid_request_error` (on `tool_choice`) | HTTP 400 error response                                                      | `tool_choice` names a tool whose `allowed_callers` does not include `"direct"` | Either add `"direct"` to that tool's `allowed_callers`, or remove the tool from `tool_choice` and let Claude invoke it from code |12921293### Container expiration during tool call12941295If your tool result doesn't arrive within about 4 minutes, the pending call raises a `TimeoutError` inside Claude's running code. Claude sees the error in `stderr` and typically retries the call:12961297```json1298{1299  "type": "code_execution_tool_result",1300  "tool_use_id": "srvtoolu_abc123",1301  "content": {1302    "type": "code_execution_result",1303    "stdout": "",1304    "stderr": "TimeoutError: Calling tool ['query_database'] timed out (no response after 270s).",1305    "return_code": 0,1306    "content": []1307  }1308}1309```13101311To prevent timeouts:13121313* Monitor the `expires_at` field in responses1314* Implement timeouts for your tool execution1315* Consider breaking long operations into smaller chunks13161317### Tool execution errors13181319If your tool returns an error:13201321```json1322{1323  "type": "tool_result",1324  "tool_use_id": "toolu_abc123",1325  "content": "Error: Query timeout - table lock exceeded 30 seconds"1326}1327```13281329Claude's code receives this error and can handle it appropriately.13301331## Constraints and limitations13321333### Feature incompatibilities13341335* **Structured outputs:** Tools with `strict: true` are not supported with programmatic calling1336* **Tool choice:** You cannot force programmatic calling of a specific tool through `tool_choice`1337* **Parallel tool use:** `disable_parallel_tool_use: true` is not supported with programmatic calling13381339### Input schema limitations13401341Custom tools whose `input_schema` contains a recursive `$ref` (a reference cycle, such as a schema that refers to itself) cannot be enabled for programmatic calling. Including a code execution tool version in `allowed_callers` for such a tool causes the request to fail with a `400 invalid_request_error` whose message contains `Circular $ref detected`. The same schema is accepted for direct tool calling.13421343To work around this, do one of the following:13441345* Keep the tool direct-only by omitting `allowed_callers` (or setting it to `["direct"]`). Other tools in the same request can still use programmatic calling.1346* Remove the cycle from the schema. For example, unroll the recursion to a fixed depth and describe any deeper nesting in the `description` of the innermost level, or replace the recursive property with a plain `{"type": "object"}` whose `description` explains the expected shape.13471348### Tool restrictions13491350The following tools cannot be called programmatically:13511352* Tools provided by an [MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)1353* The [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets (`computer_toolset_20260801` and `browser_toolset_20260801`), whose `allowed_callers` field accepts only `"direct"`13541355### Message formatting restrictions13561357When responding to programmatic tool calls, there are strict formatting requirements:13581359**Tool result only responses:** If there are pending programmatic tool calls waiting for results, your response message must contain **only** `tool_result` blocks. You cannot include any text content, even after the tool results.13601361Invalid - Cannot include text when responding to programmatic tool calls:13621363```json1364{1365  "role": "user",1366  "content": [1367    {1368      "type": "tool_result",1369      "tool_use_id": "toolu_01",1370      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"1371    },1372    { "type": "text", "text": "What should I do next?" }1373  ]1374}1375```13761377Valid - Only tool results when responding to programmatic tool calls:13781379```json1380{1381  "role": "user",1382  "content": [1383    {1384      "type": "tool_result",1385      "tool_use_id": "toolu_01",1386      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"1387    }1388  ]1389}1390```13911392This restriction only applies when responding to programmatic (code execution) tool calls. For regular client-side tool calls, you can include text content after tool results.13931394**Text-only tool result content:** The `content` of each `tool_result` that answers a programmatic call must be a string or `text` blocks. Image, document, and other content block types are rejected.13951396### Rate limits13971398Programmatic tool calls are subject to the same rate limits as regular tool calls. Each tool call from code execution counts as a separate invocation.13991400### Validate tool results before use14011402When implementing user-defined tools that will be called programmatically:14031404* **Tool results are returned as strings:** They can contain any content, including code snippets or executable commands that may be processed by the execution environment.1405* **Validate external tool results:** If your tool returns data from external sources or accepts user input, be aware of code injection risks if the output will be interpreted or executed as code.14061407## Token efficiency14081409Programmatic tool calling reduces token consumption in three ways:14101411* **Tool results from programmatic calls are not added to Claude's context** - only the final code output is1412* **Intermediate processing happens in code** - filtering, aggregation, and other transformations don't consume model tokens1413* **Multiple tool calls in one code execution** - reduces overhead compared to separate model turns14141415For example, calling 10 tools directly uses \~10x the tokens of calling them programmatically and returning a summary.14161417In Anthropic's internal evaluations on a production Claude model:14181419* On a 75-tool project-management agent benchmark, enabling programmatic tool calling reduced billed input tokens by roughly 38% with no change in task accuracy.1420* On [τ²-bench](https://arxiv.org/abs/2506.07982) (airline, retail, and telecom domains), where each turn makes one or two sequential tool calls, programmatic tool calling left scores unchanged and cost roughly 8% more. Sequential single-call workflows do not benefit.1421* Across production API traffic, requests whose `tools` array contains 10 to 49 tool definitions see typical token savings of 20% to 40% with programmatic tool calling enabled.14221423Actual savings vary with workload shape. See [When to use programmatic calling](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#when-to-use-programmatic-calling).14241425## Usage and pricing14261427Programmatic tool calling uses the same pricing as code execution. See the [code execution pricing](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#usage-and-pricing) for details.14281429<Note>1430  Token counting for programmatic tool calls: Tool results from programmatic invocations do not count toward your input/output token usage. Only the final code execution result and Claude's response count.1431</Note>14321433## Best practices14341435### Tool design14361437* **Provide detailed output descriptions:** Because Claude deserializes tool results in code, document the format (JSON structure and field types)1438* **Return structured data:** JSON or other machine-readable formats work best for programmatic processing1439* **Keep responses concise:** Return only necessary data to minimize processing overhead14401441### When to use programmatic calling14421443Programmatic tool calling trades a small fixed overhead (container startup, script generation) for large savings on tool-result tokens and model round-trips. Whether that trade pays off depends on workload shape.14441445**Strong fit:**14461447* Fan-out or parallel operations across many items (for example, checking 50 endpoints or looking up 20 records)1448* Large tool results that can be filtered, aggregated, or summarized before reaching Claude's context1449* Agentic search and retrieval, where iterative querying and result filtering dominate the workflow14501451**Weak fit:**14521453* Strictly sequential workflows where each call depends on Claude reasoning over the previous result, because the script cannot skip the model round-trip in that case1454* A small number of tool calls with small responses, especially on the first turn of a conversation, where container and script overhead can exceed the savings1455* Tools that require immediate user feedback between calls14561457If you are unsure, measure billed input tokens with and without `allowed_callers` on a representative sample of your traffic before enabling it broadly.14581459### Performance optimization14601461* **Reuse containers** when making multiple related requests to maintain state1462* **Batch similar operations** in a single code execution when possible14631464## Troubleshooting14651466### Common issues14671468**`invalid_request_error` when setting `tool_choice`**14691470* `tool_choice` cannot name a tool whose `allowed_callers` omits `"direct"`. Either add `"direct"` to that tool's `allowed_callers`, or remove the tool from `tool_choice` and let Claude invoke it from code.14711472**Container expiration**14731474* Respond to each programmatic tool call well before the paused response's `expires_at` timestamp. Claude's code stops waiting for a result after about 4 minutes, and idle containers are currently reclaimed after about 5 minutes.1475* Consider implementing faster tool execution14761477**Tool result not parsed correctly**14781479* Ensure your tool returns string data that Claude can deserialize1480* Provide clear output format documentation in your tool description14811482### Debugging tips148314841. **Log all tool calls and results** to track the flow14852. **Check the `caller` field** to confirm programmatic invocation14863. **Monitor container IDs** to ensure proper reuse14874. **Test tools independently** before enabling programmatic calling14881489## Why programmatic tool calling works14901491Claude is trained on large amounts of code, so presenting tools as callable Python functions lets it use that strength:14921493* **Tool composition:** Chained calls, loops, and conditionals are ordinary Python control flow instead of a series of model round trips1494* **Result processing:** Claude's code filters and aggregates large tool outputs, or writes them to files, and only the final output enters the context window1495* **Latency:** The model is not re-sampled between the tool calls inside one code execution14961497## Alternative implementations14981499Programmatic tool calling is a generalizable pattern that can also be implemented on your own infrastructure. Here's how the approaches compare:15001501### Client-side direct execution15021503Provide Claude with a code execution tool and describe what functions are available in that environment. When Claude invokes the tool with code, your application executes it locally where those functions are defined.15041505**Advantages:**15061507* Minimal re-architecting of your application1508* Full control over the environment and instructions15091510**Disadvantages:**15111512* Executes untrusted code outside of a sandbox1513* Tool invocations can be vectors for code injection15141515**Use when:** Your application can safely execute arbitrary code, you want the smallest implementation, and Anthropic's managed offering doesn't fit your needs.15161517### Self-managed sandboxed execution15181519Same approach from Claude's perspective, but code runs in a sandboxed container with security restrictions (for example, no network egress). If your tools require external resources, you'll need a protocol for executing tool calls outside the sandbox.15201521**Advantages:**15221523* Safe programmatic tool calling on your own infrastructure1524* Full control over the execution environment15251526**Disadvantages:**15271528* Complex to build and maintain1529* Requires managing both infrastructure and inter-process communication15301531**Use when:** Security is critical and Anthropic's managed solution doesn't fit your requirements.15321533### Anthropic-managed execution15341535Anthropic's programmatic tool calling is a managed version of sandboxed execution with an opinionated Python environment tuned for Claude. Anthropic handles container management, code execution, and secure tool invocation communication.15361537**Advantages:**15381539* Safe and secure by default1540* Enabled with a tool definition, with no infrastructure to run1541* Environment and instructions optimized for Claude15421543Consider using Anthropic's managed solution if you're using the Claude API, [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), or [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry). On Microsoft Foundry, programmatic tool calling requires a [Hosted on Anthropic deployment](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).15441545## Data retention15461547Programmatic tool calling is built on the code execution infrastructure and uses the same sandbox containers. Container data, including execution artifacts and outputs, is retained for up to 30 days.15481549For ZDR eligibility across all features, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention).15501551## Next steps15521553<CardGroup cols={2}>1554  <Card title="Fine-grained tool streaming" icon="bolt" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming">1555    Stream tool inputs without server-side JSON buffering for latency-sensitive applications.1556  </Card>15571558  <Card title="Code execution tool" icon="code" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool">1559    Run Python and bash code in a sandboxed container to analyze data, generate files, and iterate on solutions.1560  </Card>15611562  <Card title="Tool use with Claude" icon="wrench" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview">1563    Connect Claude to external tools and APIs. See where tools execute, when Claude calls them, and which tool fits your task.1564  </Card>15651566  <Card title="Define tools" icon="hammer" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools">1567    Specify tool schemas, write effective descriptions, and control when Claude calls your tools.1568  </Card>1569</CardGroup>1570
Files main
Menu

Theme