mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(guardrails): scan every chunk when rerouting a streaming guardrail off its OpenAI-only hook
Sampling forwarded unscanned Anthropic deltas before the first scan, so short streams still leaked blocked content. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
8baaf6e71b
commit
2c4690b3c1
3 changed files with 9 additions and 7 deletions
|
|
@ -8,7 +8,7 @@ Unified Guardrail, leveraging LiteLLM's /applyGuardrail endpoint
|
|||
|
||||
import copy
|
||||
import json
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, List, Union
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, List, Mapping, Optional, Union
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
|
|
@ -804,6 +804,7 @@ class UnifiedLLMGuardrails(CustomLogger):
|
|||
user_api_key_dict: UserAPIKeyAuth,
|
||||
response: Any,
|
||||
request_data: dict,
|
||||
streaming_flag_defaults: Optional[Mapping[str, Any]] = None,
|
||||
) -> AsyncGenerator[Any, None]:
|
||||
"""
|
||||
Passes the entire stream to the guardrail
|
||||
|
|
@ -827,10 +828,10 @@ class UnifiedLLMGuardrails(CustomLogger):
|
|||
guardrail_to_apply: CustomGuardrail = request_data.pop("guardrail_to_apply", None)
|
||||
|
||||
# Get streaming configuration. Resolution order (later wins): default
|
||||
# < guardrail attribute < guardrail_config dict < this callback's
|
||||
# optional_params.
|
||||
# < caller-supplied default < guardrail attribute < guardrail_config
|
||||
# dict < this callback's optional_params.
|
||||
def _streaming_flag(name: str, default: Any) -> Any:
|
||||
value = default
|
||||
value = default if streaming_flag_defaults is None else streaming_flag_defaults.get(name, default)
|
||||
if guardrail_to_apply is not None:
|
||||
value = getattr(guardrail_to_apply, name, value)
|
||||
config = getattr(guardrail_to_apply, "guardrail_config", {})
|
||||
|
|
|
|||
|
|
@ -2705,6 +2705,10 @@ class ProxyLogging:
|
|||
user_api_key_dict=user_api_key_dict,
|
||||
request_data=request_data,
|
||||
response=current_response,
|
||||
# A guardrail that ships its own iterator hook scans
|
||||
# every chunk there, so keep that cadence when we
|
||||
# reroute it: sampling would forward unscanned content.
|
||||
streaming_flag_defaults=({"streaming_sampling_rate": 1} if effective_kind != kind else None),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -485,9 +485,6 @@ def _content_filter_guardrail():
|
|||
blocked_words=[{"keyword": "zebra", "action": "BLOCK"}],
|
||||
default_on=True,
|
||||
)
|
||||
# scan every chunk so the block decision lands before the offending delta
|
||||
# is forwarded, matching the /chat/completions withholding behavior
|
||||
guardrail.streaming_sampling_rate = 1
|
||||
return guardrail
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue