mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(proxy): persist guardrail info in spend logs for /v1/responses
Pre-call guardrail blocks on /v1/responses wrote guardrail_information as null in LiteLLM_SpendLogs because _handle_logging_proxy_only_error splits request_data by LoggedLiteLLMParams keys and litellm_metadata, where the Responses API stores request metadata including standard_logging_guardrail_information, was not among them. It fell into optional_params, so merge_litellm_metadata never saw it. Add litellm_metadata to LoggedLiteLLMParams so it routes into litellm_params the same way metadata does on the chat completions path Fixes #28971.
This commit is contained in:
parent
e15b37a18e
commit
d5aad8ced8
2 changed files with 58 additions and 0 deletions
|
|
@ -2486,6 +2486,7 @@ class LoggedLiteLLMParams(TypedDict, total=False):
|
|||
litellm_call_id: Optional[str]
|
||||
model_alias_map: Optional[dict]
|
||||
metadata: Optional[dict]
|
||||
litellm_metadata: Optional[dict]
|
||||
model_info: Optional[dict]
|
||||
proxy_server_request: Optional[dict]
|
||||
acompletion: Optional[bool]
|
||||
|
|
|
|||
|
|
@ -118,6 +118,63 @@ async def test_proxy_only_error_log_marks_no_upstream_llm_call():
|
|||
assert captured.get("flag") is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_proxy_only_error_log_keeps_litellm_metadata_in_litellm_params():
|
||||
"""Responses API requests carry guardrail info under ``litellm_metadata``
|
||||
(not ``metadata``). It must land in litellm_params so
|
||||
``merge_litellm_metadata`` can surface ``guardrail_information`` in the
|
||||
spend-log failure row, matching the chat completions path."""
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=DualCache())
|
||||
captured = {}
|
||||
guardrail_info = [{"guardrail_name": "test-guard", "guardrail_status": "blocked"}]
|
||||
|
||||
def fake_update_environment_variables(self, *args, **kwargs):
|
||||
captured["litellm_params"] = kwargs.get("litellm_params")
|
||||
captured["optional_params"] = kwargs.get("optional_params")
|
||||
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging
|
||||
|
||||
orig_update_env = Logging.update_environment_variables
|
||||
orig_pre_call = Logging.pre_call
|
||||
orig_async_failure = Logging.async_failure_handler
|
||||
|
||||
async def _noop_async_failure(self, *args, **kwargs):
|
||||
return None
|
||||
|
||||
Logging.update_environment_variables = fake_update_environment_variables
|
||||
Logging.pre_call = lambda self, *args, **kwargs: None
|
||||
Logging.async_failure_handler = _noop_async_failure
|
||||
try:
|
||||
await proxy_logging_obj._handle_logging_proxy_only_error(
|
||||
request_data={
|
||||
"model": "gpt-4o",
|
||||
"input": "blocked prompt",
|
||||
"litellm_metadata": {
|
||||
"standard_logging_guardrail_information": guardrail_info
|
||||
},
|
||||
},
|
||||
user_api_key_dict=UserAPIKeyAuth(
|
||||
api_key="sk-1234", request_route="/v1/responses"
|
||||
),
|
||||
route="/v1/responses",
|
||||
original_exception=HTTPException(status_code=400, detail="blocked"),
|
||||
)
|
||||
finally:
|
||||
Logging.update_environment_variables = orig_update_env
|
||||
Logging.pre_call = orig_pre_call
|
||||
Logging.async_failure_handler = orig_async_failure
|
||||
|
||||
assert (
|
||||
captured["litellm_params"]["litellm_metadata"][
|
||||
"standard_logging_guardrail_information"
|
||||
]
|
||||
== guardrail_info
|
||||
)
|
||||
assert "litellm_metadata" not in captured["optional_params"]
|
||||
|
||||
|
||||
def test_get_model_group_info_order():
|
||||
from litellm import Router
|
||||
from litellm.proxy.proxy_server import _get_model_group_info
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue