Skip to content

Commit 1969142

Browse files
authored
models - openai - null usage (#442)
1 parent e1ca809 commit 1969142

File tree

4 files changed

+45
-9
lines changed

4 files changed

+45
-9
lines changed

src/strands/models/litellm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ async def stream(
177177
async for event in response:
178178
_ = event
179179

180-
yield self.format_chunk({"chunk_type": "metadata", "data": event.usage})
180+
if event.usage:
181+
yield self.format_chunk({"chunk_type": "metadata", "data": event.usage})
181182

182183
logger.debug("finished streaming response from model")
183184

src/strands/models/openai.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ async def stream(
394394
async for event in response:
395395
_ = event
396396

397-
yield self.format_chunk({"chunk_type": "metadata", "data": event.usage})
397+
if event.usage:
398+
yield self.format_chunk({"chunk_type": "metadata", "data": event.usage})
398399

399400
logger.debug("finished streaming response from model")
400401

tests/strands/models/test_litellm.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,42 @@ async def test_stream(litellm_acompletion, api_key, model_id, model, agenerator,
197197
litellm_acompletion.assert_called_once_with(**expected_request)
198198

199199

200+
@pytest.mark.asyncio
201+
async def test_stream_empty(litellm_acompletion, api_key, model_id, model, agenerator, alist):
202+
mock_delta = unittest.mock.Mock(content=None, tool_calls=None, reasoning_content=None)
203+
204+
mock_event_1 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason=None, delta=mock_delta)])
205+
mock_event_2 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason="stop", delta=mock_delta)])
206+
mock_event_3 = unittest.mock.Mock()
207+
mock_event_4 = unittest.mock.Mock(usage=None)
208+
209+
litellm_acompletion.side_effect = unittest.mock.AsyncMock(
210+
return_value=agenerator([mock_event_1, mock_event_2, mock_event_3, mock_event_4])
211+
)
212+
213+
messages = [{"role": "user", "content": []}]
214+
response = model.stream(messages)
215+
216+
tru_events = await alist(response)
217+
exp_events = [
218+
{"messageStart": {"role": "assistant"}},
219+
{"contentBlockStart": {"start": {}}},
220+
{"contentBlockStop": {}},
221+
{"messageStop": {"stopReason": "end_turn"}},
222+
]
223+
224+
assert len(tru_events) == len(exp_events)
225+
expected_request = {
226+
"api_key": api_key,
227+
"model": model_id,
228+
"messages": [],
229+
"stream": True,
230+
"stream_options": {"include_usage": True},
231+
"tools": [],
232+
}
233+
litellm_acompletion.assert_called_once_with(**expected_request)
234+
235+
200236
@pytest.mark.asyncio
201237
async def test_structured_output(litellm_acompletion, model, test_output_model_cls, alist):
202238
messages = [{"role": "user", "content": [{"text": "Generate a person"}]}]

tests/strands/models/test_openai.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ def test_format_chunk_unknown_type(model):
382382

383383

384384
@pytest.mark.asyncio
385-
async def test_stream(openai_client, model, agenerator, alist):
385+
async def test_stream(openai_client, model_id, model, agenerator, alist):
386386
mock_tool_call_1_part_1 = unittest.mock.Mock(index=0)
387387
mock_tool_call_2_part_1 = unittest.mock.Mock(index=1)
388388
mock_delta_1 = unittest.mock.Mock(
@@ -465,7 +465,7 @@ async def test_stream(openai_client, model, agenerator, alist):
465465
# Verify that format_request was called with the correct arguments
466466
expected_request = {
467467
"max_tokens": 1,
468-
"model": "m1",
468+
"model": model_id,
469469
"messages": [{"role": "user", "content": [{"text": "calculate 2+2", "type": "text"}]}],
470470
"stream": True,
471471
"stream_options": {"include_usage": True},
@@ -475,14 +475,13 @@ async def test_stream(openai_client, model, agenerator, alist):
475475

476476

477477
@pytest.mark.asyncio
478-
async def test_stream_empty(openai_client, model, agenerator, alist):
478+
async def test_stream_empty(openai_client, model_id, model, agenerator, alist):
479479
mock_delta = unittest.mock.Mock(content=None, tool_calls=None, reasoning_content=None)
480-
mock_usage = unittest.mock.Mock(prompt_tokens=0, completion_tokens=0, total_tokens=0)
481480

482481
mock_event_1 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason=None, delta=mock_delta)])
483482
mock_event_2 = unittest.mock.Mock(choices=[unittest.mock.Mock(finish_reason="stop", delta=mock_delta)])
484483
mock_event_3 = unittest.mock.Mock()
485-
mock_event_4 = unittest.mock.Mock(usage=mock_usage)
484+
mock_event_4 = unittest.mock.Mock(usage=None)
486485

487486
openai_client.chat.completions.create = unittest.mock.AsyncMock(
488487
return_value=agenerator([mock_event_1, mock_event_2, mock_event_3, mock_event_4]),
@@ -497,13 +496,12 @@ async def test_stream_empty(openai_client, model, agenerator, alist):
497496
{"contentBlockStart": {"start": {}}},
498497
{"contentBlockStop": {}},
499498
{"messageStop": {"stopReason": "end_turn"}},
500-
{"metadata": {"usage": {"inputTokens": 0, "outputTokens": 0, "totalTokens": 0}, "metrics": {"latencyMs": 0}}},
501499
]
502500

503501
assert len(tru_events) == len(exp_events)
504502
expected_request = {
505503
"max_tokens": 1,
506-
"model": "m1",
504+
"model": model_id,
507505
"messages": [],
508506
"stream": True,
509507
"stream_options": {"include_usage": True},

0 commit comments

Comments
 (0)