From 6bce073520ae2691210c93f4b61f927ecdc10deb Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 11 Aug 2026 18:34:27 -0700 Subject: [PATCH] fix(responses): keep chat-shaped usage extras from colliding in the bridge Gemini image usage carries prompt_tokens and friends as extra fields on ResponseAPIUsage, which collided with the bridge's explicit kwargs and raised TypeError. Exclude keys the bridge already sets explicitly. --- litellm/responses/utils.py | 11 ++++++++++- .../responses/test_responses_utils.py | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/litellm/responses/utils.py b/litellm/responses/utils.py index c59f7afd88c..1907b5aa447 100644 --- a/litellm/responses/utils.py +++ b/litellm/responses/utils.py @@ -1099,7 +1099,16 @@ class ResponseAPILoggingUtils: extra_usage_fields: Final = { key: value for key, value in (response_api_usage.model_extra or {}).items() - if key not in ("input_token_details", "output_token_details") + if key + not in ( + "input_token_details", + "output_token_details", + "prompt_tokens", + "completion_tokens", + "total_tokens", + "prompt_tokens_details", + "completion_tokens_details", + ) } chat_usage: Final = Usage( prompt_tokens=prompt_tokens, diff --git a/tests/test_litellm/responses/test_responses_utils.py b/tests/test_litellm/responses/test_responses_utils.py index 4f1629eb431..2b9e6d34828 100644 --- a/tests/test_litellm/responses/test_responses_utils.py +++ b/tests/test_litellm/responses/test_responses_utils.py @@ -459,6 +459,25 @@ class TestResponseAPILoggingUtils: assert result.completion_tokens == 20 assert getattr(result, "server_side_tool_usage_details") == details + def test_transform_response_api_usage_ignores_chat_shaped_extras(self): + """Gemini image usage carries chat-shaped keys as extras; they must not collide with explicit kwargs.""" + usage = ResponseAPIUsage( + input_tokens=35, + output_tokens=1716, + total_tokens=1751, + prompt_tokens=35, + prompt_tokens_details={"image_tokens": 5, "text_tokens": 30}, + completion_tokens=1716, + completion_tokens_details={"image_tokens": 1120, "text_tokens": 596}, + server_side_tool_usage_details={"web_search_calls": 1}, + ) + + result = ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage(usage) + + assert result.prompt_tokens == 35 + assert result.completion_tokens == 1716 + assert getattr(result, "server_side_tool_usage_details") == {"web_search_calls": 1} + def test_transform_already_chat_usage_passthrough_keeps_tool_details(self): """Re-running the bridge on an already-converted chat Usage must not drop fields.""" details = {"web_search_calls": 2, "x_search_calls": 0}