litellm/tests/test_litellm/proxy
yucheng-berri b2202cb1aa
feat(guardrails): streaming text transformation in generic_guardrail_api (#33110)
* feat(guardrails): support streaming text transformation in generic_guardrail_api

* chore(guardrails): address PR review feedback

* fix(guardrails): fail closed on tool-call and prefix-rewrite leaks in streaming transform

* fix(guardrails): address Bugbot review on streaming transform correctness

* fix(guardrails): coerce holdback in handler for in-process guardrails

* fix(guardrails): harden streaming transform (holdback coercion, tool-call passthrough, n>1 finish_reason)

* test(guardrails): targeted _mode_matches coverage for all guardrail_mode shapes

* fix(guardrails): inspect streamed tool calls and harden incremental_diff edge cases

* test: move ComplianceChecker mode tests to the compliance PR

* fix(guardrails): strip content from tool-call passthrough so streamed text can't bypass the transform

* fix(guardrails): four correctness fixes for incremental_diff streaming path

Four bug fixes on top of the OSS PR's incremental_diff streaming text
transformation, all inside the incremental_diff code paths only. No
existing block_only, non-streaming, or pre_call behavior is touched.

Fix #1 — Mixed content+tool_call finish_reason ordering
  _tool_call_passthrough_chunk now takes an optional finish_reason_per_choice
  map. For a choice carrying both delta.content and delta.tool_calls,
  finish_reason is stripped from the passthrough and recorded on the map so
  the final synthetic text chunk delivers it. Without this, SSE-compliant
  clients stopping at finish_reason drop the guardrailed text — defeating
  the redaction the whole feature exists for. (Greptile P1 twice, Veria.)

Fix #2 — Choice index sort in _process_streaming_transform
  indices/texts_to_check were derived from dict insertion order. For n>1
  streams where choice 1 emits before choice 0, guardrail-returned texts
  aligned to the input order mapped back to the wrong choice indices on
  write-back — wrong text goes to wrong choice. Sort raw_by_index.keys()
  up front so realignment is deterministic. (Bugbot Medium.)

Fix #3 — Cross-chunk pre-tool-call text flush
  With default streaming_sampling_rate=5, text chunks followed by a pure
  tool-call chunk carrying finish_reason='tool_calls' would emit the
  passthrough with finish_reason before any transformed text delta had
  fired. Same failure mode as fix #1 but cross-chunk. Now we flush any
  accumulated text via _round(is_final=False) BEFORE yielding the
  tool-call passthrough. (Greptile P1.)

Fix #4 — Terminator chunk for deferred finish_reason on empty mutated_text
  _build_transform_chunk returned None early when mutated_text_per_choice
  was empty. If a mixed content+tool_call chunk had deferred its
  finish_reason (via fix #1) and the guardrail then suppressed the text
  (empty return), the deferred finish_reason was never delivered. Now on
  is_final=True with empty mutated_text_per_choice, we emit a terminator
  carrying finish_reason per choice from finish_reason_per_choice.
  (Bugbot High.)

Also normalized Optional[X] → X | None across the OSS PR's added surface
via ruff UP045 autofix to keep the strict-rule gate within budget. Pure
mechanical typing style change, no semantic effect.

Regression tests for all four fixes:
- test_mixed_chunk_finish_reason_arrives_after_transformed_text (#1)
- test_text_flush_precedes_tool_call_passthrough (#3)
- test_final_finish_reason_flushed_when_guardrail_suppresses_text (#4)
- test_transform_sends_texts_sorted_by_choice_index (#2)

All fixes reachable only when streaming_transform_mode == 'incremental_diff'
is configured (via _run_incremental_transform_stream) or when a
StreamTransformSink is present (via _process_streaming_transform). Verified
scope-clean: no changes to block_only, non-streaming, pre_call, moderation,
or sibling guardrails.

---------

Co-authored-by: Marton Schneider <marton@schneider.co.nl>
2026-07-14 17:38:11 -07:00
..
_experimental/mcp_server refactor(mcp): extract the dcr_bridge token flow into bridge_token_flow.py 2026-07-13 23:12:54 -07:00
a2a feat(a2a): support a2a-sdk 1.x proxy routing for 0.3 and 1.0 agents (#30950) 2026-06-29 09:32:39 +05:30
agent_endpoints feat(a2a): support a2a-sdk 1.x proxy routing for 0.3 and 1.0 agents (#30950) 2026-06-29 09:32:39 +05:30
anthropic_endpoints feat: litellm oss staging (#31935) 2026-07-03 09:27:31 +05:30
auth fix(auth): scope the JWT enterprise gate to actual JWTs (#33296) 2026-07-14 17:05:05 -07:00
batches_endpoints test(batches): add 1:1 test file scaffold for batches component paths (#30529) 2026-06-29 09:22:58 +05:30
client feat: add lite auth print-token for Claude Code apiKeyHelper support (#32846) 2026-07-11 13:31:41 -07:00
common_utils fix(team): bound json merge patch recursion depth 2026-07-11 09:36:15 -07:00
db fix(mcp): classify get_user_object's wrapped DB outage across the exception chain 2026-07-13 13:25:41 -07:00
discovery_endpoints chore: litellm oss staging160626 (#30527) 2026-06-16 18:23:13 -07:00
experimental/mcp_server
google_endpoints chore: litellm oss staging160626 (#30527) 2026-06-16 18:23:13 -07:00
guardrails feat(guardrails): streaming text transformation in generic_guardrail_api (#33110) 2026-07-14 17:38:11 -07:00
health_endpoints fix(proxy): authorize /health/test_connection against loaded deployment's team_id (VERIA-441) (#31767) 2026-07-01 17:05:49 -07:00
hooks fix(proxy): track unauthenticated pass-through requests in spend logs (#32410) 2026-07-13 13:39:38 -04:00
image_endpoints fix(proxy): extend response headers hook to streaming, TTS, image gen, and pass-through (#24232) 2026-06-09 22:10:23 +02:00
logging_endpoints feat(proxy): add POST /v1/callbacks/logs to replay logging payloads through callbacks (#31134) 2026-06-24 15:25:10 -07:00
management_endpoints fix(proxy): never log raw virtual keys in key insertion debug output (#33268) 2026-07-14 16:32:26 -07:00
management_helpers feat(mcp): add all-proxy-mcpservers sentinel to grant teams every MCP server (#32012) 2026-07-03 13:59:28 -07:00
memory Litellm memory improvements v2 (#26541) 2026-04-25 19:03:43 -07:00
middleware feat(proxy): configurable response headers and login-page hint (#30792) 2026-06-18 18:12:45 -07:00
openai_files_endpoint fix(vertex/files): stream OpenAI->Vertex batch JSONL uploads (#31036) 2026-06-24 13:19:57 -07:00
pass_through_endpoints fix(passthrough): stream non-sse passthrough responses instead of buffering in memory (#32386) 2026-07-07 20:51:15 -07:00
policy_engine fix(policies): reject non-existent team/key/model scope entries on attachment create (#32131) 2026-07-04 11:58:29 -07:00
prompts style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
proxy_server fix(proxy): resolve os.environ/ refs universally in DB-sourced models 2026-07-07 18:31:44 -07:00
public_endpoints feat(ui): add Amazon Bedrock Mantle to the Add Model provider dropdown (#31034) 2026-06-22 17:31:25 -07:00
rag_endpoints fix: harden /key/update authorization checks (#27878) 2026-05-14 04:16:04 +00:00
realtime_endpoints chore: litellm oss 170626 (#30637) 2026-06-17 21:11:12 -07:00
response_api_endpoints Litellm websocket improvements (#29563) 2026-06-03 11:48:35 -07:00
shutdown feat(proxy): native /health/drain preStop hook for graceful shutdown (#29439) 2026-06-02 16:30:44 -07:00
spend_tracking fix(spend): sum multi-round session cost in logs UI (#32796) 2026-07-10 10:44:33 -07:00
test_configs
types_utils chore(proxy): also scrub guardrail callbacks / module paths from DB overlay 2026-05-14 01:24:51 +00:00
ui_crud_endpoints fix(mcp): byom visibility, preview UX, and admin settings gating (#31809) 2026-07-02 01:04:22 -07:00
utils fix(proxy): never log raw virtual keys in key insertion debug output (#33268) 2026-07-14 16:32:26 -07:00
vector_store_endpoints Title: fix(proxy): resolve vector store file list credentials from team deployments (#29739) 2026-06-06 12:36:05 -07:00
video_endpoints test(videos): add 1:1 test file scaffold for videos component paths (#30631) 2026-06-29 09:12:51 +05:30
__init__.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
conftest.py fix(proxy): recover Prisma DB reconnect loop when client is disconnected 2026-07-07 09:50:27 +03:00
test_aiohttp_cleanup_closed.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_aiohttp_session_recovery.py fix: use AsyncMock for concurrent test consistency 2026-03-18 00:54:23 +00:00
test_api_key_masking_in_errors.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_audio_speech_prometheus_hooks.py fix(proxy): extend response headers hook to streaming, TTS, image gen, and pass-through (#24232) 2026-06-09 22:10:23 +02:00
test_batch_expiry.py fix(proxy): strip LiteLLM policy tracking from OpenAI batch metadata (#28425) 2026-05-26 11:35:42 -07:00
test_batch_metadata_none_fix.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_batch_retrieve_bedrock.py fix(proxy/batches): forward model to retrieve_batch for bedrock 2026-04-29 22:48:03 +02:00
test_batch_x_litellm_model_encoding.py test(batches): move orphan tests into tests/test_litellm for CI coverage (#30510) 2026-06-16 10:20:59 -07:00
test_blocked_response_usage.py feat: litellm oss staging (#31935) 2026-07-03 09:27:31 +05:30
test_budget_reservation.py fix(proxy)!: enforce user budget on team keys (read-time + reservation) with UI opt-out (#32005) 2026-07-14 13:21:32 -07:00
test_caching_routes.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_chat_completion_metadata.py
test_common_request_processing.py test(proxy): cover per-key per-model TPM limit triggering gateway fallback 2026-07-06 18:25:49 -07:00
test_component_allowlists.py fix(gateway): keep the Prometheus /metrics Mount in the gateway route trim (#32317) 2026-07-07 18:36:38 +03:00
test_cors_config.py refactor: extract _get_cors_config() for testability, fix no-op CORS tests 2026-04-11 22:24:04 +05:30
test_custom_proxy.py
test_dynamic_mcp_route.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_empty_model_list.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_enforce_user_param.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_fallback_management_endpoints.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_fastapi_offline_routes.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_filter_models_by_team_access_group.py fix: resolve access group names in _filter_models_by_team_id (#25224) 2026-05-01 11:55:36 +05:30
test_health_check_functions.py feat(proxy): skip disable_background_health_check models on GET /health when flag set (#27716) 2026-05-13 09:49:05 -07:00
test_health_check_max_tokens.py fix: skip health check for semantic auto_router deployments (#31668) 2026-06-29 19:47:20 -07:00
test_langfuse_passthrough_security.py chore(callbacks): guard dynamic integration hosts 2026-04-30 14:27:19 -07:00
test_lazy_openapi_snapshot.py [Fix] Tests: Move Misplaced Import in Lazy OpenAPI Snapshot Test 2026-05-01 14:24:53 -07:00
test_litellm_pre_call_utils.py fix(proxy): restore admin key/team callback_vars.turn_off_message_logging override (LIT-3587) (#31905) 2026-07-02 15:01:58 -07:00
test_max_budget_env_var.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_mcp_asgi_response.py fix(mcp): surface upstream 401 for token-forwarding MCP servers (#27847) 2026-05-13 12:03:36 -07:00
test_model_based_routing_files_batches.py test(batches): move orphan tests into tests/test_litellm for CI coverage (#30510) 2026-06-16 10:20:59 -07:00
test_model_dump_with_preserved_fields.py Fix_mapped tests part 2 2026-02-26 12:43:39 +05:30
test_model_id_header_propagation.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_model_info_default_limits.py fix(proxy): align /v1/model/info with router deployments (#30025) 2026-06-10 19:38:21 -07:00
test_model_level_guardrails.py fix(guardrails): run pre_call hook once for model-level guardrails (#30543) 2026-06-16 11:17:03 -07:00
test_model_list_healthy_only.py feat: litellm oss 110626 (#30202) 2026-06-11 22:30:26 -07:00
test_modify_response_streaming_passthrough.py fix(proxy): use e.request_data for logging_obj in ModifyResponseException streaming passthrough (#30800) 2026-06-18 23:29:08 -07:00
test_openapi_schema_validation.py fix(proxy): preserve HTTP operations when injecting WebSocket stubs into OpenAPI schema 2026-05-06 00:28:42 +02:00
test_plugin_routes.py feat: litellm plugin architecture v2 (#30688) 2026-06-20 20:37:22 -07:00
test_pricing_field_strip.py chore: litellm oss staging160626 (#30527) 2026-06-16 18:23:13 -07:00
test_prometheus_cleanup.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_provider_url_destination_guard.py chore(proxy): move URL-valued model/file_id guard from SDK to proxy 2026-05-02 02:17:46 +00:00
test_proxy_cli.py chore: litellm oss staging (#30968) 2026-06-23 07:31:44 -07:00
test_proxy_logging_hook_detection.py perf: reduce per-request and per-chunk overhead across Anthropic streaming hot paths (#28289) 2026-05-23 12:15:59 -07:00
test_proxy_server.py fix(proxy)!: enforce user budget on team keys (read-time + reservation) with UI opt-out (#32005) 2026-07-14 13:21:32 -07:00
test_proxy_types.py fix(proxy): add default=None to LiteLLM_TeamMembership.litellm_budget_table (#29684) 2026-06-04 12:13:11 -07:00
test_proxy_utils.py fix(proxy): record partial spend on the failure row for interrupted streams (#30788) 2026-06-19 12:03:15 -07:00
test_pyroscope.py Implement normalize_nonempty_secret_str function to trim whitespace from secrets and treat empty values as unset. Update proxy_server to use this function for Grafana credentials. Enhance tests to validate the new normalization behavior. 2026-05-04 18:17:31 +00:00
test_read_model_list.py feat: add minimal rust router + axum ai-gateway calling router.realtime (2/2) (#31135) 2026-06-23 19:16:34 -07:00
test_redis_auth_cache_flag.py refactor(proxy): replace DualCache with UserApiKeyCache for user API key management 2026-04-28 19:15:03 +00:00
test_response_model_sanitization.py perf: eliminate per-request callback scanning on proxy hot path (#27858) 2026-05-14 09:28:31 -07:00
test_route_a2a_models.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_route_llm_request.py fix(realtime): preserve nested transcription model and session-first model priority 2026-07-03 14:21:22 -07:00
test_sensitive_route_auth.py chore(proxy): guard sensitive public endpoints 2026-04-30 11:52:47 -07:00
test_shared_health_check.py feat(proxy): skip disable_background_health_check models on GET /health when flag set (#27716) 2026-05-13 09:49:05 -07:00
test_spend_log_cleanup.py feat(spend_logs): opt-in native Postgres partitioning for SpendLogs retention (#29466) 2026-06-11 11:02:42 -07:00
test_swagger_chat_completions.py fix(proxy): avoid misleading multi-method operation ids 2026-04-30 20:44:14 -07:00
test_team_member_update.py feat(ui): add budget duration to edit team member form (#29717) 2026-06-06 17:24:55 -07:00
test_team_org_move.py fix(team_endpoints): auto-add SSO team members to org on move (proxy admin only) (#26377) 2026-04-24 08:36:25 -07:00
test_tools_allowlist_enforcement.py fix(responses-bridge): custom tool round-trip and allowlist preservation for Codex CLI (#32258) 2026-07-06 17:34:27 -07:00
test_update_llm_router_resilience.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00