diff --git a/pydantic_ai_slim/pydantic_ai/_parts_manager.py b/pydantic_ai_slim/pydantic_ai/_parts_manager.py index 3988f1ea8c..76b3f2b482 100644 --- a/pydantic_ai_slim/pydantic_ai/_parts_manager.py +++ b/pydantic_ai_slim/pydantic_ai/_parts_manager.py @@ -198,16 +198,16 @@ def handle_thinking_delta( existing_thinking_part_and_index = existing_part, part_index if existing_thinking_part_and_index is None: - if content is not None: + if content is not None or signature is not None: # There is no existing thinking part that should be updated, so create a new one new_part_index = len(self._parts) - part = ThinkingPart(content=content, id=id, signature=signature, provider_name=provider_name) + part = ThinkingPart(content=content or '', id=id, signature=signature, provider_name=provider_name) if vendor_part_id is not None: # pragma: no branch self._vendor_id_to_part_index[vendor_part_id] = new_part_index self._parts.append(part) return PartStartEvent(index=new_part_index, part=part) else: - raise UnexpectedModelBehavior('Cannot create a ThinkingPart with no content') + raise UnexpectedModelBehavior('Cannot create a ThinkingPart with no content or signature') else: if content is not None or signature is not None: # Update the existing ThinkingPart with the new content and/or signature delta diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 509b7fdf59..49b69f9567 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -641,7 +641,6 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: yield self._parts_manager.handle_thinking_delta( vendor_part_id=event.index, id='redacted_thinking', - content='', signature=current_block.data, provider_name=self.provider_name, ) diff --git a/pydantic_ai_slim/pydantic_ai/models/bedrock.py b/pydantic_ai_slim/pydantic_ai/models/bedrock.py index a7a2182146..2b53ac0a30 100644 --- a/pydantic_ai_slim/pydantic_ai/models/bedrock.py +++ b/pydantic_ai_slim/pydantic_ai/models/bedrock.py @@ -681,7 +681,6 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: yield self._parts_manager.handle_thinking_delta( vendor_part_id=index, id='redacted_content', - content='', signature=redacted_content.decode('utf-8'), provider_name=self.provider_name, ) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 5b724fca3c..75d2adbe17 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -596,7 +596,6 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: signature = base64.b64encode(part.thought_signature).decode('utf-8') yield self._parts_manager.handle_thinking_delta( vendor_part_id='thinking', - content='', # A thought signature may occur without a preceding thinking part, so we add an empty delta so that a new part can be created signature=signature, provider_name=self.provider_name, ) diff --git a/tests/models/test_google.py b/tests/models/test_google.py index bfdeebda5a..4b143646bc 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -1226,9 +1226,7 @@ def dummy() -> None: ... # pragma: no cover PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), - PartDeltaEvent( - index=0, delta=ThinkingPartDelta(content_delta='', signature_delta=IsStr(), provider_name='google-gla') - ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(signature_delta=IsStr(), provider_name='google-gla')), PartStartEvent(index=1, part=TextPart(content=IsStr())), FinalResultEvent(tool_name=None, tool_call_id=None), PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())),