Skip to content

fix(types): sync ParsedBetaContentBlock union with BetaContentBlock#1445

Open
abhicris wants to merge 1 commit intoanthropics:mainfrom
abhicris:fix/parsed-beta-content-block-union-sync
Open

fix(types): sync ParsedBetaContentBlock union with BetaContentBlock#1445
abhicris wants to merge 1 commit intoanthropics:mainfrom
abhicris:fix/parsed-beta-content-block-union-sync

Conversation

@abhicris
Copy link
Copy Markdown

Closes #1422.

Bug

`ParsedBetaContentBlock` (the union used by `ParsedBetaMessage.content` in the beta streaming accumulator) was missing three block types that the sibling `BetaContentBlock` does include:

  • `BetaWebFetchToolResultBlock`
  • `BetaAdvisorToolResultBlock` (also missing — added while syncing)
  • `BetaToolSearchToolResultBlock`

When `accumulate_event` in `lib/streaming/beta_messages.py` calls `construct_type(type=ParsedBetaContentBlock, value=event.content_block.to_dict())` for a `content_block_start` carrying any of those three result blocks, pydantic's discriminated-union resolution fails to match and the block is silently dropped from `stream.get_final_message().content`.

Fix

Add the missing imports and union members so `ParsedBetaContentBlock` mirrors `BetaContentBlock` exactly. Keeping the two unions in lockstep is the property we actually want — there's no reason any block type that streams should be absent from the parsed snapshot.

```diff
ParsedBetaContentBlock: TypeAlias = Annotated[
Union[
ParsedBetaTextBlock[ResponseFormatT],
BetaThinkingBlock,
BetaRedactedThinkingBlock,
BetaToolUseBlock,
BetaServerToolUseBlock,
BetaWebSearchToolResultBlock,

  •    BetaWebFetchToolResultBlock,
    
  •    BetaAdvisorToolResultBlock,
       BetaCodeExecutionToolResultBlock,
       BetaBashCodeExecutionToolResultBlock,
       BetaTextEditorCodeExecutionToolResultBlock,
    
  •    BetaToolSearchToolResultBlock,
       BetaMCPToolUseBlock,
       BetaMCPToolResultBlock,
       BetaContainerUploadBlock,
       BetaCompactionBlock,
    
    ],
    PropertyInfo(discriminator="type"),
    ]
    ```

`+6 / -0`. Type-only change; no runtime behavior change apart from the previously-dropped blocks now being present in `stream.get_final_message().content`.

The issue body explicitly named tool-search and web-fetch; advisor was added because it has the same root cause and the same fix. Happy to drop it if you'd rather keep this PR strictly to the issue's letter.


Contributed by kcolbchain.

…loses anthropics#1422)

`ParsedBetaContentBlock` (the union used by `ParsedBetaMessage.content` in the
beta streaming accumulator) was missing three block types that the sibling
`BetaContentBlock` does include:

  - `BetaWebFetchToolResultBlock`
  - `BetaAdvisorToolResultBlock`
  - `BetaToolSearchToolResultBlock`

Impact: when `accumulate_event` in `lib/streaming/_beta_messages.py` calls
`construct_type(type_=ParsedBetaContentBlock, value=...)` for a
`content_block_start` carrying any of those three result blocks, pydantic's
discriminated-union resolution fails to match and the block is silently dropped.
The block never appears in `stream.get_final_message().content`, even though
it was present on the wire.

The issue called out `tool_search` and `web_fetch`; while syncing, also added
`BetaAdvisorToolResultBlock` since it's present in `BetaContentBlock` and
absent here for the same reason. Keeping the two unions in lockstep is the
property we actually want.
@abhicris abhicris requested a review from a team as a code owner April 25, 2026 09:53
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.

ParsedBetaContentBlock union missing tool_search/web_fetch result blocks — stream accumulator drops them from get_final_message()

1 participant