From 31f270cd6c533f87920e9503a92ad87db8b444cc Mon Sep 17 00:00:00 2001 From: Mohammad Javad Naderi Date: Thu, 23 Jul 2026 05:06:21 +0330 Subject: [PATCH] fix(logging): preserve Responses API streaming usage --- litellm/litellm_core_utils/litellm_logging.py | 15 ------- .../test_litellm_logging.py | 44 +++++++++++++++++++ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index a72d46e3fe8..b6240588298 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -3409,21 +3409,6 @@ class Logging(LiteLLMLoggingBaseClass): result, (ResponseCompletedEvent, ResponseIncompleteEvent, ResponseFailedEvent), ): - ## return unified Usage object - if isinstance(result.response.usage, ResponseAPIUsage): - transformed_usage: Final = ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage( - result.response.usage - ) - # Set as dict instead of Usage object so model_dump() serializes it correctly - setattr( - result.response, - "usage", - ( - transformed_usage.model_dump() - if hasattr(transformed_usage, "model_dump") - else dict(transformed_usage) - ), - ) return result.response else: return None diff --git a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py index 28a6c8dd18d..7004c1a7846 100644 --- a/tests/test_litellm/litellm_core_utils/test_litellm_logging.py +++ b/tests/test_litellm/litellm_core_utils/test_litellm_logging.py @@ -2721,6 +2721,50 @@ def test_get_assembled_streaming_response_returns_result_for_streaming(): assert assembled is result +def test_get_assembled_streaming_response_preserves_responses_usage(): + import datetime + + from litellm.litellm_core_utils.litellm_logging import StandardLoggingPayloadSetup + from litellm.types.llms.openai import ( + ResponseAPIUsage, + ResponseCompletedEvent, + ResponsesAPIResponse, + ResponsesAPIStreamEvents, + ) + + logging_obj = _make_logging_obj(stream=True) + response = ResponsesAPIResponse( + id="resp-1", + created_at=1700000000, + output=[], + usage=ResponseAPIUsage( + input_tokens=4, + output_tokens=5, + total_tokens=9, + ), + ) + event = ResponseCompletedEvent( + type=ResponsesAPIStreamEvents.RESPONSE_COMPLETED, + response=response, + ) + + assembled = logging_obj._get_assembled_streaming_response( + result=event, + start_time=datetime.datetime.now(), + end_time=datetime.datetime.now(), + is_async=True, + streaming_chunks=[], + ) + + assert isinstance(assembled, ResponsesAPIResponse) + assembled.model_dump(warnings="error") + assert isinstance(assembled.usage, ResponseAPIUsage) + logging_usage = StandardLoggingPayloadSetup.get_usage_from_response_obj(assembled.model_dump()) + assert logging_usage.prompt_tokens == 4 + assert logging_usage.completion_tokens == 5 + assert logging_usage.total_tokens == 9 + + def test_streaming_success_handler_includes_vertex_ai_metadata_in_standard_logging(): """Assembled streaming responses should include Vertex AI metadata in logging payload.""" import datetime