mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(logging): avoid mutating streaming hidden params
Backfill calculated streaming response cost into logging payload copies so OTEL spans expose hidden_params.response_cost without mutating the response object. Made-with: Cursor
This commit is contained in:
parent
d4a989d16e
commit
73e15e0124
2 changed files with 72 additions and 22 deletions
|
|
@ -978,9 +978,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
try:
|
||||
# [Non-blocking Extra Debug Information in metadata]
|
||||
if turn_off_message_logging is True:
|
||||
_metadata[
|
||||
"raw_request"
|
||||
] = "redacted by litellm. \
|
||||
_metadata["raw_request"] = "redacted by litellm. \
|
||||
'litellm.turn_off_message_logging=True'"
|
||||
else:
|
||||
curl_command = self._get_request_curl_command(
|
||||
|
|
@ -1015,12 +1013,8 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
] = RawRequestTypedDict(
|
||||
error=str(e),
|
||||
)
|
||||
_metadata[
|
||||
"raw_request"
|
||||
] = "Unable to Log \
|
||||
raw request: {}".format(
|
||||
str(e)
|
||||
)
|
||||
_metadata["raw_request"] = "Unable to Log \
|
||||
raw request: {}".format(str(e))
|
||||
if getattr(self, "logger_fn", None) and callable(self.logger_fn):
|
||||
try:
|
||||
self.logger_fn(
|
||||
|
|
@ -1703,13 +1697,20 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
return
|
||||
if self.model_call_details.get("litellm_params") is None:
|
||||
return
|
||||
metadata_hidden_params = hidden_params.copy()
|
||||
response_cost = self.model_call_details.get("response_cost")
|
||||
if hidden_params.get("response_cost") is None and response_cost is not None:
|
||||
hidden_params["response_cost"] = response_cost
|
||||
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"] = hidden_params
|
||||
if (
|
||||
metadata_hidden_params.get("response_cost") is None
|
||||
and response_cost is not None
|
||||
):
|
||||
metadata_hidden_params["response_cost"] = response_cost
|
||||
|
||||
litellm_params = self.model_call_details["litellm_params"]
|
||||
metadata = litellm_params.setdefault("metadata", {})
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
litellm_params["metadata"] = metadata
|
||||
metadata["hidden_params"] = metadata_hidden_params
|
||||
|
||||
def _process_hidden_params_and_response_cost(
|
||||
self,
|
||||
|
|
@ -5393,11 +5394,6 @@ def get_standard_logging_object_payload(
|
|||
completion_start_time_float=completion_start_time_float,
|
||||
stream=kwargs.get("stream", False),
|
||||
)
|
||||
# clean up litellm hidden params
|
||||
clean_hidden_params = StandardLoggingPayloadSetup.get_hidden_params(
|
||||
hidden_params
|
||||
)
|
||||
|
||||
# clean up litellm metadata
|
||||
clean_metadata = StandardLoggingPayloadSetup.get_standard_logging_metadata(
|
||||
metadata=metadata,
|
||||
|
|
@ -5431,6 +5427,17 @@ def get_standard_logging_object_payload(
|
|||
## Get model cost information ##
|
||||
base_model = _get_base_model_from_metadata(model_call_details=kwargs)
|
||||
custom_pricing = use_custom_pricing_for_model(litellm_params=litellm_params)
|
||||
response_cost: float = kwargs.get("response_cost", 0) or 0.0
|
||||
|
||||
# clean up litellm hidden params
|
||||
clean_hidden_params = StandardLoggingPayloadSetup.get_hidden_params(
|
||||
hidden_params
|
||||
)
|
||||
if (
|
||||
clean_hidden_params["response_cost"] is None
|
||||
and kwargs.get("response_cost") is not None
|
||||
):
|
||||
clean_hidden_params["response_cost"] = response_cost
|
||||
|
||||
model_cost_information = StandardLoggingPayloadSetup.get_model_cost_information(
|
||||
base_model=base_model,
|
||||
|
|
@ -5439,7 +5446,6 @@ def get_standard_logging_object_payload(
|
|||
init_response_obj=init_response_obj,
|
||||
api_base=litellm_params.get("api_base"),
|
||||
)
|
||||
response_cost: float = kwargs.get("response_cost", 0) or 0.0
|
||||
|
||||
error_information = StandardLoggingPayloadSetup.get_error_information(
|
||||
original_exception=original_exception,
|
||||
|
|
|
|||
|
|
@ -2297,10 +2297,54 @@ def test_merge_hidden_params_from_response_into_metadata_backfills_response_cost
|
|||
class _Resp:
|
||||
_hidden_params = {"response_cost": None, "model_id": "mid-test"}
|
||||
|
||||
logging_obj._merge_hidden_params_from_response_into_metadata(_Resp())
|
||||
response = _Resp()
|
||||
logging_obj._merge_hidden_params_from_response_into_metadata(response)
|
||||
meta = logging_obj.model_call_details["litellm_params"]["metadata"]
|
||||
assert meta["hidden_params"]["response_cost"] == 0.002
|
||||
assert meta["hidden_params"]["model_id"] == "mid-test"
|
||||
assert response._hidden_params["response_cost"] is None
|
||||
|
||||
|
||||
def test_standard_logging_hidden_params_backfills_response_cost_without_mutating_response():
|
||||
"""Streaming standard logging payload should expose the calculated response cost."""
|
||||
from datetime import datetime
|
||||
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.types.utils import Usage
|
||||
|
||||
logging_obj = LiteLLMLoggingObj(
|
||||
model="gpt-4o-mini",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
stream=True,
|
||||
call_type="acompletion",
|
||||
start_time=time.time(),
|
||||
litellm_call_id="standard-hp-cost-test",
|
||||
function_id="standard-hp-cost-fn",
|
||||
)
|
||||
logging_obj.model_call_details = {
|
||||
"litellm_params": {"metadata": {}, "proxy_server_request": {}},
|
||||
"litellm_call_id": "standard-hp-cost-test",
|
||||
"call_type": "acompletion",
|
||||
"stream": True,
|
||||
"model": "gpt-4o-mini",
|
||||
"custom_llm_provider": "openai",
|
||||
"optional_params": {"stream": True},
|
||||
"response_cost": 0.002,
|
||||
}
|
||||
response = ModelResponse(
|
||||
id="standard-hp-cost-response",
|
||||
model="gpt-4o-mini",
|
||||
usage=Usage(prompt_tokens=10, completion_tokens=5, total_tokens=15),
|
||||
)
|
||||
response._hidden_params = {"response_cost": None, "model_id": "mid-test"}
|
||||
|
||||
payload = logging_obj._build_standard_logging_payload(
|
||||
response, datetime.now(), datetime.now()
|
||||
)
|
||||
|
||||
assert payload is not None
|
||||
assert payload["hidden_params"]["response_cost"] == 0.002
|
||||
assert response._hidden_params["response_cost"] is None
|
||||
|
||||
|
||||
def test_merge_hidden_params_from_response_into_metadata_preserves_response_cost():
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue