Repository navigation
Description
Observed Behavior
With the stock AnthropicClient, native get_web_search_tool(), and one local function tool, a parallel tool turn can fail with HTTP 400. A pending Anthropic server_tool_use is serialized back as a local tool_use, so the API incorrectly expects a local result for the server search.
Reproduced against the real API with and without adaptive thinking. Web search alone and sequential search followed by a local tool succeeded. No application history provider or custom agent loop was involved.
Expected Behavior
Preserve the pending server_tool_use when sending the local tool result. Anthropic documents this mixed-tool flow: the application returns the local result, then the API executes the pending server tool on the next request (server tools).
Steps to Reproduce
- Install the versions below and set
ANTHROPIC_API_KEY. - Run the minimal example.
- When Claude emits a local
tool_usealongside a pendingserver_tool_use, the next API request fails. Tool scheduling is model-dependent; a sequential response will not trigger it.
Minimal Reproduction
import asyncio
import anthropic
from agent_framework import tool
from agent_framework.anthropic import AnthropicClient
@tool
def local_value() -> str:
"""Return a local test value."""
return "local-ok"
async def main():
async with anthropic.AsyncAnthropic() as raw:
client = AnthropicClient(anthropic_client=raw, model="claude-opus-5-5")
async with client.as_agent(
tools=[client.get_web_search_tool(), local_value],
default_options={"max_tokens": 4096},
) as agent:
result = await agent.run(
"Call local_value and search the web for the Microsoft Agent "
"Framework Python 1.22 release page. These tasks are independent; "
"use the tools in parallel where possible. Return the local "
"value and the release URL.",
stream=True,
).get_final_response()
print(result.text)
asyncio.run(main())Error Messages and Stack Traces
Relevant error excerpt (identifier abbreviated):
ChatClientInvalidRequestException: Error code: 400
messages.2: `tool_use` ids were found without `tool_result` blocks immediately after: srvtoolu_...
Each `tool_use` block must have a corresponding `tool_result` block in the next message.
Package Versions
agent-framework-core==1.22.0, agent-framework-anthropic==1.0.0b261015, anthropic==1.11.0, httpx2==2.13.1
Python Version / Operating System
Python 3.14.7 / macOS
Regression
Unknown.
Additional Context
The parser preserves hosted=True, informational_only=True, and the raw server_tool_use block, but the outgoing function_call conversion emits "type": "tool_use" unconditionally (source). This code is also present on current main; runtime reproduction was on the released versions above.
Simplified wire shape:
API response: assistant [tool_use(local_id), server_tool_use(srv_id)]
Next request: assistant [tool_use(local_id), tool_use(srv_id)]
user [tool_result(local_id)]
Related: #6997 prevents local execution of hosted calls, but the outgoing Anthropic serialization still loses their server-tool type.
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Oct 17, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
python/packages/anthropic/agent_framework_anthropic/_chat_client.py::_prepare_message_for_anthropicat line 1003 losesserver_tool_useidentity when a hosted call appears alongside a local tool call. Parsing retainshosted=Trueandinformational_only=True, but serialization emits both calls astool_use. Minimal repro: parse parallel localtool_useand hostedserver_tool_useblocks, append only the local result, then call_prepare_messages_for_anthropicand inspect the assistant block types.python/packages/anthropic/tests/test_anthropic_client.py::test_prepare_messages_preserves_parallel_server_tool_use1.0.0b2610151.0.0b261015