From 12bfff9921cb7add7d862ecbad31c4f4f4db0a96 Mon Sep 17 00:00:00 2001 From: "2285166171@qq.com" <2285166171@qq.com> Date: Fri, 20 Mar 2026 10:27:34 +0800 Subject: [PATCH] fix(streaming): handle dict objects that lack to_dict() in stream accumulator When using beta streaming with certain betas (e.g. effort, code-execution), the accumulator intermittently receives raw dicts instead of Pydantic models for message_start and content_block_start events. Calling .to_dict() on a dict raises AttributeError. Add hasattr checks to fall back to dict() when to_dict is not available, in both beta and non-beta streaming paths. Fixes #1088 --- src/anthropic/lib/streaming/_beta_messages.py | 8 ++++++-- src/anthropic/lib/streaming/_messages.py | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/anthropic/lib/streaming/_beta_messages.py b/src/anthropic/lib/streaming/_beta_messages.py index c1447a8d..6d2c40f9 100644 --- a/src/anthropic/lib/streaming/_beta_messages.py +++ b/src/anthropic/lib/streaming/_beta_messages.py @@ -467,8 +467,9 @@ def accumulate_event( if current_snapshot is None: if event.type == "message_start": + message_data = event.message.to_dict() if hasattr(event.message, "to_dict") else dict(event.message) return cast( - ParsedBetaMessage[ResponseFormatT], ParsedBetaMessage.construct(**cast(Any, event.message.to_dict())) + ParsedBetaMessage[ResponseFormatT], ParsedBetaMessage.construct(**cast(Any, message_data)) ) raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"') @@ -478,7 +479,10 @@ def accumulate_event( current_snapshot.content.append( cast( Any, # Pydantic does not support generic unions at runtime - construct_type(type_=ParsedBetaContentBlock, value=event.content_block.to_dict()), + construct_type( + type_=ParsedBetaContentBlock, + value=event.content_block.to_dict() if hasattr(event.content_block, "to_dict") else dict(event.content_block), + ), ), ) elif event.type == "content_block_delta": diff --git a/src/anthropic/lib/streaming/_messages.py b/src/anthropic/lib/streaming/_messages.py index b6b5f538..6f60acf3 100644 --- a/src/anthropic/lib/streaming/_messages.py +++ b/src/anthropic/lib/streaming/_messages.py @@ -449,7 +449,8 @@ def accumulate_event( if current_snapshot is None: if event.type == "message_start": - return cast(ParsedMessage[ResponseFormatT], ParsedMessage.construct(**cast(Any, event.message.to_dict()))) + message_data = event.message.to_dict() if hasattr(event.message, "to_dict") else dict(event.message) + return cast(ParsedMessage[ResponseFormatT], ParsedMessage.construct(**cast(Any, message_data))) raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"')