fix: model-level guardrails not taking effect (#18363) (#18895)

* fix: model-level guardrails not taking effect (#18363)

* fix(proxy): add support event-based deployment hooks

* fix(proxy): add type safety check for guardrails
This commit is contained in:
Harshit Jain 2026-01-16 03:37:20 +05:30 • committed by GitHub
parent ae7b70b917
commit 1c1b6faa82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 5 deletions

View file

@ -49,7 +49,9 @@ if TYPE_CHECKING:
ProxyConfig = _ProxyConfig
else:
ProxyConfig = Any
from litellm.proxy.litellm_pre_call_utils import add_litellm_data_to_request
from litellm.proxy.litellm_pre_call_utils import (
add_litellm_data_to_request,
)
from litellm.types.utils import ModelResponse, ModelResponseStream, Usage

View file

@ -846,7 +846,9 @@ async def add_litellm_data_to_request( # noqa: PLR0915
# Add headers to metadata for guardrails to access (fixes #17477)
# Guardrails use metadata["headers"] to access request headers (e.g., User-Agent)
if _metadata_variable_name in data and isinstance(data[_metadata_variable_name], dict):
if _metadata_variable_name in data and isinstance(
data[_metadata_variable_name], dict
):
data[_metadata_variable_name]["headers"] = _headers
# check for forwardable headers
@ -1307,6 +1309,9 @@ def move_guardrails_to_metadata(
- If guardrails set on API Key metadata then sets guardrails on request metadata
- If guardrails not set on API key, then checks request metadata
Note: We copy (not pop) guardrails from data to metadata to ensure deployment-level
guardrails merged by the router remain in kwargs for async_pre_call_deployment_hook.
"""
# Check key-level guardrails
_add_guardrails_from_key_or_team_metadata(
@ -1319,15 +1324,25 @@ def move_guardrails_to_metadata(
#########################################################################################
# User's might send "guardrails" in the request body, we need to add them to the request metadata.
# Since downstream logic requires "guardrails" to be in the request metadata
#
# IMPORTANT: We copy instead of pop to preserve guardrails in kwargs for
# async_pre_call_deployment_hook (custom_guardrail.py:290) which checks kwargs.get("guardrails").
# This is the event-based approach for deployment-level guardrails.
#########################################################################################
if "guardrails" in data:
request_body_guardrails = data.pop("guardrails")
request_body_guardrails = data.get("guardrails")
if request_body_guardrails is None:
return
if "guardrails" in data[_metadata_variable_name] and isinstance(
data[_metadata_variable_name]["guardrails"], list
):
data[_metadata_variable_name]["guardrails"].extend(request_body_guardrails)
# Merge unique guardrails
existing = data[_metadata_variable_name]["guardrails"]
for g in request_body_guardrails:
if g not in existing:
existing.append(g)
else:
data[_metadata_variable_name]["guardrails"] = request_body_guardrails
data[_metadata_variable_name]["guardrails"] = list(request_body_guardrails)
#########################################################################################
if "guardrail_config" in data: