feat(guardrails): expose streaming knobs on generic_guardrail_api - #30924
feat(guardrails): expose streaming knobs on generic_guardrail_api#30924schneidermr wants to merge 8 commits into
Conversation
Wire streaming_end_of_stream_only and streaming_sampling_rate through optional params, initialize_guardrail, and get_config_model so the generic guardrail API participates in UnifiedLLMGuardrails streaming checks with configurable cadence and end-of-stream-only mode.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR adds first-class streaming configuration to
Confidence Score: 5/5Safe to merge — the change is additive, all new fields are opt-in with backwards-compatible defaults, and no existing behaviour is altered. The two new streaming knobs are wired cleanly through every layer (Pydantic model → constructor → initialize_guardrail), the None-sentinel pattern correctly prevents unset optional_params from shadowing top-level config, and the new tests verify every integration point with mocks only. No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/init.py | Adds _get_config_value helper for priority resolution between top-level litellm_params and nested optional_params, and wires the two new streaming knobs into initialize_guardrail |
| litellm/proxy/guardrails/guardrail_hooks/generic_guardrail_api/generic_guardrail_api.py | Adds streaming_end_of_stream_only and streaming_sampling_rate constructor params with correct None-sentinel defaults; validates sampling rate >= 1; exposes get_config_model() static method |
| litellm/types/proxy/guardrails/guardrail_hooks/generic_guardrail_api.py | Adds streaming_end_of_stream_only and streaming_sampling_rate fields to GenericGuardrailAPIOptionalParams with default=None (correct sentinel pattern) and Pydantic ge=1 constraint on the rate field |
| tests/test_litellm/proxy/guardrails/guardrail_hooks/test_generic_guardrail_api.py | Adds 718 lines of new mock-only tests covering streaming defaults, overrides, cadence sampling, mid-stream BLOCKED, fail-open, config model exposure, initialize_guardrail plumbing for both dict and model optional_params, and /v1/responses streaming |
Reviews (3): Last reviewed commit: "fix(guardrails): read nested streaming c..." | Re-trigger Greptile
Avoids a new UP006 violation that tripped the ruff strict-rule budget gate on the PR lint job.
Non-None Pydantic defaults on GenericGuardrailAPIOptionalParams made _get_config_value treat unset nested fields as explicit values, which shadowed top-level litellm_params streaming flags whenever any other optional_params key was present. Real defaults stay in the constructor.
Muhtasim-Munif-Fahim
left a comment
There was a problem hiding this comment.
Clean feature addition. \streaming_end_of_stream_only\ and \streaming_sampling_rate\ knobs give users meaningful control over guardrail cost/latency tradeoffs in streaming mode. The _get_config_value\ priority logic (optional_params wins over litellm_params) is correct and well-documented. Thorough test coverage across defaults, overrides, sampling cadence, and fail-open scenarios. LGTM.
Sameerlite
left a comment
There was a problem hiding this comment.
Minor nits :
Duplicated _get_config_value — Same helper exists in openai/init.py. Fine for now; could be shared later.
No /v1/responses streaming test — All integration tests use /chat/completions. Acceptable since the unified hook is route-agnostic, but a responses-streaming test would match real-world usage (e.g. your gpt-5.5 curl).
No validation on streaming_sampling_rate — 0 or negative values aren’t guarded. Same gap as other guardrails; only worth fixing if you want parity with stricter validators elsewhere.
Validate streaming_sampling_rate >= 1 in the constructor and Pydantic optional_params (ge=1), and add /v1/responses streaming coverage through the unified post-call hook so Responses API usage is exercised alongside chat completions.
|
Thanks for the review @Sameerlite, good catches. Pushed a follow-up that covers the actionable nits:
On the duplicated Mind taking another look when you get a chance? |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
|
@schneidermr Please check veria comment |
Guardrail API/UI delivers optional_params as a plain dict, so getattr was silently ignoring streaming_sampling_rate and streaming_end_of_stream_only. Handle both dict and model shapes in _get_config_value with regression tests.
|
@Sameerlite thanks for the ping, and thanks to Veria for catching this Fixed the nested streaming config issue: when configs come through the guardrail API/UI, Also added regression tests for the dict path (explicit nested values win, and sibling-only dict keys still fall through to top-level knobs). All 52 tests in the generic guardrail suite pass Mind taking another look when you get a chance? |
|
Thanks for your patience on this one! Your changes look solid — the Greptile review is just stale because of commits since the last review. Kicking off a fresh pass now. |
Keep generic_guardrail_api streaming_end_of_stream_only / streaming_sampling_rate and get_config_model alongside upstream fail_on_error, GuardrailToolParam extra=allow, and related tests
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2b464fd. Configure here.
|
merged with #31730 |
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
make test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
Unit coverage is in
tests/test_litellm/proxy/guardrails/guardrail_hooks/test_generic_guardrail_api.pyfor streaming defaults, optional_params plumbing viainitialize_guardrail(including top-level knobs not shadowed by sibling optional_params defaults), sampled vs end-of-stream-only cadence throughUnifiedLLMGuardrails.async_post_call_streaming_iterator_hook, mid-stream BLOCKED, fail_open on unreachable,/v1/responsesstreaming (end-of-stream-only + BLOCKED), andstreaming_sampling_raterejection of non-positive valuesPR-scoped local run: streaming config + unified classes -> 18 passed on the latest commit. Greptile P1 (optional_params non-None defaults shadowing top-level streaming flags) addressed earlier. Sameerlite review nits addressed:
streaming_sampling_ratevalidated>= 1(constructor + Pydanticge=1),/v1/responsesstreaming tests added;_get_config_valueleft local for now (same pattern as openai/grayswan/pillar)For a live proxy smoke test (run the proxy with your usual
dev_config.yamland ageneric_guardrail_apiguardrail configured onpost_call), exercise both modes:Type
🆕 New Feature
Changes
Adds first-class streaming configuration to
generic_guardrail_apiso it can participate in the existingUnifiedLLMGuardrailspost-call streaming path with the same knobs other guardrails already honor viagetattr(guardrail_to_apply, "streaming_*", default)streaming_end_of_stream_only(defaultfalsewhen unset) controls whether the guardrail runs incrementally on sampled chunks (an in-flight BLOCKED stops further chunks) or once at end of stream over the assembled response (cheaper/faster, but flagged content may already have reached the client).streaming_sampling_rate(default5when unset) sets the every-Nth-chunk cadence when incremental mode is on; ignored when end-of-stream-only is truePlumbing is through
GenericGuardrailAPIOptionalParams/GenericGuardrailAPIConfigModel(UI/config surface viaget_config_model()), constructor attributes onGenericGuardrailAPI, andinitialize_guardrailwhich reads either top-levellitellm_paramsor nestedoptional_paramsso both config styles work. Optional-params fields default toNoneso unset nested values do not shadow top-level streaming flags; real defaults are applied in the constructorTests cover defaults/overrides, config model exposure, initialize_guardrail forwarding, mixed-config priority (top-level vs explicit optional_params), safe streaming yield, mid-stream BLOCKED, sampling cadence (sampled + final aggregate), fail_open continuing the stream when the guardrail API is unreachable, non-positive
streaming_sampling_raterejection, and/v1/responsesstreaming through the unified hook (end-of-stream-only and BLOCKED)Note
Medium Risk
Changes guardrail behavior on streaming responses (when checks run and whether bad content may already reach the client); misconfiguration could weaken policy enforcement or increase guardrail API load.
Overview
Adds streaming post-call guardrail settings to
generic_guardrail_apiso it plugs into the existingUnifiedLLMGuardrailsstreaming hook viastreaming_end_of_stream_onlyandstreaming_sampling_rateon the guardrail instance.streaming_end_of_stream_only(defaultfalse) chooses between sampled in-stream checks (mid-streamBLOCKEDcan stop the stream) versus a single check on the assembled response at end of stream.streaming_sampling_rate(default5, must be ≥ 1) sets every-Nth-chunk sampling when incremental mode is on.Config is exposed on
GenericGuardrailAPIOptionalParams/GenericGuardrailAPIConfigModel, wired throughinitialize_guardrailwith_get_config_valueso nestedoptional_params(model or dict) wins when set butNonedefaults do not override top-levellitellm_params.GenericGuardrailAPI.get_config_model()is added for the UI/config surface.Tests cover init defaults, config resolution, unified streaming behavior (cadence, block, fail-open,
/v1/responses), and validation of non-positive sampling rates.Reviewed by Cursor Bugbot for commit 2b464fd. Bugbot is set up for automated code reviews on this repo. Configure here.