-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Labels
Description
What happened?
When using Anthropic's web search tool together with custom tools, multi-turn conversations fail because:
server_tool_useblocks are converted to regulartool_useblocks when transforming the responseweb_search_tool_resultblocks are dropped entirely from the message content- When the conversation continues, Claude expects a
tool_resultfor theserver_tool_use(which is server-side and shouldn't need one)
Error Message
messages.2: `tool_use` ids were found without `tool_result` blocks immediately after: srvtoolu_XXX. Each `tool_use` block must have a corresponding `tool_result` block in the next message.
Relevant log output
Raw response from Claude API (correct format):
"content":[
{"type":"server_tool_use","id":"srvtoolu_XXX","name":"web_search","input":{...}},
{"type":"web_search_tool_result","tool_use_id":"srvtoolu_XXX","content":[...]},
{"type":"tool_use","id":"toolu_XXX","name":"add_numbers","input":{...}}
]What litellm sends back to Claude (incorrect - causes error):
"messages": [
{"role": "assistant", "content": [
{"type": "tool_use", "id": "srvtoolu_XXX", "name": "web_search", "input": {...}},
{"type": "tool_use", "id": "toolu_XXX", "name": "add_numbers", "input": {...}}
]},
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "toolu_XXX", "content": "9600"}
]}
]Problems:
server_tool_usebecametool_useweb_search_tool_resultis missing entirely- No
tool_resultforsrvtoolu_XXX(which shouldn't need one - it's server-side)
Minimal Reproduction
import litellm
def add_numbers(a: int, b: int) -> int:
return a + b
tool_def = {
'type': 'function',
'function': {
'name': 'add_numbers',
'description': 'Add two numbers',
'parameters': {
'type': 'object',
'properties': {
'a': {'type': 'integer'},
'b': {'type': 'integer'}
},
'required': ['a', 'b']
}
}
}
msgs = [{"role": "user", "content": "Search the web for the avg weight in kg of male African and Asian elephants. Then add them."}]
# First call - works
r = litellm.completion(
model="anthropic/claude-sonnet-4-5",
messages=msgs,
tools=[tool_def],
web_search_options={"search_context_size": "low"}
)
# Add assistant response and tool result
msgs.append(r.choices[0].message.to_dict())
# Find the custom tool call (not the server tool)
for tc in r.choices[0].message.tool_calls:
if tc.id.startswith('toolu_'): # Only respond to custom tools
msgs.append({
"role": "tool",
"tool_call_id": tc.id,
"content": str(add_numbers(5000, 4000))
})
# Second call - FAILS
r2 = litellm.completion(
model="anthropic/claude-sonnet-4-5",
messages=msgs,
tools=[tool_def],
web_search_options={"search_context_size": "low"}
)Expected Behavior
Multi-turn conversations with web search + custom tools should work. The transformation should:
- Preserve
server_tool_useas-is (not convert totool_use) - Preserve
web_search_tool_resultblocks in the message content - Not require
tool_resultfor server-side tools
Environment
- litellm version: 1.80.9 (also affects 1.80.6-1.80.8)
- Python version: 3.12
- OS: macOS
Related Issues
- [Bug]: Streaming Anthropic Web Search broken in 1.80.6 and 1.80.7 #17254 - Streaming Anthropic Web Search broken
- response_format (structured output) + web_search returns raw tool call tokens instead of parsed JSON #17556 - response_format + web_search returns raw tool call tokens
- [Bug]: Mults BUGs when combine Claude Code and gemini with litellm(caching,inner token count,websearch tools Translation) #16962 - Multiple bugs with Claude + web search
Additional Context
The raw Claude API correctly returns server_tool_use (with srvtoolu_ prefix) and includes web_search_tool_result immediately after. These are server-side tool executions that don't require user-provided results. The issue is in litellm's response transformation and message reconstruction for multi-turn conversations.