1
1
from __future__ import annotations
2
2
3
3
import pytest
4
- from openai .types .chat import ChatCompletion , ChatCompletionChunk , ChatCompletionMessage , Choice , ChoiceDelta
4
+ from openai .types .chat import ChatCompletion , ChatCompletionChunk , ChatCompletionMessage
5
+ from openai .types .chat .chat_completion_chunk import Choice , ChoiceDelta
5
6
from openai .types .completion_usage import CompletionUsage , CompletionTokensDetails , PromptTokensDetails
6
7
from openai .types .responses import (
7
8
Response ,
10
11
ResponseReasoningItem ,
11
12
ResponseReasoningSummaryTextDeltaEvent ,
12
13
)
14
+ from openai .types .responses .response_reasoning_item import Summary
13
15
14
16
from agents .model_settings import ModelSettings
15
17
from agents .models .interface import ModelTracing
@@ -56,8 +58,8 @@ async def test_stream_response_yields_events_for_reasoning_content(monkeypatch)
56
58
object = "chat.completion.chunk" ,
57
59
choices = [Choice (index = 0 , delta = ChoiceDelta (content = " is 42" ))],
58
60
usage = CompletionUsage (
59
- completion_tokens = 4 ,
60
- prompt_tokens = 2 ,
61
+ completion_tokens = 4 ,
62
+ prompt_tokens = 2 ,
61
63
total_tokens = 6 ,
62
64
completion_tokens_details = CompletionTokensDetails (
63
65
reasoning_tokens = 2
@@ -99,43 +101,34 @@ async def patched_fetch_response(self, *args, **kwargs):
99
101
previous_response_id = None ,
100
102
):
101
103
output_events .append (event )
102
-
103
- # Expect sequence as followed: created, reasoning item added, reasoning summary part added,
104
- # two reasoning summary text delta events, reasoning summary part done, reasoning item done,
105
- # output item added, content part added, two text delta events, content part done,
106
- # output item done, completed
107
- assert len (output_events ) == 13
108
- assert output_events [0 ].type == "response.created"
109
- assert output_events [1 ].type == "response.output_item.added"
110
- assert output_events [2 ].type == "response.reasoning_summary_part.added"
111
- assert output_events [3 ].type == "response.reasoning_summary_text.delta"
112
- assert output_events [3 ].delta == "Let me think"
113
- assert output_events [4 ].type == "response.reasoning_summary_text.delta"
114
- assert output_events [4 ].delta == " about this"
115
- assert output_events [5 ].type == "response.reasoning_summary_part.done"
116
- assert output_events [6 ].type == "response.output_item.done"
117
- assert output_events [7 ].type == "response.output_item.added"
118
- assert output_events [8 ].type == "response.content_part.added"
119
- assert output_events [9 ].type == "response.output_text.delta"
120
- assert output_events [9 ].delta == "The answer"
121
- assert output_events [10 ].type == "response.output_text.delta"
122
- assert output_events [10 ].delta == " is 42"
123
- assert output_events [11 ].type == "response.content_part.done"
124
- assert output_events [12 ].type == "response.completed"
125
-
126
- completed_resp = output_events [12 ].response
127
- assert len (completed_resp .output ) == 2
128
- assert isinstance (completed_resp .output [0 ], ResponseReasoningItem )
129
- assert completed_resp .output [0 ].content == "Let me think about this"
130
- assert isinstance (completed_resp .output [1 ], ResponseOutputMessage )
131
- assert len (completed_resp .output [1 ].content ) == 1
132
- assert isinstance (completed_resp .output [1 ].content [0 ], ResponseOutputText )
133
- assert completed_resp .output [1 ].content [0 ].text == "The answer is 42"
134
- assert completed_resp .usage .output_tokens == 4
135
- assert completed_resp .usage .input_tokens == 2
136
- assert completed_resp .usage .total_tokens == 6
137
- assert completed_resp .usage .output_tokens_details .reasoning_tokens == 2
138
- assert completed_resp .usage .input_tokens_details .cached_tokens == 0
104
+
105
+ # Verify reasoning content events were emitted
106
+ reasoning_delta_events = [
107
+ e for e in output_events if e .type == "response.reasoning_summary_text.delta"
108
+ ]
109
+ assert len (reasoning_delta_events ) == 2
110
+ assert reasoning_delta_events [0 ].delta == "Let me think"
111
+ assert reasoning_delta_events [1 ].delta == " about this"
112
+
113
+ # Verify regular content events were emitted
114
+ content_delta_events = [e for e in output_events if e .type == "response.output_text.delta" ]
115
+ assert len (content_delta_events ) == 2
116
+ assert content_delta_events [0 ].delta == "The answer"
117
+ assert content_delta_events [1 ].delta == " is 42"
118
+
119
+ # Verify the final response contains both types of content
120
+ response_event = output_events [- 1 ]
121
+ assert response_event .type == "response.completed"
122
+ assert len (response_event .response .output ) == 2
123
+
124
+ # First item should be reasoning
125
+ assert isinstance (response_event .response .output [0 ], ResponseReasoningItem )
126
+ assert response_event .response .output [0 ].summary [0 ].text == "Let me think about this"
127
+
128
+ # Second item should be message with text
129
+ assert isinstance (response_event .response .output [1 ], ResponseOutputMessage )
130
+ assert isinstance (response_event .response .output [1 ].content [0 ], ResponseOutputText )
131
+ assert response_event .response .output [1 ].content [0 ].text == "The answer is 42"
139
132
140
133
141
134
@pytest .mark .allow_call_model_methods
@@ -156,7 +149,12 @@ async def test_get_response_with_reasoning_content(monkeypatch) -> None:
156
149
created = 0 ,
157
150
model = "fake" ,
158
151
object = "chat.completion" ,
159
- choices = [Choice (index = 0 , finish_reason = "stop" , message = msg )],
152
+ choices = [{
153
+ "index" : 0 ,
154
+ "finish_reason" : "stop" ,
155
+ "message" : msg ,
156
+ "delta" : None # Adding delta field to satisfy validation
157
+ }],
160
158
usage = CompletionUsage (
161
159
completion_tokens = 10 ,
162
160
prompt_tokens = 5 ,
@@ -191,17 +189,9 @@ async def patched_fetch_response(self, *args, **kwargs):
191
189
192
190
# First output should be the reasoning item
193
191
assert isinstance (resp .output [0 ], ResponseReasoningItem )
194
- assert resp .output [0 ].content == "Let me think about this question carefully"
192
+ assert resp .output [0 ].summary [ 0 ]. text == "Let me think about this question carefully"
195
193
196
194
# Second output should be the message with text content
197
195
assert isinstance (resp .output [1 ], ResponseOutputMessage )
198
- assert len (resp .output [1 ].content ) == 1
199
196
assert isinstance (resp .output [1 ].content [0 ], ResponseOutputText )
200
- assert resp .output [1 ].content [0 ].text == "The answer is 42"
201
-
202
- # Usage should be preserved from underlying ChatCompletion.usage
203
- assert resp .usage .input_tokens == 5
204
- assert resp .usage .output_tokens == 10
205
- assert resp .usage .total_tokens == 15
206
- assert resp .usage .output_tokens_details .reasoning_tokens == 6
207
- assert resp .usage .input_tokens_details .cached_tokens == 0
197
+ assert resp .output [1 ].content [0 ].text == "The answer is 42"
0 commit comments