Merge pull request #42385 from BerriAI/litellm_fix_responses_stream_cost_breakdown

fix(logging): price terminal Responses stream events from their inner response
This commit is contained in:
kerry-berri 2026-09-21 18:47:13 -07:00 • committed by GitHub
commit 3bbbf7f693
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 3 deletions

View file

@ -1757,13 +1757,21 @@ class Logging(LiteLLMLoggingBaseClass):
if transformed_result is not None:
result = transformed_result
result_hidden_params: Final = getattr(result, "_hidden_params", None) or MappingProxyType({})
priced_result: Final = (
result.response
if isinstance(result, (ResponseCompletedEvent, ResponseIncompleteEvent, ResponseFailedEvent))
else result
)
result_hidden_params: Final = getattr(priced_result, "_hidden_params", None) or MappingProxyType({})
result_additional_headers: Final = (
result_hidden_params.get("additional_headers")
if isinstance(result_hidden_params, dict)
else getattr(result_hidden_params, "additional_headers", None)
)
if isinstance(result, (BaseModel, HttpxBinaryResponseContent)) and hasattr(result, "_hidden_params"):
if isinstance(priced_result, (BaseModel, HttpxBinaryResponseContent)) and hasattr(
priced_result, "_hidden_params"
):
hidden_params: Final = result_hidden_params
if (
"response_cost" in hidden_params and hidden_params["response_cost"] is not None
@ -1799,7 +1807,7 @@ class Logging(LiteLLMLoggingBaseClass):
try:
response_cost_calculator_kwargs: Final = {
"response_object": result,
"response_object": priced_result,
"model": litellm_model_name or self.model,
"cache_hit": cache_hit,
"custom_llm_provider": self.model_call_details.get("custom_llm_provider", None),

View file

@ -76,6 +76,9 @@ def test_fal_h3_video_create_uses_canonical_body_and_status_path(gateway: Gatewa
request_id: Final = "fal-h3-req-" + uuid.uuid4().hex
def respond(request: Request) -> Reply:
if request.target == f"/files/{request_id}.mp4":
assert request.method == "GET"
return Reply(body=_MP4, content_type="video/mp4")
assert request.headers["authorization"] == "Key synthetic-fal-key"
if request.method == "POST":
assert request.target == f"/{_H3_MODEL}"

View file

@ -5,6 +5,7 @@ general_settings:
store_model_in_db: true
disable_spend_logs: false
proxy_batch_write_at: 1
allow_unmanaged_response_ids: true
litellm_settings:
enable_redis_auth_cache: true
cache: true

View file

@ -7467,3 +7467,24 @@ def test_get_assembled_streaming_response_without_usage_cost_leaves_pricing_to_t
assert "additional_headers" not in assembled._hidden_params
price_map_cost = logging_obj._response_cost_calculator(result=assembled)
assert price_map_cost is not None and 0 < price_map_cost != 0.0042
def test_response_cost_calculator_prices_terminal_responses_event_from_its_response():
logging_obj: Final = _responses_stream_logging_obj()
inner_response: Final = ResponsesAPIResponse(
id="resp-priced",
created_at=1,
object="response",
status="completed",
model="gpt-4o-mini",
output=[],
usage=ResponseAPIUsage(input_tokens=1840, output_tokens=412, total_tokens=2252),
)
event: Final = ResponseCompletedEvent(type="response.completed", response=inner_response)
event_cost: Final = logging_obj._response_cost_calculator(result=event)
inner_cost: Final = logging_obj._response_cost_calculator(result=inner_response)
assert event_cost is not None and event_cost > 0
assert event_cost == inner_cost
assert logging_obj.cost_breakdown["input_cost"] is not None and logging_obj.cost_breakdown["input_cost"] > 0