From accdaa4a74a156ecc98586fd58f40c95413b14e6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 12 Mar 2025 11:12:09 -0700 Subject: [PATCH] fix ResponseAPILoggingUtils --- litellm/cost_calculator.py | 17 ++++++++++++++--- .../test_openai_responses_api.py | 14 ++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index fb49c079812..209db5247dc 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -45,7 +45,11 @@ from litellm.llms.vertex_ai.image_generation.cost_calculator import ( cost_calculator as vertex_ai_image_cost_calculator, ) from litellm.responses.utils import ResponseAPILoggingUtils -from litellm.types.llms.openai import HttpxBinaryResponseContent, ResponsesAPIResponse +from litellm.types.llms.openai import ( + HttpxBinaryResponseContent, + ResponseAPIUsage, + ResponsesAPIResponse, +) from litellm.types.rerank import RerankBilledUnits, RerankResponse from litellm.types.utils import ( CallTypesLiteral, @@ -465,6 +469,13 @@ def _get_usage_object( return usage_obj +def _is_known_usage_objects(usage_obj): + """Returns True if the usage obj is a known Usage type""" + return isinstance(usage_obj, litellm.Usage) or isinstance( + usage_obj, ResponseAPIUsage + ) + + def _infer_call_type( call_type: Optional[CallTypesLiteral], completion_response: Any ) -> Optional[CallTypesLiteral]: @@ -588,8 +599,8 @@ def completion_cost( # noqa: PLR0915 ) else: usage_obj = getattr(completion_response, "usage", {}) - if isinstance(usage_obj, BaseModel) and not isinstance( - usage_obj, litellm.Usage + if isinstance(usage_obj, BaseModel) and not _is_known_usage_objects( + usage_obj=usage_obj ): setattr( completion_response, diff --git a/tests/llm_responses_api_testing/test_openai_responses_api.py b/tests/llm_responses_api_testing/test_openai_responses_api.py index 777a70dcafd..a8324505059 100644 --- a/tests/llm_responses_api_testing/test_openai_responses_api.py +++ b/tests/llm_responses_api_testing/test_openai_responses_api.py @@ -13,6 +13,8 @@ from litellm.types.llms.openai import ( ResponseCompletedEvent, ResponsesAPIResponse, ResponseTextConfig, + ResponseAPIUsage, + IncompleteDetails, ) @@ -50,7 +52,7 @@ def validate_responses_api_response(response): # Optional fields with their expected types optional_fields = { "error": (dict, type(None)), # error can be dict or None - "incomplete_details": (dict, type(None)), + "incomplete_details": (IncompleteDetails, type(None)), "instructions": (str, type(None)), "metadata": dict, "model": str, @@ -65,7 +67,7 @@ def validate_responses_api_response(response): "status": str, "text": ResponseTextConfig, "truncation": str, - # "usage": dict, + "usage": ResponseAPIUsage, "user": (str, type(None)), } @@ -89,9 +91,13 @@ async def test_basic_openai_responses_api(sync_mode): litellm._turn_on_debug() if sync_mode: - response = litellm.responses(model="gpt-4o", input="Basic ping") + response = litellm.responses( + model="gpt-4o", input="Basic ping", max_output_tokens=20 + ) else: - response = await litellm.aresponses(model="gpt-4o", input="Basic ping") + response = await litellm.aresponses( + model="gpt-4o", input="Basic ping", max_output_tokens=20 + ) print("litellm response=", json.dumps(response, indent=4, default=str))