8000 fix: Handle empty choices in OpenAI model provider (#185) · lgigit200/sdk-python@a64e80d · GitHub
[go: up one dir, main page]

Skip to content

Commit a64e80d

Browse files
mrityunjayshuklaMrityunjay Shukla
andauthored
fix: Handle empty choices in OpenAI model provider (strands-agents#185)
Co-authored-by: Mrityunjay Shukla <mrshukla@amazon.com>
1 parent 903a260 commit a64e80d

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

src/strands/models/openai.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ def stream(self, request: dict[str, Any]) -> Iterable[dict[str, Any]]:
9494
tool_calls: dict[int, list[Any]] = {}
9595

9696
for event in response:
97+
# Defensive: skip events with empty or missing choices
98+
if not getattr(event, "choices", None):
99+
continue
97100
choice = event.choices[0]
98101

99102
if choice.delta.content:

tests/strands/models/test_openai.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,44 @@ def test_stream_empty(openai_client, model):
132132

133133
assert tru_events == exp_events
134134
openai_client.chat.completions.create.assert_called_once_with(**request)
135+
136+
137+
def test_stream_with_empty_choices(openai_client, model):
138+
mock_delta = unittest.mock.Mock(content="content", tool_calls=None)
139+
mock_usage = unittest.mock.Mock(prompt_tokens=10, completion_tokens=20, total_tokens=30)
140+
141+
# Event with no choices attribute
142+
mock_event_1 = unittest.mock.Mock(spec=[])
143+
144+
# Event with empty choices list
145+
mock_event_2 = unittest.mock.Mock(choices=[])
146+
147+
# Valid event with content
148+
mock_event_3 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason=None, delta=mock_delta)])
149+
150+
# Event with finish reason
151+
mock_event_4 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason="stop", delta=mock_delta)])
152+
153+
# Final event with usage info
154+
mock_event_5 = unittest.mock.Mock(usage=mock_usage)
155+
156+
openai_client.chat.completions.create.return_value = iter(
157+
[mock_event_1, mock_event_2, mock_event_3, mock_event_4, mock_event_5]
158+
)
159+
160+
request = {"model": "m1", "messages": [{"role": "user", "content": ["test"]}]}
161+
response = model.stream(request)
162+
163+
tru_events = list(response)
164+
exp_events = [
165+
{"chunk_type": "message_start"},
166+
{"chunk_type": "content_start", "data_type": "text"},
167+
{"chunk_type": "content_delta", "data_type": "text", "data": "content"},
168+
{"chunk_type": "content_delta", "data_type": "text", "data": "content"},
169+
{"chunk_type": "content_stop", "data_type": "text"},
170+
{"chunk_type": "message_stop", "data": "stop"},
171+
{"chunk_type": "metadata", "data": mock_usage},
172+
]
173+
174+
assert tru_events == exp_events
175+
openai_client.chat.completions.create.assert_called_once_with(**request)

0 commit comments

Comments
 (0)
0