mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix: merge HiddenParams into logging metadata; lazy-import response_metadata to avoid cycles
Made-with: Cursor
This commit is contained in:
parent
ec736e5975
commit
76cb94157e
4 changed files with 86 additions and 20 deletions
|
|
@ -60,9 +60,6 @@ from litellm.integrations.deepeval.deepeval import DeepEvalLogger
|
|||
from litellm.integrations.mlflow import MlflowLogger
|
||||
from litellm.integrations.sqs import SQSLogger
|
||||
from litellm.litellm_core_utils.core_helpers import reconstruct_model_name
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
get_response_hidden_params,
|
||||
)
|
||||
from litellm.litellm_core_utils.get_litellm_params import get_litellm_params
|
||||
from litellm.litellm_core_utils.llm_cost_calc.tool_call_cost_tracking import (
|
||||
StandardBuiltInToolCostTracking,
|
||||
|
|
@ -1705,7 +1702,17 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
"""
|
||||
if logging_result is None:
|
||||
return
|
||||
incoming = get_response_hidden_params(logging_result)
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
get_response_hidden_params,
|
||||
hidden_params_to_plain_dict,
|
||||
)
|
||||
|
||||
incoming_raw = get_response_hidden_params(logging_result)
|
||||
incoming = hidden_params_to_plain_dict(incoming_raw)
|
||||
if not incoming:
|
||||
return
|
||||
# Do not let explicit None values from model_dump wipe proxy-injected timing keys.
|
||||
incoming = {k: v for k, v in incoming.items() if v is not None}
|
||||
if not incoming:
|
||||
return
|
||||
if self.model_call_details.get("litellm_params") is None:
|
||||
|
|
@ -1719,9 +1726,6 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
existing = md.get("hidden_params")
|
||||
if not isinstance(existing, dict):
|
||||
existing = {}
|
||||
if not isinstance(incoming, dict):
|
||||
md["hidden_params"] = existing or incoming
|
||||
return
|
||||
md["hidden_params"] = {**existing, **incoming}
|
||||
|
||||
def _process_hidden_params_and_response_cost(
|
||||
|
|
@ -1730,18 +1734,20 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
start_time,
|
||||
end_time,
|
||||
):
|
||||
hidden_params = get_response_hidden_params(logging_result)
|
||||
if hidden_params:
|
||||
if self.model_call_details.get("litellm_params") is not None:
|
||||
self.model_call_details["litellm_params"].setdefault("metadata", {})
|
||||
if self.model_call_details["litellm_params"]["metadata"] is None:
|
||||
self.model_call_details["litellm_params"]["metadata"] = {}
|
||||
self.model_call_details["litellm_params"]["metadata"]["hidden_params"] = get_response_hidden_params(logging_result) # type: ignore
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
get_response_hidden_params,
|
||||
hidden_params_to_plain_dict,
|
||||
)
|
||||
|
||||
hp_raw = get_response_hidden_params(logging_result)
|
||||
if hp_raw:
|
||||
self._merge_hidden_params_from_response_into_metadata(logging_result)
|
||||
hp_dict = hidden_params_to_plain_dict(hp_raw) if hp_raw else {}
|
||||
|
||||
if self.model_call_details.get("cache_hit") is True:
|
||||
self.model_call_details["response_cost"] = 0.0
|
||||
elif "response_cost" in hidden_params:
|
||||
self.model_call_details["response_cost"] = hidden_params["response_cost"]
|
||||
elif "response_cost" in hp_dict:
|
||||
self.model_call_details["response_cost"] = hp_dict["response_cost"]
|
||||
elif self.model_call_details.get("response_cost") is not None:
|
||||
# Preserve response_cost if already calculated (e.g., by pass-through
|
||||
# handlers like Gemini/Vertex which call completion_cost directly)
|
||||
|
|
@ -5316,6 +5322,10 @@ def _extract_response_obj_and_hidden_params(
|
|||
hidden_params = getattr(init_response_obj, "_hidden_params", None)
|
||||
elif isinstance(init_response_obj, dict):
|
||||
response_obj = init_response_obj
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
get_response_hidden_params,
|
||||
)
|
||||
|
||||
hp = get_response_hidden_params(init_response_obj)
|
||||
if hp:
|
||||
hidden_params = (
|
||||
|
|
|
|||
|
|
@ -33,6 +33,20 @@ def get_response_hidden_params(response: Any) -> Union[HiddenParams, dict]:
|
|||
return {}
|
||||
|
||||
|
||||
def hidden_params_to_plain_dict(hp: Any) -> dict:
|
||||
"""
|
||||
Normalize ``get_response_hidden_params`` output (``dict`` or ``HiddenParams``) to a
|
||||
plain ``dict`` for merging into ``metadata['hidden_params']``.
|
||||
"""
|
||||
if not hp:
|
||||
return {}
|
||||
if isinstance(hp, dict):
|
||||
return dict(hp)
|
||||
if hasattr(hp, "model_dump"):
|
||||
return hp.model_dump(exclude_none=True)
|
||||
return {}
|
||||
|
||||
|
||||
def strip_litellm_internal_keys_from_dict_response(response: Any) -> None:
|
||||
"""Remove internal keys from dict API responses before JSON serialization."""
|
||||
if isinstance(response, dict):
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLogging
|
|||
from litellm.litellm_core_utils.llm_response_utils.get_headers import (
|
||||
get_response_headers,
|
||||
)
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
merge_hidden_params_with_logging_timings,
|
||||
strip_litellm_internal_keys_from_dict_response,
|
||||
)
|
||||
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
|
||||
from litellm.proxy._types import ProxyException, UserAPIKeyAuth
|
||||
from litellm.proxy.auth.auth_utils import check_response_size_is_safe
|
||||
|
|
@ -1042,6 +1038,10 @@ class ProxyBaseLLMRequestProcessing:
|
|||
|
||||
_exception_raised = False
|
||||
try:
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
merge_hidden_params_with_logging_timings,
|
||||
)
|
||||
|
||||
# Async generators (e.g. Anthropic /v1/messages SSE) have no _hidden_params;
|
||||
# merge timing from logging_obj.model_call_details (llm_api_duration_ms, etc.).
|
||||
hidden_params = merge_hidden_params_with_logging_timings(
|
||||
|
|
@ -1287,6 +1287,11 @@ class ProxyBaseLLMRequestProcessing:
|
|||
log_context=f"litellm_call_id={logging_obj.litellm_call_id}",
|
||||
)
|
||||
|
||||
from litellm.litellm_core_utils.llm_response_utils.response_metadata import (
|
||||
merge_hidden_params_with_logging_timings,
|
||||
strip_litellm_internal_keys_from_dict_response,
|
||||
)
|
||||
|
||||
# Re-merge after post_call_success_hook so dict / CSW hidden_params + logging timings align.
|
||||
hidden_params = merge_hidden_params_with_logging_timings(
|
||||
response,
|
||||
|
|
|
|||
|
|
@ -2333,6 +2333,43 @@ def test_merge_hidden_params_from_response_preserves_proxy_injected_timing():
|
|||
assert hp["model_id"] == "mid-2"
|
||||
|
||||
|
||||
def test_merge_hidden_params_from_response_preserves_proxy_injected_timing_with_hidden_params_model():
|
||||
"""Assembled streaming response may use HiddenParams object; merge must not drop fields."""
|
||||
from litellm.types.llms.base import HiddenParams
|
||||
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
|
||||
logging_obj = LiteLLMLoggingObj(
|
||||
model="claude-3-5-sonnet",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
stream=True,
|
||||
call_type="anthropic_messages",
|
||||
start_time=time.time(),
|
||||
litellm_call_id="merge-hp-hp-model",
|
||||
function_id="merge-hp-hp-model-fn",
|
||||
)
|
||||
logging_obj.model_call_details = {
|
||||
"litellm_params": {
|
||||
"metadata": {
|
||||
"hidden_params": {
|
||||
"litellm_overhead_time_ms": 273.329,
|
||||
"_response_ms": 1590.0,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
class _Assembled:
|
||||
_hidden_params = HiddenParams(response_cost=0.001, model_id="mid-2")
|
||||
|
||||
logging_obj._merge_hidden_params_from_response_into_metadata(_Assembled())
|
||||
hp = logging_obj.model_call_details["litellm_params"]["metadata"]["hidden_params"]
|
||||
assert hp["litellm_overhead_time_ms"] == 273.329
|
||||
assert hp["_response_ms"] == 1590.0
|
||||
assert hp["response_cost"] == 0.001
|
||||
assert hp["model_id"] == "mid-2"
|
||||
|
||||
|
||||
def test_get_standard_logging_payload_includes_metadata_hidden_params_overhead():
|
||||
"""Spend logs read overhead from standard_logging_object.hidden_params; merge metadata.hidden_params."""
|
||||
from datetime import datetime
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue