Skip to content

fix: fire InputJsonEvent for server_tool_use blocks in streaming#1380

Open
atishay2 wants to merge 3 commits intoanthropics:mainfrom
atishay2:fix/server-tool-use-input-json-event
Open

fix: fire InputJsonEvent for server_tool_use blocks in streaming#1380
atishay2 wants to merge 3 commits intoanthropics:mainfrom
atishay2:fix/server-tool-use-input-json-event

Conversation

@atishay2
Copy link
Copy Markdown

Summary

build_events() in _messages.py only fires InputJsonEvent for tool_use content blocks, silently skipping server_tool_use blocks even when the API streams input_json_delta events for them.

Root Cause

There is an internal inconsistency in the same file:

  • TRACKS_TOOL_INPUT (line 427) correctly includes both ToolUseBlock and ServerToolUseBlock, so accumulate_event() properly accumulates the input JSON for both types
  • build_events() (line 363) only checks content_block.type == "tool_use", so InputJsonEvent is never fired for server_tool_use

The result: the streaming machinery accumulates the server tool input JSON internally but never surfaces it to the caller via the event stream.

Impact

Any code using on_input_json callbacks or iterating stream events to observe server tool input construction receives no events for server_tool_use blocks. The silence gives no indication that anything is wrong — the input is being accumulated, just not emitted.

Fix

Extend the type check to include server_tool_use, consistent with how TRACKS_TOOL_INPUT already handles both types.

Atishay Tiwari added 3 commits April 11, 2026 20:56
…silently

  The __stream__ methods in Stream and AsyncStream used separate if statements
  with no else clause, causing any unrecognized event type to be silently
  dropped. This broke client.beta.sessions.events.stream() entirely since
  managed agents emit different event names (agent.message, session.status_*)
  that don't match the hardcoded Messages API event list.

  Fix: Convert if/if/if/if to if/elif/elif/elif/else in both sync and async
  __stream__ methods so unknown events pass through process_data() instead
  of being silently discarded.

  Fixes anthropics#1357
ParsedContentBlock in types/parsed_message.py only included
WebSearchToolResultBlock but was missing 5 other server tool result types:

- CodeExecutionToolResultBlock
- WebFetchToolResultBlock
- BashCodeExecutionToolResultBlock
- TextEditorCodeExecutionToolResultBlock
- ToolSearchToolResultBlock

When any of these arrived as content_block_start events during streaming,
construct_type() failed discriminated union parsing and silently dropped them
from current_snapshot.content. As a result, get_final_message().content was
missing server tool results when client tools ran concurrently with server
tools — the bug reported in anthropics#1325.

Fix: add all 5 missing types to ParsedContentBlock to match ContentBlock.

Adds sync + async regression tests with a fixture that streams both
web_search_tool_result and code_execution_tool_result blocks alongside
a concurrent client tool_use, asserting all 4 blocks are present in
get_final_message().content.

Fixes anthropics#1325
…ta handler

build_events() only fired InputJsonEvent for tool_use blocks, skipping
server_tool_use entirely. This is inconsistent with TRACKS_TOOL_INPUT which
already includes ServerToolUseBlock — the SDK accumulates the input JSON
internally for server tool use blocks but never surfaces the InputJsonEvent
to the caller.

Anyone streaming server tool calls and listening to on_input_json receives
no events, even though the underlying JSON is being accumulated correctly.
@atishay2 atishay2 requested a review from a team as a code owner April 14, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant