Handling tool_use Blocks and Returning Results
When Claude decides to use a tool, it returns a tool_use content block instead of text. Your code must execute the tool and return the result to continue the conversation.
Parsing tool_use Blocks
import anthropic
import json
client = anthropic.Anthropic()
def get_weather(city: str, units: str = "celsius") -> str:
"""Mock weather function — replace with real API."""
return json.dumps({
"city": city,
"temperature": 18,
"units": units,
"conditions": "Partly cloudy",
"humidity": 72,
})
tools = [
{
"name": "get_weather",
"description": "Get current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"units": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["city"],
},
}
]
# Step 1: Send initial message
messages = [{"role": "user", "content": "What is the weather in Paris?"}]
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
# Step 2: Handle tool_use
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
tool_name = block.name
tool_input = block.input
tool_use_id = block.id
# Execute the actual tool
if tool_name == "get_weather":
result = get_weather(**tool_input)
else:
result = json.dumps({"error": f"Unknown tool: {tool_name}"})
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": result,
})
# Step 3: Append assistant response and tool results
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
# Step 4: Continue the conversation
final_response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(final_response.content[0].text)
# "The current weather in Paris is 18°C (partly cloudy) with 72% humidity."
Handling Tool Errors Gracefully
def safe_tool_call(tool_name: str, tool_input: dict) -> str:
try:
if tool_name == "get_weather":
return get_weather(**tool_input)
elif tool_name == "search_web":
return search_web(**tool_input)
else:
return json.dumps({"error": f"Tool '{tool_name}' not implemented"})
except Exception as e:
# Return error as string — Claude will handle it gracefully
return json.dumps({"error": str(e), "tool": tool_name})
JavaScript Implementation
async function handleToolUse(response, tools) {
if (response.stop_reason !== "tool_use") return response;
const toolResults = [];
for (const block of response.content) {
if (block.type === "tool_use") {
let result;
try {
result = await executeToolByName(block.name, block.input);
} catch (err) {
result = JSON.stringify({ error: err.message });
}
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: typeof result === "string" ? result : JSON.stringify(result),
});
}
}
return toolResults;
}
Always return a tool_result for every tool_use block. Claude expects a one-to-one correspondence.