fix(guardrails): read the requested guardrails from both metadata buckets when naming a deployment-level run
Some checks failed
Cost map pins recheck / rerun-cost-map-guard (push) Has been cancelled
LiteLLM Rust DB / db-queries (push) Has been cancelled
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled

This commit is contained in:
yucheng 2026-10-30 01:18:26 -07:00
parent b1eabac7b4
commit cf863890e5
2 changed files with 22 additions and 2 deletions

View file

@ -923,8 +923,7 @@ class CustomGuardrail(CustomLogger):
policy_state[PRE_CALL_EXECUTED_GUARDRAILS_KEY] = [marker]
elif marker not in recorded:
cast("list[object]", recorded).append(marker) # cast-ok: markers are only compared as strings
requested: Final = next((bucket.get("guardrails") for bucket in buckets if "guardrails" in bucket), None)
if name not in _str_collection(requested):
if not any(name in _str_collection(bucket.get("guardrails")) for bucket in buckets):
return
named_lists: Final = tuple(
cast("list[object]", bucket["applied_guardrails"]) # cast-ok: entries are only compared with names

View file

@ -1846,6 +1846,27 @@ async def test_deployment_hook_names_a_pipeline_step_it_ran_before_any_guardrail
assert metadata["applied_guardrails"] == ["second"]
@pytest.mark.asyncio
async def test_deployment_hook_names_a_pipeline_step_requested_only_in_the_other_metadata_bucket() -> None:
guardrail: Final = _PipelineStepGuardrail("second", "pre_call")
kwargs: Final[dict[str, object]] = {
"model": "m",
"messages": [{"role": "user", "content": "hi"}],
"guardrails": ["second"],
"metadata": {
"guardrails": ["first"],
"applied_guardrails": ["first"],
"_pipeline_managed_guardrails": frozenset({"first", "second"}),
},
"litellm_metadata": {"guardrails": ["second"]},
}
await guardrail.async_pre_call_deployment_hook(kwargs=kwargs, call_type=CallTypes.completion)
assert guardrail.calls == 1
assert sorted(get_logging_caching_headers(kwargs)["x-litellm-applied-guardrails"].split(",")) == ["first", "second"]
@pytest.mark.asyncio
@pytest.mark.parametrize("named_bucket", ["metadata", "litellm_metadata"])
async def test_deployment_hook_names_a_pipeline_step_next_to_the_steps_already_named_when_both_buckets_exist(