Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pydantic_ai_slim/pydantic_ai/_parts_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def handle_thinking_delta(
*,
vendor_part_id: Hashable | None,
content: str | None = None,
id: str | None = None,
signature: str | None = None,
) -> ModelResponseStreamEvent:
"""Handle incoming thinking content, creating or updating a ThinkingPart in the manager as appropriate.
Expand All @@ -167,6 +168,7 @@ def handle_thinking_delta(
of thinking. If None, a new part will be created unless the latest part is already
a ThinkingPart.
content: The thinking content to append to the appropriate ThinkingPart.
id: An optional id for the thinking part.
signature: An optional signature for the thinking content.

Returns:
Expand Down Expand Up @@ -197,7 +199,7 @@ def handle_thinking_delta(
if content 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, signature=signature)
part = ThinkingPart(content=content, id=id, signature=signature)
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)
Expand Down
21 changes: 9 additions & 12 deletions pydantic_ai_slim/pydantic_ai/models/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,12 +1270,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:
tool_call_id=chunk.item.call_id,
)
elif isinstance(chunk.item, responses.ResponseReasoningItem):
content = chunk.item.summary[0].text if chunk.item.summary else ''
yield self._parts_manager.handle_thinking_delta(
vendor_part_id=chunk.item.id,
content=content,
signature=chunk.item.id,
)
pass
elif isinstance(chunk.item, responses.ResponseOutputMessage):
pass
elif isinstance(chunk.item, responses.ResponseFunctionWebSearch):
Expand All @@ -1291,7 +1286,11 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:
pass

elif isinstance(chunk, responses.ResponseReasoningSummaryPartAddedEvent):
pass # there's nothing we need to do here
yield self._parts_manager.handle_thinking_delta(
vendor_part_id=f'{chunk.item_id}-{chunk.summary_index}',
content=chunk.part.text,
id=chunk.item_id,
)

elif isinstance(chunk, responses.ResponseReasoningSummaryPartDoneEvent):
pass # there's nothing we need to do here
Expand All @@ -1301,19 +1300,17 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:

elif isinstance(chunk, responses.ResponseReasoningSummaryTextDeltaEvent):
yield self._parts_manager.handle_thinking_delta(
vendor_part_id=chunk.item_id,
vendor_part_id=f'{chunk.item_id}-{chunk.summary_index}',
content=chunk.delta,
signature=chunk.item_id,
id=chunk.item_id,
)

# TODO(Marcelo): We should support annotations in the future.
elif isinstance(chunk, responses.ResponseOutputTextAnnotationAddedEvent):
pass # there's nothing we need to do here

elif isinstance(chunk, responses.ResponseTextDeltaEvent):
maybe_event = self._parts_manager.handle_text_delta(
vendor_part_id=chunk.content_index, content=chunk.delta
)
maybe_event = self._parts_manager.handle_text_delta(vendor_part_id=chunk.item_id, content=chunk.delta)
if maybe_event is not None: # pragma: no branch
yield maybe_event

Expand Down
Loading