mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-14 04:09:09 +00:00
* fix(logging): redact nested callback input and provider response fields * fix(logging): keep shared request body for per-callback redaction and drop hidden provider fields The deprecated per-callback message_logging=False path ran perform_redaction on the shared model_call_details, which now also redacted the nested proxy_server_request body. The spend log Request column and previous_response_id replay read that body, so one opted-out callback blanked them for everyone. That path now keeps the shared body and hidden params, and redact_streaming_responses_for_custom_logger hands the opted-out callback its own redacted litellm_params. Redacted litellm_params also clear provider_specific_fields copied into metadata.hidden_params (Anthropic thinking text), in litellm_params and in the nested request body, and the nested body redacts system and instructions. * fix(logging): keep replayed instructions and router usage marker under redaction The shared request body keeps system and instructions again, so spend logs store them and previous_response_id follow-ups replay the real instructions. Per-callback copies still redact them. Provider-specific fields in metadata.hidden_params are cleared in place, so the metadata dict keeps its identity and the router's counted-usage marker stays visible to deployment_callback_on_success (no double tpm/rpm count). * fix(logging): never copy shared metadata dicts during redaction The shared redaction pass now leaves litellm_params metadata dicts as they are, so a hidden_params write from the other success handler between the in-place clear and the copy can no longer move the router usage marker to a stale dict. The key-presence predicate change is reverted as unneeded. * refactor(logging): redact nested request body and provider fields with the existing message rules Run perform_redaction on a copy of proxy_server_request.body, the same call the spend log already makes, and redact reasoning inside provider_specific_fields the way the message's own reasoning_content and thinking_blocks are redacted, instead of clearing every provider field. Opaque fields such as Gemini thought_signatures stay, and the metadata dicts and streaming objects are handled as on main. --------- Co-authored-by: moyai-devin-berriai[bot] <336287033+moyai-devin-berriai[bot]@users.noreply.github.com> Co-authored-by: yucheng-berri <293926326+yucheng-berri@users.noreply.github.com>
47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
import json
|
|
import os
|
|
from collections.abc import Mapping
|
|
from datetime import datetime
|
|
from typing import Final
|
|
|
|
import httpx
|
|
from pydantic import BaseModel
|
|
|
|
from litellm.integrations.custom_logger import CustomLogger
|
|
|
|
|
|
def _payload(kwargs: Mapping[str, object], response_obj: object) -> str:
|
|
params: Final = kwargs.get("litellm_params")
|
|
request: Final = params.get("proxy_server_request") if isinstance(params, Mapping) else None
|
|
standard: Final = kwargs.get("standard_logging_object")
|
|
return json.dumps(
|
|
{
|
|
"request": request,
|
|
"response": response_obj.model_dump() if isinstance(response_obj, BaseModel) else response_obj,
|
|
"standard_response": standard.get("response") if isinstance(standard, Mapping) else None,
|
|
},
|
|
default=str,
|
|
)
|
|
|
|
|
|
class SyncRedactionProbe(CustomLogger):
|
|
def log_success_event(
|
|
self, kwargs: Mapping[str, object], response_obj: object, start_time: datetime, end_time: datetime
|
|
) -> None:
|
|
with httpx.Client(trust_env=False) as client:
|
|
response: Final = client.post(os.environ["REDACTION_PROBE_URL"], content=_payload(kwargs, response_obj))
|
|
response.raise_for_status()
|
|
|
|
|
|
class RedactionProbe(CustomLogger):
|
|
async def async_log_success_event(
|
|
self, kwargs: Mapping[str, object], response_obj: object, start_time: datetime, end_time: datetime
|
|
) -> None:
|
|
async with httpx.AsyncClient(trust_env=False) as client:
|
|
response: Final = await client.post(
|
|
os.environ["REDACTION_PROBE_URL"], content=_payload(kwargs, response_obj)
|
|
)
|
|
response.raise_for_status()
|
|
|
|
|
|
probe: Final = RedactionProbe()
|