mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix(proxy): warn at submit when a body-selected post_call policy is deferred
This commit is contained in:
parent
c4bd3763e8
commit
c5e93aff13
2 changed files with 46 additions and 2 deletions
|
|
@ -622,6 +622,15 @@ def _defer_post_call_pipelines(
|
|||
response.id,
|
||||
", ".join(tag_matched),
|
||||
)
|
||||
body_selected: Final = _body_selected_deferrals(data, deferred)
|
||||
if body_selected:
|
||||
verbose_proxy_logger.warning(
|
||||
"Policy engine: background response %s matched post_call policies through the request body's policies "
|
||||
"list at submit; retrieval carries no request body, so those policies do not govern the completed "
|
||||
"response: %s",
|
||||
response.id,
|
||||
", ".join(body_selected),
|
||||
)
|
||||
_withdraw_deferred_claims(data, deferred)
|
||||
|
||||
|
||||
|
|
@ -638,6 +647,14 @@ def _tag_matched_deferrals(
|
|||
)
|
||||
|
||||
|
||||
def _body_selected_deferrals(
|
||||
data: Mapping[str, object], deferred: Sequence[tuple[str, "GuardrailPipeline"]]
|
||||
) -> tuple[str, ...]:
|
||||
sources: Final = _policy_state_metadata(data).get("policy_sources")
|
||||
attributed: Final = frozenset(sources) if isinstance(sources, dict) else frozenset()
|
||||
return tuple(policy_name for policy_name, _pipeline in deferred if policy_name not in attributed)
|
||||
|
||||
|
||||
def _pipeline_is_streamable(policy_name: str, pipeline: "GuardrailPipeline") -> bool:
|
||||
unsupported: Final = tuple(
|
||||
dict.fromkeys(
|
||||
|
|
|
|||
|
|
@ -941,6 +941,7 @@ def _post_call_pipeline_data(
|
|||
"metadata": {
|
||||
"_guardrail_pipelines": [("response-governance", pipeline)],
|
||||
"_pipeline_managed_guardrails": {guardrail},
|
||||
"policy_sources": {"response-governance": "model:m"},
|
||||
},
|
||||
**extra,
|
||||
}
|
||||
|
|
@ -1468,7 +1469,7 @@ def _output_passing_callbacks() -> list[CustomGuardrail]:
|
|||
|
||||
|
||||
def _claimed_post_call_pipeline_data(
|
||||
*policy_names: str, extra_guardrails: dict[str, list[str]] | None = None, policy_source: str = "model:m"
|
||||
*policy_names: str, extra_guardrails: dict[str, list[str]] | None = None, policy_source: str | None = "model:m"
|
||||
):
|
||||
from litellm.proxy.policy_engine.policy_registry import get_policy_registry
|
||||
|
||||
|
|
@ -1491,7 +1492,7 @@ def _claimed_post_call_pipeline_data(
|
|||
"_pipeline_managed_guardrails": {"gr-post"},
|
||||
"applied_policies": list(policy_names),
|
||||
"applied_guardrails": ["gr-post", *(g for gs in (extra_guardrails or {}).values() for g in gs)],
|
||||
"policy_sources": {policy_name: policy_source for policy_name in policy_names},
|
||||
"policy_sources": {policy_name: policy_source for policy_name in policy_names if policy_source is not None},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1551,6 +1552,32 @@ async def test_pending_background_response_warns_when_the_deferred_policy_was_ma
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pending_background_response_warns_when_the_deferred_policy_came_from_the_request_body(
|
||||
proxy_logging: ProxyLogging,
|
||||
make_user_api_key_auth: Callable[..., UserAPIKeyAuth],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
clear_policy_registry: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
monkeypatch.setattr(litellm, "callbacks", _output_blocking_callbacks({}))
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", None, raising=False)
|
||||
data = _claimed_post_call_pipeline_data("body-governance", policy_source=None)
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM Proxy"):
|
||||
out = await proxy_logging.post_call_success_hook(
|
||||
data=data, response=_background_response("queued"), user_api_key_dict=make_user_api_key_auth()
|
||||
)
|
||||
|
||||
assert out.status == "queued"
|
||||
assert "policy_sources" not in data["metadata"]
|
||||
assert _warnings(caplog) == [
|
||||
"Policy engine: background response resp_bg matched post_call policies through the request body's policies "
|
||||
"list at submit; retrieval carries no request body, so those policies do not govern the completed "
|
||||
"response: body-governance"
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pending_background_response_matched_through_its_model_does_not_warn(
|
||||
proxy_logging: ProxyLogging,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue