From ff957a897baf6cb15c16b57c80790011b93cdf2c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 16:11:22 +0000 Subject: [PATCH] test(responses): cover usage and event coercion edge cases for #34754 --- .../responses/test_response_construction.py | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/tests/test_litellm/responses/test_response_construction.py b/tests/test_litellm/responses/test_response_construction.py index 565803a25f6..ef3a1d4befe 100644 --- a/tests/test_litellm/responses/test_response_construction.py +++ b/tests/test_litellm/responses/test_response_construction.py @@ -13,7 +13,10 @@ import pytest from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig -from litellm.responses.response_construction import construct_responses_api_response +from litellm.responses.response_construction import ( + construct_responses_api_response, + construct_responses_api_stream_event, +) from litellm.router import Router from litellm.types.llms.openai import ( ResponseAPIUsage, @@ -67,12 +70,30 @@ def test_usage_total_tokens_derived_when_missing(): assert response.usage.total_tokens == 7 -def test_unparseable_usage_is_dropped_not_left_as_dict(): - response = construct_responses_api_response({"id": "resp_1", "created_at": 1, "usage": "not-a-usage-block"}) +@pytest.mark.parametrize( + "usage_value", + ["not-a-usage-block", {"input_tokens": 1, "output_tokens": 2, "input_tokens_details": "not-details"}], +) +def test_unparseable_usage_is_dropped_not_left_as_dict(usage_value): + response = construct_responses_api_response({"id": "resp_1", "created_at": 1, "usage": usage_value}) assert response.usage is None +@pytest.mark.parametrize( + ("token_value", "expected"), + [("9", 9), (True, 0), ("nine", 0), (None, 0)], +) +def test_token_counts_coerced_from_loose_provider_values(token_value, expected): + response = construct_responses_api_response( + {"id": "resp_1", "created_at": 1, "usage": {"input_tokens": token_value, "output_tokens": 2}} + ) + + assert isinstance(response.usage, ResponseAPIUsage) + assert response.usage.input_tokens == expected + assert response.usage.total_tokens == expected + 2 + + def test_valid_payload_is_validated_not_constructed(): response = construct_responses_api_response( { @@ -94,6 +115,16 @@ def test_streaming_event_response_is_not_a_dict(): assert isinstance(event.response.usage, ResponseAPIUsage) +def test_streaming_event_without_nested_response_is_still_constructed(): + event = construct_responses_api_stream_event( + ResponseCompletedEvent, + {"type": "response.completed", "response": "not-a-payload"}, + ) + + assert isinstance(event, ResponseCompletedEvent) + assert event.response == "not-a-payload" + + def test_router_extracts_partial_usage_from_dict_format_response(): """Path 1: router fallback usage extraction returned .response.usage -> HTTP 500.""" event = _transform_completed_chunk()