Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
49d655d
Merge pull request #31384 from BerriAI/litellm_internal_staging
yuneng-berri Jun 26, 2026
a311f11
Merge pull request #31477 from BerriAI/litellm_internal_staging
yuneng-berri Jun 26, 2026
0ade44f
Merge pull request #31542 from BerriAI/litellm_internal_staging
shivamrawat1 Jun 28, 2026
88e03e5
Merge pull request #31765 from BerriAI/litellm_internal_staging
yuneng-berri Jun 30, 2026
badc141
Merge pull request #32027 from BerriAI/litellm_internal_staging
yuneng-berri Jul 3, 2026
79a6b8f
Merge pull request #32156 from BerriAI/litellm_internal_staging
yuneng-berri Jul 4, 2026
54e95af
fix: set overhead duration metric for all route types
factnn Jun 17, 2026
742e0fe
fix: remove start_time from self.data to avoid snapshot test pollution
factnn Jun 18, 2026
d10ec50
test: verify overhead computed for routes without pre-existing value
factnn Jun 18, 2026
9f03795
fix: guard against None logging_obj to prevent AttributeError
factnn Jun 18, 2026
78aa0b2
fix: use logging_obj.start_time for overhead calculation
factnn Jun 21, 2026
df130fe
fix: avoid shadowing logging_obj in overhead duration code path
factnn Jun 21, 2026
e40bda5
fix: use timezone-aware datetime.now for
factnn Jun 23, 2026
92bbd51
fix: revert timezone-aware datetime, restore test file
factnn Jun 23, 2026
084432f
test: add guard condition test for overhead not overwritten
factnn Jun 24, 2026
b69a4a4
fix: skip overhead metric for chat completions route types
factnn Jul 2, 2026
78a8c2d
chore: ruff format
factnn Jul 2, 2026
321e981
fix: set overhead directly instead of calling update_response_metadata
factnn Jul 2, 2026
faf9133
fix: write overhead to dict-typed responses via key assignment
factnn Jul 4, 2026
75b049d
chore: re-trigger CI
factnn Jul 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions litellm/proxy/common_request_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,30 @@ async def base_process_llm_request(

response = responses[1]

# GH#30566: set overhead duration for non-chat-completions
# routes (/v1/messages, /v1/responses). Chat completions
# already have litellm_overhead_time_ms from the SDK.
# Only set the overhead field directly (don't call
# update_response_metadata which also touches cost).
_overhead_hidden_params = getattr(response, "_hidden_params", {}) or {}
if not _overhead_hidden_params.get("litellm_overhead_time_ms") and route_type not in (
"acompletion",
"completion",
):
end_time = datetime.now()
_logging_obj = self.data.get("litellm_logging_obj")
if _logging_obj is not None and _logging_obj.start_time is not None:
overhead_ms = (end_time - _logging_obj.start_time).total_seconds() * 1000 - (
_logging_obj.model_call_details.get("llm_api_duration_ms", 0)
)
Comment thread
factnn marked this conversation as resolved.
if not isinstance(_overhead_hidden_params, dict):
_overhead_hidden_params = {}
_overhead_hidden_params["litellm_overhead_time_ms"] = overhead_ms
if hasattr(response, "_hidden_params"):
response._hidden_params = _overhead_hidden_params
Comment thread
factnn marked this conversation as resolved.
elif isinstance(response, dict):
response["_hidden_params"] = _overhead_hidden_params

_exception_raised = False
try:
hidden_params = getattr(response, "_hidden_params", {}) or {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import datetime
from unittest.mock import MagicMock

import pytest

import litellm.litellm_core_utils.llm_response_utils.response_metadata as response_metadata_mod
import litellm.proxy.common_request_processing as common_request_processing_mod
from litellm.litellm_core_utils.litellm_logging import Logging
Expand Down Expand Up @@ -91,6 +93,50 @@ def test_update_response_metadata_includes_callback_duration(self):
# overhead should also be set
assert hidden.get("litellm_overhead_time_ms") is not None

def test_overhead_computed_for_routes_without_pre_existing_value(self):
"""GH#30566: overhead is set even when _hidden_params
does not already contain litellm_overhead_time_ms.
This simulates non-chat-completions routes that skip
the SDK-level update_response_metadata call."""
result = ModelResponse()
logging_obj = self._make_logging_obj(llm_api_duration_ms=900.0)
logging_obj._response_cost_calculator = MagicMock(return_value=0.001)
logging_obj.litellm_call_id = "test-gh30566"

start = datetime.datetime(2025, 1, 1, 0, 0, 0)
end = datetime.datetime(2025, 1, 1, 0, 0, 1)

update_response_metadata(
result=result,
logging_obj=logging_obj,
model="gpt-4",
kwargs={},
start_time=start,
end_time=end,
)

hidden = result._hidden_params
assert hidden.get("litellm_overhead_time_ms") == pytest.approx(100.0, rel=0.01)
assert hidden.get("_response_ms") == pytest.approx(1000.0, rel=0.01)

def test_overhead_guard_skips_when_already_present(self):
"""GH#30566: the guard in base_process_llm_request prevents
calling update_response_metadata when litellm_overhead_time_ms
is already set by the SDK layer (e.g. /v1/chat/completions).
This test verifies the guard condition directly."""
# Chat-completions path: overhead already populated
result = ModelResponse()
result._hidden_params = {"litellm_overhead_time_ms": 50.0}
hidden_params = getattr(result, "_hidden_params", {}) or {}
should_skip = bool(hidden_params.get("litellm_overhead_time_ms"))
assert should_skip is True

# Non-chat path (/v1/messages, /v1/responses): no overhead yet
result2 = ModelResponse()
hidden_params2 = getattr(result2, "_hidden_params", {}) or {}
should_skip2 = bool(hidden_params2.get("litellm_overhead_time_ms"))
assert should_skip2 is False


class TestCallbackDurationInCustomHeaders:
"""Test that callback_duration_ms flows into get_custom_headers."""
Expand Down
Loading