Repository Public
1---2title: Parallel tool use3url: https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use4description: Enable, format, and disable parallel tool calls, with message-history guidance and troubleshooting.5---67By default, Claude may call multiple tools in a single response. This page covers how to run those calls, how to format the message history so parallelism keeps working, and how to disable parallel tool use when you need to. For the single-call flow, see [Handle tool calls](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls).89## Execution semantics1011When Claude calls tools, the response has a `stop_reason` of `tool_use` and can contain several `tool_use` blocks in a single assistant turn. How you run those calls is your decision. The API doesn't prescribe an execution order: you can run the calls concurrently (`Promise.all`, `asyncio.gather`), sequentially in the order they appear, or in any combination that suits your tools.1213Choose the strategy based on what your tools do. Independent, read-only operations are usually safe to run in parallel for lower latency. Tools with side effects, shared state, or ordering requirements might be better run sequentially.1415Whichever strategy you use, return one `tool_result` for each `tool_use` block, all together in the next user message. Match each result to its call with `tool_use_id`, and put every `tool_result` block before any text content in that message. See [Handle tool calls](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls) for the full formatting rules. If you choose not to run a particular call (for example, because you ran the batch sequentially and an earlier call failed), still return a `tool_result` for it with `is_error: true` and a brief explanation.1617```json18{19 "type": "tool_result",20 "tool_use_id": "toolu_02",21 "is_error": true,22 "content": "Not executed: the preceding write_file call failed."23}24```2526The [computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#batch-actions) and the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions) are stricter. When Claude returns several of their member tool calls in one turn (a batch action), run them sequentially in the order they appear and stop at the first failure; each tool defines the exact text to return for the calls you skip.2728## Test parallel tool calls2930<Note>31 **Use the Tool Runner for most applications:** the SDK [Tool Runner](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner) handles responses with multiple tool calls and formats the results for you, so you don't write this handling yourself. Use the manual pattern on this page when you need direct control over how the calls run, such as custom batching, ordering, or error handling.32</Note>3334The following script sends a request that should trigger parallel tool calls, verifies the response contains them, and formats the tool results so parallelism keeps working. Run it with `ANTHROPIC_API_KEY` set in your environment:3536<CodeGroup>37 ```bash cURL38 # This end-to-end test flow doesn't translate well to a one-off shell command.39 # See the SDK tabs for the full flow. The underlying HTTP request is a standard40 # tool use request with multiple tools defined.41 ```4243 ```bash CLI44 # This end-to-end test flow doesn't translate well to a one-off shell command.45 # See the SDK tabs for the full flow.46 ```4748 ```python Python49 client = Anthropic()5051 # Define tools52 tools = [53 {54 "name": "get_weather",55 "description": "Get the current weather in a given location",56 "input_schema": {57 "type": "object",58 "properties": {59 "location": {60 "type": "string",61 "description": "The city and state, e.g. San Francisco, CA",62 }63 },64 "required": ["location"],65 },66 },67 {68 "name": "get_time",69 "description": "Get the current time in a given timezone",70 "input_schema": {71 "type": "object",72 "properties": {73 "timezone": {74 "type": "string",75 "description": "The timezone, e.g. America/New_York",76 }77 },78 "required": ["timezone"],79 },80 },81 ]8283 # Test conversation with parallel tool calls84 messages = [85 {86 "role": "user",87 "content": "What's the weather in SF and NYC, and what time is it there?",88 }89 ]9091 # Make initial request92 print("Requesting parallel tool calls...")93 response = client.messages.create(94 model="claude-opus-5", max_tokens=1024, messages=messages, tools=tools95 )9697 # Check for parallel tool calls98 tool_uses = [block for block in response.content if block.type == "tool_use"]99 print(f"\n✓ Claude made {len(tool_uses)} tool calls")100101 if len(tool_uses) > 1:102 print("✓ Parallel tool calls detected!")103 for tool in tool_uses:104 print(f" - {tool.name}: {tool.input}")105 else:106 print("✗ No parallel tool calls detected")107108 # Simulate tool execution and format results correctly109 tool_results = []110 for tool_use in tool_uses:111 if tool_use.name == "get_weather":112 if "San Francisco" in str(tool_use.input):113 result = "San Francisco: 68°F, partly cloudy"114 else:115 result = "New York: 45°F, clear skies"116 else: # get_time117 if "Los_Angeles" in str(tool_use.input):118 result = "2:30 PM PST"119 else:120 result = "5:30 PM EST"121122 tool_results.append(123 {"type": "tool_result", "tool_use_id": tool_use.id, "content": result}124 )125126 # Continue conversation with tool results127 messages.extend(128 [129 {"role": "assistant", "content": response.content},130 {"role": "user", "content": tool_results}, # All results in one message!131 ]132 )133134 # Get final response135 print("\nGetting final response...")136 final_response = client.messages.create(137 model="claude-opus-5", max_tokens=1024, messages=messages, tools=tools138 )139140 final_text = next(141 block.text for block in final_response.content if block.type == "text"142 )143 print(f"\nClaude's response:\n{final_text}")144145 # Verify formatting146 print("\n--- Verification ---")147 print(f"✓ Tool results sent in single user message: {len(tool_results)} results")148 print("✓ No text before tool results in content array")149 print("✓ Conversation formatted correctly for future parallel tool use")150 ```151152 ```typescript TypeScript153 const client = new Anthropic();154155 // Define tools156 const tools: Anthropic.Tool[] = [157 {158 name: "get_weather",159 description: "Get the current weather in a given location",160 input_schema: {161 type: "object" as const,162 properties: {163 location: {164 type: "string",165 description: "The city and state, e.g. San Francisco, CA"166 }167 },168 required: ["location"]169 }170 },171 {172 name: "get_time",173 description: "Get the current time in a given timezone",174 input_schema: {175 type: "object" as const,176 properties: {177 timezone: {178 type: "string",179 description: "The timezone, e.g. America/New_York"180 }181 },182 required: ["timezone"]183 }184 }185 ];186187 // Make initial request188 console.log("Requesting parallel tool calls...");189 const response = await client.messages.create({190 model: "claude-opus-5",191 max_tokens: 1024,192 messages: [193 {194 role: "user",195 content: "What's the weather in SF and NYC, and what time is it there?"196 }197 ],198 tools: tools199 });200201 // Check for parallel tool calls202 const toolUses = response.content.filter((block) => block.type === "tool_use");203 console.log(`\n✓ Claude made ${toolUses.length} tool calls`);204205 if (toolUses.length > 1) {206 console.log("✓ Parallel tool calls detected!");207 for (const tool of toolUses) {208 if (tool.type === "tool_use") {209 console.log(` - ${tool.name}: ${JSON.stringify(tool.input)}`);210 }211 }212 } else {213 console.log("✗ No parallel tool calls detected");214 }215216 // Simulate tool execution and format results correctly217 const toolResults: Anthropic.ToolResultBlockParam[] = toolUses218 .filter((block): block is Anthropic.ToolUseBlock => block.type === "tool_use")219 .map((toolUse) => {220 const input = toolUse.input as Record<string, string>;221 let result: string;222 if (toolUse.name === "get_weather") {223 result = input.location?.includes("San Francisco")224 ? "San Francisco: 68F, partly cloudy"225 : "New York: 45F, clear skies";226 } else {227 result = input.timezone?.includes("Los_Angeles") ? "2:30 PM PST" : "5:30 PM EST";228 }229230 return {231 type: "tool_result" as const,232 tool_use_id: toolUse.id,233 content: result234 };235 });236237 // Get final response with correct formatting238 console.log("\nGetting final response...");239 const finalResponse = await client.messages.create({240 model: "claude-opus-5",241 max_tokens: 1024,242 messages: [243 {244 role: "user",245 content: "What's the weather in SF and NYC, and what time is it there?"246 },247 { role: "assistant", content: response.content },248 { role: "user", content: toolResults }249 ],250 tools: tools251 });252253 for (const block of finalResponse.content) {254 if (block.type === "text") {255 console.log(`\nClaude's response:\n${block.text}`);256 }257 }258259 // Verify formatting260 console.log("\n--- Verification ---");261 console.log(`✓ Tool results sent in single user message: ${toolResults.length} results`);262 console.log("✓ No text before tool results in content array");263 console.log("✓ Conversation formatted correctly for future parallel tool use");264 ```265266 ```csharp C#267 AnthropicClient client = new();268269 var tools = new List<ToolUnion>270 {271 new ToolUnion(new Tool()272 {273 Name = "get_weather",274 Description = "Get the current weather in a given location",275 InputSchema = new InputSchema()276 {277 Properties = new Dictionary<string, JsonElement>278 {279 ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),280 },281 Required = ["location"],282 },283 }),284 new ToolUnion(new Tool()285 {286 Name = "get_time",287 Description = "Get the current time in a given timezone",288 InputSchema = new InputSchema()289 {290 Properties = new Dictionary<string, JsonElement>291 {292 ["timezone"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The timezone, e.g. America/New_York" }),293 },294 Required = ["timezone"],295 },296 }),297 };298299 Console.WriteLine("Requesting parallel tool calls...");300 var parameters = new MessageCreateParams301 {302 Model = Model.ClaudeOpus5,303 MaxTokens = 1024,304 Messages = [new() { Role = Role.User, Content = "What's the weather in SF and NYC, and what time is it there?" }],305 Tools = tools306 };307308 var response = await client.Messages.Create(parameters);309310 var toolUses = new List<ToolUseBlock>();311 foreach (var block in response.Content)312 {313 if (block.TryPickToolUse(out var toolUse))314 {315 toolUses.Add(toolUse);316 }317 }318 Console.WriteLine($"\n✓ Claude made {toolUses.Count} tool calls");319320 if (toolUses.Count > 1)321 {322 Console.WriteLine("✓ Parallel tool calls detected!");323 foreach (var tool in toolUses)324 {325 Console.WriteLine($" - {tool.Name}: {JsonSerializer.Serialize(tool.Input)}");326 }327 }328 else329 {330 Console.WriteLine("✗ No parallel tool calls detected");331 }332333 var toolResults = new List<ContentBlockParam>();334 foreach (var toolUse in toolUses)335 {336 string result;337 if (toolUse.Name == "get_weather")338 {339 result = JsonSerializer.Serialize(toolUse.Input).Contains("San Francisco")340 ? "San Francisco: 68°F, partly cloudy"341 : "New York: 45°F, clear skies";342 }343 else344 {345 result = JsonSerializer.Serialize(toolUse.Input).Contains("Los_Angeles")346 ? "2:30 PM PST"347 : "5:30 PM EST";348 }349350 toolResults.Add(new ContentBlockParam(new ToolResultBlockParam()351 {352 ToolUseID = toolUse.ID,353 Content = result,354 }));355 }356357 Console.WriteLine("\nGetting final response...");358 var finalParameters = new MessageCreateParams359 {360 Model = Model.ClaudeOpus5,361 MaxTokens = 1024,362 Messages = [363 new() { Role = Role.User, Content = "What's the weather in SF and NYC, and what time is it there?" },364 new() { Role = Role.Assistant, Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList() },365 new() { Role = Role.User, Content = new MessageParamContent(toolResults) }366 ],367 Tools = tools368 };369370 var finalResponse = await client.Messages.Create(finalParameters);371 var text = finalResponse.Content.Select(b => b.Value).OfType<TextBlock>().FirstOrDefault();372 Console.WriteLine($"\nClaude's response:\n{text?.Text}");373374 Console.WriteLine("\n--- Verification ---");375 Console.WriteLine($"✓ Tool results sent in single user message: {toolResults.Count} results");376 Console.WriteLine("✓ No text before tool results in content array");377 Console.WriteLine("✓ Conversation formatted correctly for future parallel tool use");378 ```379380 ```go Go381 client := anthropic.NewClient()382383 tools := []anthropic.ToolUnionParam{384 {OfTool: &anthropic.ToolParam{385 Name: "get_weather",386 Description: anthropic.String("Get the current weather in a given location"),387 InputSchema: anthropic.ToolInputSchemaParam{388 Properties: map[string]any{389 "location": map[string]any{390 "type": "string",391 "description": "The city and state, e.g. San Francisco, CA",392 },393 },394 Required: []string{"location"},395 },396 }},397 {OfTool: &anthropic.ToolParam{398 Name: "get_time",399 Description: anthropic.String("Get the current time in a given timezone"),400 InputSchema: anthropic.ToolInputSchemaParam{401 Properties: map[string]any{402 "timezone": map[string]any{403 "type": "string",404 "description": "The timezone, e.g. America/New_York",405 },406 },407 Required: []string{"timezone"},408 },409 }},410 }411412 fmt.Println("Requesting parallel tool calls...")413 response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{414 Model: anthropic.ModelClaudeOpus5,415 MaxTokens: 1024,416 Messages: []anthropic.MessageParam{417 anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in SF and NYC, and what time is it there?")),418 },419 Tools: tools,420 })421 if err != nil {422 log.Fatal(err)423 }424425 // Find tool use blocks using type switch426 type toolUseInfo struct {427 ID string428 Name string429 Input json.RawMessage430 }431 var toolUses []toolUseInfo432 for _, block := range response.Content {433 switch variant := block.AsAny().(type) {434 case anthropic.ToolUseBlock:435 toolUses = append(toolUses, toolUseInfo{436 ID: variant.ID,437 Name: variant.Name,438 Input: variant.Input,439 })440 }441 }442443 fmt.Printf("\n✓ Claude made %d tool calls\n", len(toolUses))444445 if len(toolUses) > 1 {446 fmt.Println("✓ Parallel tool calls detected!")447 for _, tool := range toolUses {448 fmt.Printf(" - %s: %s\n", tool.Name, string(tool.Input))449 }450 } else {451 fmt.Println("✗ No parallel tool calls detected")452 }453454 // Build tool results455 var toolResults []anthropic.ContentBlockParamUnion456 for _, toolUse := range toolUses {457 var result string458 inputStr := string(toolUse.Input)459460 if toolUse.Name == "get_weather" {461 if strings.Contains(inputStr, "San Francisco") {462 result = "San Francisco: 68°F, partly cloudy"463 } else {464 result = "New York: 45°F, clear skies"465 }466 } else {467 if strings.Contains(inputStr, "Los_Angeles") {468 result = "2:30 PM PST"469 } else {470 result = "5:30 PM EST"471 }472 }473474 toolResults = append(toolResults, anthropic.NewToolResultBlock(toolUse.ID, result, false))475 }476477 fmt.Println("\nGetting final response...")478 finalResponse, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{479 Model: anthropic.ModelClaudeOpus5,480 MaxTokens: 1024,481 Messages: []anthropic.MessageParam{482 anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in SF and NYC, and what time is it there?")),483 response.ToParam(),484 anthropic.NewUserMessage(toolResults...),485 },486 Tools: tools,487 })488 if err != nil {489 log.Fatal(err)490 }491492 var finalText string493 for _, block := range finalResponse.Content {494 if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {495 finalText = textBlock.Text496 break497 }498 }499500 fmt.Printf("\nClaude's response:\n%s\n", finalText)501502 fmt.Println("\n--- Verification ---")503 fmt.Printf("✓ Tool results sent in single user message: %d results\n", len(toolResults))504 fmt.Println("✓ No text before tool results in content array")505 fmt.Println("✓ Conversation formatted correctly for future parallel tool use")506 ```507508 ```java Java509 AnthropicClient client = AnthropicOkHttpClient.fromEnv();510511 Tool weatherTool = Tool.builder()512 .name("get_weather")513 .description("Get the current weather in a given location")514 .inputSchema(InputSchema.builder()515 .properties(JsonValue.from(Map.of(516 "location", Map.of(517 "type", "string",518 "description", "The city and state, e.g. San Francisco, CA"519 )520 )))521 .putAdditionalProperty("required", JsonValue.from(List.of("location")))522 .build())523 .build();524525 Tool timeTool = Tool.builder()526 .name("get_time")527 .description("Get the current time in a given timezone")528 .inputSchema(InputSchema.builder()529 .properties(JsonValue.from(Map.of(530 "timezone", Map.of(531 "type", "string",532 "description", "The timezone, e.g. America/New_York"533 )534 )))535 .putAdditionalProperty("required", JsonValue.from(List.of("timezone")))536 .build())537 .build();538539 MessageCreateParams params = MessageCreateParams.builder()540 .model(Model.CLAUDE_OPUS_5)541 .maxTokens(1024L)542 .addTool(weatherTool)543 .addTool(timeTool)544 .addUserMessage("What's the weather in SF and NYC, and what time is it there?")545 .build();546547 IO.println("Requesting parallel tool calls...");548 Message response = client.messages().create(params);549550 List<ToolUseBlock> toolUses = new ArrayList<>();551 for (ContentBlock block : response.content()) {552 if (block.toolUse().isPresent()) {553 toolUses.add(block.toolUse().get());554 }555 }556557 IO.println("\n✓ Claude made " + toolUses.size() + " tool calls");558559 if (toolUses.size() > 1) {560 IO.println("✓ Parallel tool calls detected!");561 for (ToolUseBlock tool : toolUses) {562 IO.println(" - " + tool.name() + ": " + tool._input());563 }564 } else {565 IO.println("✗ No parallel tool calls detected");566 }567568 List<ContentBlockParam> toolResults = new ArrayList<>();569 for (ToolUseBlock toolUse : toolUses) {570 String result;571 if (toolUse.name().equals("get_weather")) {572 String location = toolUse._input().toString();573 result = location.contains("San Francisco")574 ? "San Francisco: 68°F, partly cloudy"575 : "New York: 45°F, clear skies";576 } else {577 String timezone = toolUse._input().toString();578 result = timezone.contains("Los_Angeles")579 ? "2:30 PM PST"580 : "5:30 PM EST";581 }582 toolResults.add(ContentBlockParam.ofToolResult(583 ToolResultBlockParam.builder()584 .toolUseId(toolUse.id())585 .content(result)586 .build()587 ));588 }589590 IO.println("\nGetting final response...");591 MessageCreateParams finalParams = MessageCreateParams.builder()592 .model(Model.CLAUDE_OPUS_5)593 .maxTokens(1024L)594 .addTool(weatherTool)595 .addTool(timeTool)596 .addUserMessage("What's the weather in SF and NYC, and what time is it there?")597 .addMessage(response)598 .addUserMessageOfBlockParams(toolResults)599 .build();600601 Message finalResponse = client.messages().create(finalParams);602 finalResponse.content().stream()603 .flatMap(block -> block.text().stream())604 .forEach(textBlock -> IO.println("\nClaude's response:\n" + textBlock.text()));605606 IO.println("\n--- Verification ---");607 IO.println("✓ Tool results sent in single user message: " + toolResults.size() + " results");608 IO.println("✓ No text before tool results in content array");609 IO.println("✓ Conversation formatted correctly for future parallel tool use");610 ```611612 ```php PHP613 $client = new Client();614615 $tools = [616 [617 'name' => 'get_weather',618 'description' => 'Get the current weather in a given location',619 'input_schema' => [620 'type' => 'object',621 'properties' => [622 'location' => [623 'type' => 'string',624 'description' => 'The city and state, e.g. San Francisco, CA'625 ]626 ],627 'required' => ['location']628 ]629 ],630 [631 'name' => 'get_time',632 'description' => 'Get the current time in a given timezone',633 'input_schema' => [634 'type' => 'object',635 'properties' => [636 'timezone' => [637 'type' => 'string',638 'description' => 'The timezone, e.g. America/New_York'639 ]640 ],641 'required' => ['timezone']642 ]643 ]644 ];645646 echo "Requesting parallel tool calls...\n";647 $response = $client->messages->create(648 maxTokens: 1024,649 messages: [650 ['role' => 'user', 'content' => "What's the weather in SF and NYC, and what time is it there?"]651 ],652 model: 'claude-opus-5',653 tools: $tools,654 );655656 $toolUses = array_filter($response->content, fn($block) => $block->type === 'tool_use');657 echo "\n✓ Claude made " . count($toolUses) . " tool calls\n";658659 if (count($toolUses) > 1) {660 echo "✓ Parallel tool calls detected!\n";661 foreach ($toolUses as $tool) {662 echo " - {$tool->name}: " . json_encode($tool->input) . "\n";663 }664 } else {665 echo "✗ No parallel tool calls detected\n";666 }667668 $toolResults = [];669 foreach ($toolUses as $toolUse) {670 if ($toolUse->name === 'get_weather') {671 $result = str_contains(json_encode($toolUse->input), 'San Francisco')672 ? 'San Francisco: 68°F, partly cloudy'673 : 'New York: 45°F, clear skies';674 } else {675 $result = str_contains(json_encode($toolUse->input), 'Los_Angeles')676 ? '2:30 PM PST'677 : '5:30 PM EST';678 }679680 $toolResults[] = [681 'type' => 'tool_result',682 'tool_use_id' => $toolUse->id,683 'content' => $result684 ];685 }686687 echo "\nGetting final response...\n";688 $finalResponse = $client->messages->create(689 maxTokens: 1024,690 messages: [691 ['role' => 'user', 'content' => "What's the weather in SF and NYC, and what time is it there?"],692 ['role' => 'assistant', 'content' => $response->content],693 ['role' => 'user', 'content' => $toolResults]694 ],695 model: 'claude-opus-5',696 tools: $tools,697 );698699 $textBlock = array_find($finalResponse->content, static fn ($block): bool => $block->type === 'text');700 echo "\nClaude's response:\n{$textBlock->text}\n";701702 echo "\n--- Verification ---\n";703 echo "✓ Tool results sent in single user message: " . count($toolResults) . " results\n";704 echo "✓ No text before tool results in content array\n";705 echo "✓ Conversation formatted correctly for future parallel tool use\n";706 ```707708 ```ruby Ruby709 client = Anthropic::Client.new710711 tools = [712 {713 name: "get_weather",714 description: "Get the current weather in a given location",715 input_schema: {716 type: "object",717 properties: {718 location: {719 type: "string",720 description: "The city and state, e.g. San Francisco, CA"721 }722 },723 required: ["location"]724 }725 },726 {727 name: "get_time",728 description: "Get the current time in a given timezone",729 input_schema: {730 type: "object",731 properties: {732 timezone: {733 type: "string",734 description: "The timezone, e.g. America/New_York"735 }736 },737 required: ["timezone"]738 }739 }740 ]741742 puts "Requesting parallel tool calls..."743 response = client.messages.create(744 model: "claude-opus-5",745 max_tokens: 1024,746 messages: [747 { role: "user", content: "What's the weather in SF and NYC, and what time is it there?" }748 ],749 tools: tools750 )751752 tool_uses = response.content.select { |block| block.type == :tool_use }753 puts "\n✓ Claude made #{tool_uses.length} tool calls"754755 if tool_uses.length > 1756 puts "✓ Parallel tool calls detected!"757 tool_uses.each do |tool|758 puts " - #{tool.name}: #{tool.input}"759 end760 else761 puts "✗ No parallel tool calls detected"762 end763764 tool_results = tool_uses.map do |tool_use|765 result = if tool_use.name == "get_weather"766 location = tool_use.input[:location].to_s767 location.include?("San Francisco") ? "San Francisco: 68°F, partly cloudy" : "New York: 45°F, clear skies"768 else769 timezone = tool_use.input[:timezone].to_s770 timezone.include?("Los_Angeles") ? "2:30 PM PST" : "5:30 PM EST"771 end772773 {774 type: "tool_result",775 tool_use_id: tool_use.id,776 content: result777 }778 end779780 puts "\nGetting final response..."781 final_response = client.messages.create(782 model: "claude-opus-5",783 max_tokens: 1024,784 messages: [785 { role: "user", content: "What's the weather in SF and NYC, and what time is it there?" },786 { role: "assistant", content: response.content },787 { role: "user", content: tool_results }788 ],789 tools: tools790 )791792 final_text = final_response.content.find { |block| block.type == :text }793 puts "\nClaude's response:\n#{final_text.text}"794795 puts "\n--- Verification ---"796 puts "✓ Tool results sent in single user message: #{tool_results.length} results"797 puts "✓ No text before tool results in content array"798 puts "✓ Conversation formatted correctly for future parallel tool use"799 ```800</CodeGroup>801802The summary lines at the end restate the two formatting rules that keep parallelism working: every tool result returns in a single user message, and no text content appears before the tool results in that message.803804## Maximizing parallel tool use805806Claude 4 and later models make parallel tool calls by default when a request benefits from multiple tools. For all models, you can increase the likelihood of parallel tool calls with targeted prompting:807808<AccordionGroup>809 <Accordion title="System prompts for parallel tool use">810 For Claude 4 and later models, add this to your system prompt:811812 ```text wrap813 For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.814 ```815816 For even stronger parallel tool use (recommended if the default isn't sufficient), use:817818 ```text wrap819 <use_parallel_tool_calls>820 For maximum efficiency, whenever you perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. Prioritize calling tools in parallel whenever possible. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. When running multiple read-only commands like `ls` or `list_dir`, always run all of the commands in parallel. Err on the side of maximizing parallel tool calls rather than running too many tools sequentially.821 </use_parallel_tool_calls>822 ```823 </Accordion>824825 <Accordion title="User message prompting">826 You can also encourage parallel tool use within specific user messages:827828 ```text wrap829 Instead of:830 "What's the weather in Paris? Also check London."831832 Use:833 "Check the weather in Paris and London simultaneously."834835 Or be explicit:836 "Please use parallel tool calls to get the weather for Paris, London, and Tokyo at the same time."837 ```838 </Accordion>839</AccordionGroup>840841<Note>842 **Claude Fable 5.1 in long agent loops**843844 Claude Fable 5.1 may issue fewer parallel tool calls than earlier models, most noticeably in long agent loops where the next reads are only implied (custom coding agents, bash and text editor harnesses, computer use). Standard function calling is unaffected. For the batching instruction to add and where to put it, see [Batch independent tool calls in agent loops](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1#batch-independent-tool-calls-in-agent-loops).845</Note>846847## Disable parallel tool use848849Parallel tool use is on by default. To turn it off, set `disable_parallel_tool_use: true` inside the [`tool_choice`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools#forcing-tool-use) object. It is not a top-level request parameter. The effect depends on the `tool_choice` type.850851### At most one tool call852853When `tool_choice` type is `auto` (the default), setting `disable_parallel_tool_use: true` means Claude calls at most one tool per response. Claude can still answer in plain text without calling any tool. The highlighted lines are the only change from a standard tool use request:854855<CodeGroup>856 ```bash cURL857 curl https://api.anthropic.com/v1/messages \858 -H "content-type: application/json" \859 -H "x-api-key: $ANTHROPIC_API_KEY" \860 -H "anthropic-version: 2023-06-01" \861 -d '{862 "model": "claude-opus-5",863 "max_tokens": 1024,864 "tools": [{865 "name": "get_weather",866 "description": "Get the current weather in a given location",867 "input_schema": {868 "type": "object",869 "properties": {870 "location": {871 "type": "string",872 "description": "The city and state, e.g. San Francisco, CA"873 }874 },875 "required": ["location"]876 }877 }],878 "tool_choice": {"type": "auto", "disable_parallel_tool_use": true},879 "messages": [880 {"role": "user", "content": "What is the weather in San Francisco and New York?"}881 ]882 }'883 ```884885 ```bash CLI886 ant messages create <<'YAML'887 model: claude-opus-5888 max_tokens: 1024889 tools:890 - name: get_weather891 description: Get the current weather in a given location892 input_schema:893 type: object894 properties:895 location:896 type: string897 description: The city and state, e.g. San Francisco, CA898 required: [location]899 tool_choice:900 type: auto901 disable_parallel_tool_use: true902 messages:903 - role: user904 content: What is the weather in San Francisco and New York?905 YAML906 ```907908 ```python Python909 client = Anthropic()910911 response = client.messages.create(912 model="claude-opus-5",913 max_tokens=1024,914 tools=[915 {916 "name": "get_weather",917 "description": "Get the current weather in a given location",918 "input_schema": {919 "type": "object",920 "properties": {921 "location": {922 "type": "string",923 "description": "The city and state, e.g. San Francisco, CA",924 }925 },926 "required": ["location"],927 },928 }929 ],930 tool_choice={"type": "auto", "disable_parallel_tool_use": True},931 messages=[932 {933 "role": "user",934 "content": "What is the weather in San Francisco and New York?",935 }936 ],937 )938 print(response.content)939 ```940941 ```typescript TypeScript942 const client = new Anthropic();943944 const response = await client.messages.create({945 model: "claude-opus-5",946 max_tokens: 1024,947 tools: [948 {949 name: "get_weather",950 description: "Get the current weather in a given location",951 input_schema: {952 type: "object",953 properties: {954 location: {955 type: "string",956 description: "The city and state, e.g. San Francisco, CA"957 }958 },959 required: ["location"]960 }961 }962 ],963 tool_choice: { type: "auto", disable_parallel_tool_use: true },964 messages: [{ role: "user", content: "What is the weather in San Francisco and New York?" }]965 });966 console.log(response.content);967 ```968969 ```csharp C#970 AnthropicClient client = new();971972 var parameters = new MessageCreateParams973 {974 Model = Model.ClaudeOpus5,975 MaxTokens = 1024,976 Tools = [977 new ToolUnion(new Tool()978 {979 Name = "get_weather",980 Description = "Get the current weather in a given location",981 InputSchema = new InputSchema()982 {983 Properties = new Dictionary<string, JsonElement>984 {985 ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),986 },987 Required = ["location"],988 },989 }),990 ],991 ToolChoice = new ToolChoiceAuto { DisableParallelToolUse = true },992 Messages = [new() { Role = Role.User, Content = "What is the weather in San Francisco and New York?" }]993 };994995 var response = await client.Messages.Create(parameters);996 Console.WriteLine(response);997 ```998999 ```go Go1000 client := anthropic.NewClient()10011002 response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{1003 Model: anthropic.ModelClaudeOpus5,1004 MaxTokens: 1024,1005 Tools: []anthropic.ToolUnionParam{1006 {OfTool: &anthropic.ToolParam{1007 Name: "get_weather",1008 Description: anthropic.String("Get the current weather in a given location"),1009 InputSchema: anthropic.ToolInputSchemaParam{1010 Properties: map[string]any{1011 "location": map[string]any{1012 "type": "string",1013 "description": "The city and state, e.g. San Francisco, CA",1014 },1015 },1016 Required: []string{"location"},1017 },1018 }},1019 },1020 ToolChoice: anthropic.ToolChoiceUnionParam{1021 OfAuto: &anthropic.ToolChoiceAutoParam{1022 DisableParallelToolUse: anthropic.Bool(true),1023 },1024 },1025 Messages: []anthropic.MessageParam{1026 anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather in San Francisco and New York?")),1027 },1028 })1029 if err != nil {1030 log.Fatal(err)1031 }1032 fmt.Println(response.Content)1033 ```10341035 ```java Java1036 AnthropicClient client = AnthropicOkHttpClient.fromEnv();10371038 InputSchema schema = InputSchema.builder()1039 .properties(1040 JsonValue.from(1041 Map.of(1042 "location", Map.of(1043 "type", "string",1044 "description", "The city and state, e.g. San Francisco, CA"1045 )1046 )1047 )1048 )1049 .putAdditionalProperty("required", JsonValue.from(List.of("location")))1050 .build();10511052 MessageCreateParams params = MessageCreateParams.builder()1053 .model(Model.CLAUDE_OPUS_5)1054 .maxTokens(1024L)1055 .addTool(1056 Tool.builder()1057 .name("get_weather")1058 .description("Get the current weather in a given location")1059 .inputSchema(schema)1060 .build()1061 )1062 .toolChoice(ToolChoiceAuto.builder().disableParallelToolUse(true).build())1063 .addUserMessage("What is the weather in San Francisco and New York?")1064 .build();10651066 Message response = client.messages().create(params);1067 IO.println(response.content());1068 ```10691070 ```php PHP1071 $client = new Client();10721073 $response = $client->messages->create(1074 maxTokens: 1024,1075 messages: [1076 ['role' => 'user', 'content' => 'What is the weather in San Francisco and New York?']1077 ],1078 model: 'claude-opus-5',1079 toolChoice: ['type' => 'auto', 'disableParallelToolUse' => true],1080 tools: [1081 [1082 'name' => 'get_weather',1083 'description' => 'Get the current weather in a given location',1084 'input_schema' => [1085 'type' => 'object',1086 'properties' => [1087 'location' => [1088 'type' => 'string',1089 'description' => 'The city and state, e.g. San Francisco, CA'1090 ]1091 ],1092 'required' => ['location']1093 ]1094 ]1095 ],1096 );10971098 echo $response;1099 ```11001101 ```ruby Ruby1102 client = Anthropic::Client.new11031104 response = client.messages.create(1105 model: "claude-opus-5",1106 max_tokens: 1024,1107 tools: [1108 {1109 name: "get_weather",1110 description: "Get the current weather in a given location",1111 input_schema: {1112 type: "object",1113 properties: {1114 location: {1115 type: "string",1116 description: "The city and state, e.g. San Francisco, CA"1117 }1118 },1119 required: ["location"]1120 }1121 }1122 ],1123 tool_choice: { type: "auto", disable_parallel_tool_use: true },1124 messages: [1125 { role: "user", content: "What is the weather in San Francisco and New York?" }1126 ]1127 )1128 puts response.content1129 ```1130</CodeGroup>11311132### Exactly one tool call11331134When `tool_choice` type is `any` or `tool`, setting `disable_parallel_tool_use: true` means Claude calls exactly one tool. Claude Fable 5.1 and Claude Mythos 5.1 don't support these `tool_choice` types (see [Forcing tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools#forcing-tool-use)). The following example uses `any`. The same field works with `tool`:11351136<CodeGroup>1137 ```bash cURL1138 curl https://api.anthropic.com/v1/messages \1139 -H "content-type: application/json" \1140 -H "x-api-key: $ANTHROPIC_API_KEY" \1141 -H "anthropic-version: 2023-06-01" \1142 -d '{1143 "model": "claude-opus-5",1144 "max_tokens": 1024,1145 "tools": [{1146 "name": "get_weather",1147 "description": "Get the current weather in a given location",1148 "input_schema": {1149 "type": "object",1150 "properties": {1151 "location": {1152 "type": "string",1153 "description": "The city and state, e.g. San Francisco, CA"1154 }1155 },1156 "required": ["location"]1157 }1158 }],1159 "tool_choice": {"type": "any", "disable_parallel_tool_use": true},1160 "messages": [1161 {"role": "user", "content": "What is the weather in San Francisco and New York?"}1162 ]1163 }'1164 ```11651166 ```bash CLI1167 ant messages create <<'YAML'1168 model: claude-opus-51169 max_tokens: 10241170 tools:1171 - name: get_weather1172 description: Get the current weather in a given location1173 input_schema:1174 type: object1175 properties:1176 location:1177 type: string1178 description: The city and state, e.g. San Francisco, CA1179 required: [location]1180 tool_choice:1181 type: any1182 disable_parallel_tool_use: true1183 messages:1184 - role: user1185 content: What is the weather in San Francisco and New York?1186 YAML1187 ```11881189 ```python Python1190 client = Anthropic()11911192 response = client.messages.create(1193 model="claude-opus-5",1194 max_tokens=1024,1195 tools=[1196 {1197 "name": "get_weather",1198 "description": "Get the current weather in a given location",1199 "input_schema": {1200 "type": "object",1201 "properties": {1202 "location": {1203 "type": "string",1204 "description": "The city and state, e.g. San Francisco, CA",1205 }1206 },1207 "required": ["location"],1208 },1209 }1210 ],1211 tool_choice={"type": "any", "disable_parallel_tool_use": True},1212 messages=[1213 {1214 "role": "user",1215 "content": "What is the weather in San Francisco and New York?",1216 }1217 ],1218 )1219 print(response.content)1220 ```12211222 ```typescript TypeScript1223 const client = new Anthropic();12241225 const response = await client.messages.create({1226 model: "claude-opus-5",1227 max_tokens: 1024,1228 tools: [1229 {1230 name: "get_weather",1231 description: "Get the current weather in a given location",1232 input_schema: {1233 type: "object",1234 properties: {1235 location: {1236 type: "string",1237 description: "The city and state, e.g. San Francisco, CA"1238 }1239 },1240 required: ["location"]1241 }1242 }1243 ],1244 tool_choice: { type: "any", disable_parallel_tool_use: true },1245 messages: [{ role: "user", content: "What is the weather in San Francisco and New York?" }]1246 });1247 console.log(response.content);1248 ```12491250 ```csharp C#1251 AnthropicClient client = new();12521253 var parameters = new MessageCreateParams1254 {1255 Model = Model.ClaudeOpus5,1256 MaxTokens = 1024,1257 Tools = [1258 new ToolUnion(new Tool()1259 {1260 Name = "get_weather",1261 Description = "Get the current weather in a given location",1262 InputSchema = new InputSchema()1263 {1264 Properties = new Dictionary<string, JsonElement>1265 {1266 ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),1267 },1268 Required = ["location"],1269 },1270 }),1271 ],1272 ToolChoice = new ToolChoiceAny { DisableParallelToolUse = true },1273 Messages = [new() { Role = Role.User, Content = "What is the weather in San Francisco and New York?" }]1274 };12751276 var response = await client.Messages.Create(parameters);1277 Console.WriteLine(response);1278 ```12791280 ```go Go1281 client := anthropic.NewClient()12821283 response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{1284 Model: anthropic.ModelClaudeOpus5,1285 MaxTokens: 1024,1286 Tools: []anthropic.ToolUnionParam{1287 {OfTool: &anthropic.ToolParam{1288 Name: "get_weather",1289 Description: anthropic.String("Get the current weather in a given location"),1290 InputSchema: anthropic.ToolInputSchemaParam{1291 Properties: map[string]any{1292 "location": map[string]any{1293 "type": "string",1294 "description": "The city and state, e.g. San Francisco, CA",1295 },1296 },1297 Required: []string{"location"},1298 },1299 }},1300 },1301 ToolChoice: anthropic.ToolChoiceUnionParam{1302 OfAny: &anthropic.ToolChoiceAnyParam{1303 DisableParallelToolUse: anthropic.Bool(true),1304 },1305 },1306 Messages: []anthropic.MessageParam{1307 anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather in San Francisco and New York?")),1308 },1309 })1310 if err != nil {1311 log.Fatal(err)1312 }1313 fmt.Println(response.Content)1314 ```13151316 ```java Java1317 AnthropicClient client = AnthropicOkHttpClient.fromEnv();13181319 InputSchema schema = InputSchema.builder()1320 .properties(1321 JsonValue.from(1322 Map.of(1323 "location", Map.of(1324 "type", "string",1325 "description", "The city and state, e.g. San Francisco, CA"1326 )1327 )1328 )1329 )1330 .putAdditionalProperty("required", JsonValue.from(List.of("location")))1331 .build();13321333 MessageCreateParams params = MessageCreateParams.builder()1334 .model(Model.CLAUDE_OPUS_5)1335 .maxTokens(1024L)1336 .addTool(1337 Tool.builder()1338 .name("get_weather")1339 .description("Get the current weather in a given location")1340 .inputSchema(schema)1341 .build()1342 )1343 .toolChoice(ToolChoiceAny.builder().disableParallelToolUse(true).build())1344 .addUserMessage("What is the weather in San Francisco and New York?")1345 .build();13461347 Message response = client.messages().create(params);1348 IO.println(response.content());1349 ```13501351 ```php PHP1352 $client = new Client();13531354 $response = $client->messages->create(1355 maxTokens: 1024,1356 messages: [1357 ['role' => 'user', 'content' => 'What is the weather in San Francisco and New York?']1358 ],1359 model: 'claude-opus-5',1360 toolChoice: ['type' => 'any', 'disableParallelToolUse' => true],1361 tools: [1362 [1363 'name' => 'get_weather',1364 'description' => 'Get the current weather in a given location',1365 'input_schema' => [1366 'type' => 'object',1367 'properties' => [1368 'location' => [1369 'type' => 'string',1370 'description' => 'The city and state, e.g. San Francisco, CA'1371 ]1372 ],1373 'required' => ['location']1374 ]1375 ]1376 ],1377 );13781379 echo $response;1380 ```13811382 ```ruby Ruby1383 client = Anthropic::Client.new13841385 response = client.messages.create(1386 model: "claude-opus-5",1387 max_tokens: 1024,1388 tools: [1389 {1390 name: "get_weather",1391 description: "Get the current weather in a given location",1392 input_schema: {1393 type: "object",1394 properties: {1395 location: {1396 type: "string",1397 description: "The city and state, e.g. San Francisco, CA"1398 }1399 },1400 required: ["location"]1401 }1402 }1403 ],1404 tool_choice: { type: "any", disable_parallel_tool_use: true },1405 messages: [1406 { role: "user", content: "What is the weather in San Francisco and New York?" }1407 ]1408 )1409 puts response.content1410 ```1411</CodeGroup>14121413## Troubleshooting14141415If Claude isn't making parallel tool calls when expected, check these common issues:14161417**1. Incorrect tool result formatting**14181419The most common issue is formatting tool results incorrectly in the conversation history. This "teaches" Claude to avoid parallel calls.14201421Specifically for parallel tool use:14221423* **Wrong:** a separate user message for each tool result1424* **Correct:** all tool results together in a single user message14251426```json1427// Wrong: separate user messages reduce parallel tool use1428[1429 {"role": "assistant", "content": [tool_use_1, tool_use_2]},1430 {"role": "user", "content": [tool_result_1]},1431 {"role": "user", "content": [tool_result_2]} // Separate message1432]14331434// Correct: one user message with all results maintains parallel tool use1435[1436 {"role": "assistant", "content": [tool_use_1, tool_use_2]},1437 {"role": "user", "content": [tool_result_1, tool_result_2]} // Single message1438]1439```14401441See [Handle tool calls](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls) for other formatting rules.14421443**2. Weak prompting**14441445Default prompting might not be sufficient. Use the stronger system prompt from [Maximizing parallel tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use#maximizing-parallel-tool-use).14461447**3. Measuring parallel tool usage**14481449To verify parallel tool calls are working:14501451<CodeGroup>1452 ```bash cURL1453 # Measuring parallel tool use is client-side analysis of responses you've already1454 # collected, so it doesn't translate to a one-off shell command. See the SDK tabs.1455 ```14561457 ```bash CLI1458 # Measuring parallel tool use is client-side analysis of responses you've already1459 # collected, so it doesn't translate to a one-off shell command. See the SDK tabs.1460 ```14611462 ```python Python1463 messages = [] # Message objects returned by client.messages.create across your run14641465 tool_call_messages = [1466 msg for msg in messages if any(block.type == "tool_use" for block in msg.content)1467 ]1468 total_tool_calls = sum(1469 len([block for block in msg.content if block.type == "tool_use"])1470 for msg in tool_call_messages1471 )1472 avg_tools_per_message = (1473 total_tool_calls / len(tool_call_messages) if tool_call_messages else 0.01474 )1475 print(f"Average tools per message: {avg_tools_per_message}")1476 # Should be > 1.0 if parallel calls are working1477 ```14781479 ```typescript TypeScript1480 const messages: Anthropic.Message[] = []; // Message objects returned by client.messages.create across your run14811482 const toolCallMessages = messages.filter((message) =>1483 message.content.some((block) => block.type === "tool_use")1484 );1485 const totalToolCalls = toolCallMessages.reduce(1486 (sum, message) => sum + message.content.filter((block) => block.type === "tool_use").length,1487 01488 );1489 const avgToolsPerMessage =1490 toolCallMessages.length > 0 ? totalToolCalls / toolCallMessages.length : 0;1491 console.log(`Average tools per message: ${avgToolsPerMessage}`);1492 // Should be > 1.0 if parallel calls are working1493 ```14941495 ```csharp C#1496 List<Message> messages = []; // Message objects returned by client.Messages.Create across your run14971498 var toolCallMessages = messages1499 .Where(message => message.Content.Any(block => block.TryPickToolUse(out _)))1500 .ToList();1501 var totalToolCalls = toolCallMessages1502 .Sum(message => message.Content.Count(block => block.TryPickToolUse(out _)));1503 var avgToolsPerMessage = toolCallMessages.Count > 0 ? (double)totalToolCalls / toolCallMessages.Count : 0.0;1504 Console.WriteLine($"Average tools per message: {avgToolsPerMessage}");1505 // Should be > 1.0 if parallel calls are working1506 ```15071508 ```go Go1509 var messages []anthropic.Message // Message values returned by client.Messages.New across your run15101511 toolCallMessageCount := 01512 totalToolCalls := 01513 for _, message := range messages {1514 callsInMessage := 01515 for _, block := range message.Content {1516 if block.Type == "tool_use" {1517 callsInMessage++1518 }1519 }1520 if callsInMessage > 0 {1521 toolCallMessageCount++1522 totalToolCalls += callsInMessage1523 }1524 }15251526 avgToolsPerMessage := 0.01527 if toolCallMessageCount > 0 {1528 avgToolsPerMessage = float64(totalToolCalls) / float64(toolCallMessageCount)1529 }1530 fmt.Println("Average tools per message:", avgToolsPerMessage)1531 // Should be > 1.0 if parallel calls are working1532 ```15331534 ```java Java1535 List<Message> messages = List.of(); // Message objects returned by client.messages().create() across your run15361537 List<Message> toolCallMessages = messages.stream()1538 .filter(message -> message.content().stream().anyMatch(ContentBlock::isToolUse))1539 .toList();1540 long totalToolCalls = toolCallMessages.stream()1541 .mapToLong(message -> message.content().stream().filter(ContentBlock::isToolUse).count())1542 .sum();1543 double avgToolsPerMessage = toolCallMessages.isEmpty() ? 0.0 : (double) totalToolCalls / toolCallMessages.size();1544 IO.println("Average tools per message: " + avgToolsPerMessage);1545 // Should be > 1.0 if parallel calls are working1546 ```15471548 ```php PHP1549 // $messages: Message objects returned by $client->messages->create() across your run1550 $messages = [];15511552 $toolCallMessages = array_values(array_filter(1553 $messages,1554 fn ($message) => count(array_filter($message->content, fn ($block) => $block->type === 'tool_use')) > 01555 ));1556 $totalToolCalls = array_sum(array_map(1557 fn ($message) => count(array_filter($message->content, fn ($block) => $block->type === 'tool_use')),1558 $toolCallMessages1559 ));1560 $avgToolsPerMessage = count($toolCallMessages) > 0 ? $totalToolCalls / count($toolCallMessages) : 0.0;1561 echo "Average tools per message: {$avgToolsPerMessage}\n";1562 // Should be > 1.0 if parallel calls are working1563 ```15641565 ```ruby Ruby1566 messages = [] # Message objects returned by client.messages.create across your run15671568 tool_call_messages = messages.select { |message| message.content.any? { |block| block.type == :tool_use } }1569 total_tool_calls = tool_call_messages.sum { |message| message.content.count { |block| block.type == :tool_use } }1570 avg_tools_per_message = tool_call_messages.empty? ? 0.0 : total_tool_calls.to_f / tool_call_messages.size1571 puts "Average tools per message: #{avg_tools_per_message}"1572 # Should be > 1.0 if parallel calls are working1573 ```1574</CodeGroup>15751576**4. Calls in a batch appear to depend on each other**15771578Execution order is your choice. If your tools have ordering dependencies, running the batch sequentially and stopping on the first failure is a valid strategy (and the required one for the [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#batch-actions) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#batch-actions) tools): return `is_error: true` for any call you didn't run. If you run in parallel and a call fails because its prerequisite hadn't completed, return `is_error: true` with the natural error message. Claude will reissue the call on the next turn. To reduce dependent calls appearing together, add this to your system prompt: "Only batch tool calls that are independent of each other."15791580## Next steps15811582<CardGroup cols={3}>1583 <Card title="Tool Runner (SDK)" icon="wrench" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner">1584 Use the SDK's Tool Runner abstraction to handle the agentic loop, error wrapping, and type safety automatically.1585 </Card>15861587 <Card title="Handle tool calls" icon="arrows-left-right" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls">1588 Parse tool\_use blocks, format tool\_result responses, and handle errors with is\_error.1589 </Card>15901591 <Card title="Define tools" icon="hammer" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools">1592 Specify tool schemas, write effective descriptions, and control when Claude calls your tools.1593 </Card>1594</CardGroup>1595