-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Initial Checks
- I confirm that I'm using the latest version of Pydantic AI
- I confirm that I searched for my issue in https://github.com/pydantic/pydantic-ai/issues before opening this issue
Description
Another issue I've spotted is with the ThinkingPart. When OpenAi streams the thinking events they create a thinking part and then they split it into separate thinking parts where each part starts and ends, but pydantic_ai doesn't maintain this separation so for example when there's more than one thinking part we will get something like this:
2025-07-07 12:48:18,418 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' package'))
2025-07-07 12:48:18,419 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' everything'))
2025-07-07 12:48:18,473 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' into'))
2025-07-07 12:48:18,474 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a'))
2025-07-07 12:48:18,475 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' JSON'))
2025-07-07 12:48:18,542 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' structure'))
2025-07-07 12:48:18,544 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' as'))
2025-07-07 12:48:18,546 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' requested'))
2025-07-07 12:48:18,553 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.'))
2025-07-07 12:48:20,609 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='**Form'))
2025-07-07 12:48:20,612 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='ulating'))
2025-07-07 12:48:20,670 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the'))
2025-07-07 12:48:20,670 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' summary'))
2025-07-07 12:48:20,734 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="**\n\nI'm"))
2025-07-07 12:48:20,736 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' counting'))
2025-07-07 12:48:20,738 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' words'))
2025-07-07 12:48:20,785 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to'))
2025-07-07 12:48:20,786 - INFO - Part delta: PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ensure'))
You can see that the "**Form" chunk is the start of a new thinking component, but when streaming there's no "\n\n" before it because OpenAI has built-in separation for these events.
Look here:
https://platform.openai.com/docs/api-reference/responses-streaming/response/reasoning_summary_part
The could be several reasoning_summary events under the same reasoning_summmary part that each will start with a delta event and end with a done event, which we are missing here.
Here's your response (from @DouweM):
Example Code
Python, Pydantic AI & LLM client version
Python 3.11
Pydantic 0.3.5
OpenAI