Conversation
The test was creating fresh mocks but not fully isolating from setUp state, causing intermittent CI failures with 'Expected generation to be called once. Called 0 times.' Instead of creating fresh mocks, properly reset the existing setUp mocks to ensure clean state while maintaining proper mock chain configuration.
Add s3_use_virtual_hosted_style parameter to support AWS S3 virtual-hosted-style URL format (bucket.endpoint/key) alongside the existing path-style format (endpoint/bucket/key). This enables compatibility with S3-compatible services like MinIO and aligns with AWS S3 official terminology.
…ctions (#21192) * Access groups UI * new badge changes * adding tests * fix: add custom_body parameter to endpoint_func in create_pass_through_route (#20849) * fix: add custom_body parameter to endpoint_func in create_pass_through_route The bedrock_proxy_route calls `endpoint_func(custom_body=data)` to pass a pre-parsed, SigV4-signed request body. However, the `endpoint_func` closure created by `create_pass_through_route` does not accept a `custom_body` keyword argument, causing: TypeError: endpoint_func() got an unexpected keyword argument 'custom_body' Add `custom_body: Optional[dict] = None` to both `endpoint_func` definitions (adapter-based and URL-based). In the URL-based path, when `custom_body` is provided by the caller, use it instead of re-parsing the body from the raw request. Fixes #16999 * Add tests for custom_body handling in create_pass_through_route Address reviewer feedback on PR #20849: - Document why the adapter-based endpoint_func accepts custom_body for signature compatibility but does not forward it (the underlying chat_completion_pass_through_endpoint does not support it). - Add test_create_pass_through_route_custom_body_url_target: verifies that when a caller (e.g. bedrock_proxy_route) supplies custom_body, it takes precedence over the body parsed from the raw request. - Add test_create_pass_through_route_no_custom_body_falls_back: verifies that the default path (no custom_body) correctly uses the request-parsed body, preserving existing behavior. Both tests are fully mocked following the project's CONTRIBUTING.md guidelines and the patterns established in the existing test file. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: themavik <themavik@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * change to model name for backwards compat * addressing comments * allow editing of access group names * fix: populate identity fields in proxy admin JWT early-return path (#21169) * fix: populate identity fields in proxy admin JWT early-return path When is_proxy_admin is True, the UserAPIKeyAuth early-return now includes user_id, team_id, team_alias, team_metadata, org_id, and end_user_id resolved from the JWT. Previously only user_role and parent_otel_span were set, causing blank Team Name and Internal User in Request Logs UI. * test: add unit tests for proxy admin JWT identity fields * bump: version 0.4.36 → 0.4.37 * migration + build files * Add pyroscope for observability (#21167) * Pyroscope: require PYROSCOPE_APP_NAME and PYROSCOPE_SERVER_ADDRESS, add UTF-8 locale hint - No defaults for PYROSCOPE_APP_NAME or PYROSCOPE_SERVER_ADDRESS; fail at startup if unset when Pyroscope is enabled - Set LANG/LC_ALL to C.UTF-8 when unset to reduce malformed_profile (invalid UTF-8) rejections - Startup message suggests PYTHONUTF8=1 if server rejects profiles - Simplify LITELLM_ENABLE_PYROSCOPE in config_settings; document Pyroscope env vars as required with no default - Add pyroscope_profiling to sidebar (Alerting & Monitoring) - pyproject.toml: pyroscope-io as required dep on non-Windows (marker), in proxy extra * proxy: add PYROSCOPE_SAMPLE_RATE env, use verbose logging, fix int type - Add optional PYROSCOPE_SAMPLE_RATE env (integer, no default) - Pass sample_rate to pyroscope.configure() as int for pyroscope-io - Replace print with verbose_proxy_logger (info/warning) - Document PYROSCOPE_SAMPLE_RATE in config_settings.md * Address Greptile PR feedback: Pyroscope optional, docs, tests, docstring - pyproject.toml: mark pyroscope-io as optional=true (proxy extra only) - Add docs/my-website/docs/proxy/pyroscope_profiling.md (fix broken sidebar link) - Add tests/test_litellm/proxy/test_pyroscope.py for _init_pyroscope() - proxy_server: fix _init_pyroscope docstring (required server/app name, sample rate as int) * Update litellm/proxy/proxy_server.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(model_info): Add missing tpm/rpm for Gemini models (#21175) Several Gemini models (TTS, native-audio, robotics, gemma) were missing tpm/rpm values, causing test_get_model_info_gemini to fail. Added conservative default values (tpm=250000, rpm=10) for preview models. gemini-2.5-flash-preview-tts gets tpm=4000000, rpm=10. Co-authored-by: OpenClaw <openclaw@users.noreply.github.com> * fix(ci): Fix ruff lint error - unused import in vertex_ai_ingestion (#21178) Co-authored-by: shin-bot-litellm <shin-bot-litellm@users.noreply.github.com> * fix(ci): Fix mypy type errors across 6 files (#21179) - vertex_ai/gemini: fix TypedDict assignment via explicit dict cast - mcp_server: convert MutableMapping scope to dict for type safety - pass_through_endpoints: simplify custom_body logic to fix type narrowing - vector_store_endpoints: add Any annotation for dynamic hook return - responses transformation: use dict() for Reasoning and setattr for dynamic field - zscaler_ai_guard: add assert for api_base None check Co-authored-by: shin-bot-litellm <shin-bot-litellm@users.noreply.github.com> * fix(ci): Fix E2E login button selector - use exact match (#21176) * fix(ci): Fix ruff lint error - unused import Remove unused 'cast' import in vertex_ai_ingestion.py (ruff F401) * fix(ci): Fix E2E login button selector - use exact match Login button selector now matches both 'Login' and 'Login with SSO', causing strict mode violation. Use { exact: true } to match only 'Login'. --------- Co-authored-by: OpenClaw <openclaw@users.noreply.github.com> * fix(mypy): Fix type errors across multiple files (#21180) - vertex_ai/gemini/transformation.py: Fix TypedDict assignment via dict alias - mcp_server/server.py: Convert ASGI scope to dict for type compatibility - pass_through_endpoints.py: Add explicit Optional[dict] type annotation - vector_store_endpoints/endpoints.py: Add Any type for dynamic proxy hook - responses transformation.py: Use dict(Reasoning()) and setattr for compatibility - zscaler_ai_guard.py: Add assert for api_base nullability Co-authored-by: OpenClaw <openclaw@users.noreply.github.com> * [Guardrails] Add guardrail pipeline support for conditional sequential execution (#21177) * Add pipeline type definitions for guardrail pipelines PipelineStep, GuardrailPipeline, PipelineStepResult, PipelineExecutionResult with validation for actions (allow/block/next/modify_response) and modes. * Export pipeline types from policy_engine types package * Add optional pipeline field to Policy model * Add pipeline executor for sequential guardrail execution * Parse pipeline config in policy registry * Add pipeline validation in policy validator * Add pipeline resolution and managed guardrail tracking * Resolve pipelines and exclude managed guardrails in pre-call * Integrate pipeline execution into proxy pre_call_hook * Add test guardrails for pipeline E2E testing * Add example pipeline config YAML * Add unit tests for pipeline type definitions * Add unit tests for pipeline executor * Update litellm/proxy/policy_engine/pipeline_executor.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update litellm/proxy/utils.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Add pipeline flow builder UI for guardrail policies (#21188) * Add pipeline type definitions for guardrail pipelines PipelineStep, GuardrailPipeline, PipelineStepResult, PipelineExecutionResult with validation for actions (allow/block/next/modify_response) and modes. * Export pipeline types from policy_engine types package * Add optional pipeline field to Policy model * Add pipeline executor for sequential guardrail execution * Parse pipeline config in policy registry * Add pipeline validation in policy validator * Add pipeline resolution and managed guardrail tracking * Resolve pipelines and exclude managed guardrails in pre-call * Integrate pipeline execution into proxy pre_call_hook * Add test guardrails for pipeline E2E testing * Add example pipeline config YAML * Add unit tests for pipeline type definitions * Add unit tests for pipeline executor * Add pipeline column to LiteLLM_PolicyTable schema * Add pipeline field to policy CRUD request/response types * Add pipeline support to policy DB CRUD operations * Add PipelineStep and GuardrailPipeline TypeScript types * Add Zapier-style pipeline flow builder UI component * Integrate pipeline flow builder with mode toggle in policy form * Add pipeline display section to policy info view * Add unit tests for pipeline in policy CRUD types * Refactor policy form to show mode picker first with icon cards * Add full-screen FlowBuilderPage component for pipeline editing * Wire up full-screen flow builder in PoliciesPanel with edit routing * Restyle flow builder to match dev-tool UI aesthetic * Restyle flow builder cards to match reference design * Update step card to expanded layout with stacked ON PASS / ON FAIL sections * Add end card to flow builder showing return to normal control flow * Add PipelineTestRequest type for test-pipeline endpoint * Export PipelineTestRequest from policy_engine types * Add POST /policies/test-pipeline endpoint * Add testPipelineCall networking function * Add PipelineStepResult and PipelineTestResult types * Add test pipeline panel to flow builder with run button and results display * Fix pipeline executor: inject guardrail name into metadata so should_run_guardrail allows execution * Update litellm/proxy/policy_engine/pipeline_executor.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update litellm/proxy/utils.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update litellm/proxy/policy_engine/policy_endpoints.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update litellm/proxy/policy_engine/pipeline_executor.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(responses-bridge): extract list-format system content into instructions When system message content is a list of content blocks (e.g. [{"type": "text", "text": "..."}]) instead of a plain string, the responses API bridge was passing it through as a role: system message in the input items. APIs like ChatGPT Codex reject this with "System messages are not allowed". This happens when requests come through the Anthropic /v1/messages adapter, which converts system prompts into list-format content blocks in the OpenAI chat completions format. Fix: extract text from list content blocks and concatenate into the instructions parameter, matching the existing behavior for string system content. * test: add tests for system message extraction in responses bridge Add three tests for convert_chat_completion_messages_to_responses_api: - String system content → instructions - List-format content blocks → instructions (the bug this PR fixes) - Multiple system messages (mixed string and list) concatenated * fix: add warning log for unexpected system content types Address review feedback: add an else clause that logs a warning for any system content that is neither str nor list, rather than silently dropping it. --------- Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com> Co-authored-by: The Mavik <179817126+themavik@users.noreply.github.com> Co-authored-by: themavik <themavik@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com> Co-authored-by: Alexsander Hamir <alexsanderhamirgomesbaptista@gmail.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: shin-bot-litellm <shin-bot-litellm@berri.ai> Co-authored-by: OpenClaw <openclaw@users.noreply.github.com> Co-authored-by: shin-bot-litellm <shin-bot-litellm@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile OverviewGreptile SummaryLarge staging PR that introduces guardrail pipeline execution (ordered, conditional guardrail steps within policies), renames
Confidence Score: 2/5
|
| Filename | Overview |
|---|---|
| litellm/proxy/proxy_server.py | Added Pyroscope initialization but has a critical missing return statement — the function runs the configuration code even when the feature is disabled. |
| litellm/proxy/policy_engine/pipeline_executor.py | New pipeline executor for sequential guardrail execution. Well-structured but original_guardrails metadata is saved but never restored after step execution. |
| ui/litellm-dashboard/src/app/(dashboard)/hooks/accessGroups/useAccessGroups.ts | TypeScript interface still uses access_model_ids while backend was renamed to access_model_names — will cause model data to silently be undefined in the UI. |
| litellm/proxy/auth/user_api_key_auth.py | Enriches proxy admin UserAPIKeyAuth return with team/org/user context fields. Straightforward and consistent with the existing non-admin code path. |
| litellm/proxy/utils.py | Adds pipeline execution integration to the pre-call hook and pipeline-managed guardrail skipping. Cleanly integrates with existing guardrail callback loop. |
| litellm/proxy/litellm_pre_call_utils.py | Extends policy resolution to include pipeline data in metadata and exclude pipeline-managed guardrails from the flat guardrails list. |
| litellm/integrations/s3_v2.py | Adds virtual-hosted-style URL support for S3. Clean implementation with proper protocol handling. |
| litellm/proxy/management_endpoints/access_group_endpoints.py | Renames access_model_ids to access_model_names and adds unique constraint handling for update. Backend change is clean but UI was not updated to match. |
| litellm/types/proxy/policy_engine/pipeline_types.py | Well-defined Pydantic models for pipeline types with proper validation on actions and modes. |
| litellm/proxy/policy_engine/policy_resolver.py | Adds pipeline resolution and managed guardrail extraction. Clean static methods that integrate with existing policy matching. |
| litellm/completion_extras/litellm_responses_transformation/transformation.py | Adds handling for list-format system message content blocks, extracting text parts into instructions. Correct fix for the responses transformation bridge. |
| litellm/proxy/schema.prisma | Adds pipeline JSON field to policy table and renames access_model_ids to access_model_names. Schema migration included. |
| litellm/proxy/policy_engine/policy_endpoints.py | Adds /policies/test-pipeline endpoint for testing guardrail pipelines. Well-structured with proper error handling. |
| litellm/responses/litellm_completion_transformation/transformation.py | Changes Reasoning() to dict(Reasoning()) and uses setattr for provider_specific_fields to avoid Pydantic validation issues. |
| litellm/proxy/pass_through_endpoints/pass_through_endpoints.py | Adds custom_body parameter to route handlers for signature compatibility and improves body forwarding logic. |
Flowchart
flowchart TD
A[Incoming Request] --> B[Policy Resolver]
B --> C{Matching Policies<br/>with Pipelines?}
C -->|No| D[Normal Guardrail Execution]
C -->|Yes| E[Pipeline Executor]
E --> F[Step 1: Run Guardrail]
F --> G{Outcome?}
G -->|Pass| H{on_pass action}
G -->|Fail| I{on_fail action}
H -->|allow| J[✅ Allow Request]
H -->|next| K[Step N: Run Next Guardrail]
H -->|block| L[❌ Block Request]
H -->|modify_response| M[🔄 Modify Response]
I -->|allow| J
I -->|next| K
I -->|block| L
I -->|modify_response| M
K --> G
J --> N[Skip Pipeline-Managed<br/>Guardrails in Normal Loop]
N --> D
D --> O[Continue Request Processing]
Last reviewed commit: 495ce34
| if not get_secret_bool("LITELLM_ENABLE_PYROSCOPE", False): | ||
| verbose_proxy_logger.debug( | ||
| "LiteLLM: Pyroscope profiling is disabled (set LITELLM_ENABLE_PYROSCOPE=true to enable)." | ||
| ) |
There was a problem hiding this comment.
Missing return when Pyroscope is disabled
The early-exit guard logs a debug message but never returns. The code falls through to the try: block and attempts import pyroscope even when LITELLM_ENABLE_PYROSCOPE is false. This means on every proxy startup (when pyroscope-io is not installed) a spurious ImportError warning is logged. If pyroscope-io is installed, it will attempt to configure Pyroscope (and raise ValueError for missing env vars) even though the feature is disabled.
| if not get_secret_bool("LITELLM_ENABLE_PYROSCOPE", False): | |
| verbose_proxy_logger.debug( | |
| "LiteLLM: Pyroscope profiling is disabled (set LITELLM_ENABLE_PYROSCOPE=true to enable)." | |
| ) | |
| if not get_secret_bool("LITELLM_ENABLE_PYROSCOPE", False): | |
| verbose_proxy_logger.debug( | |
| "LiteLLM: Pyroscope profiling is disabled (set LITELLM_ENABLE_PYROSCOPE=true to enable)." | |
| ) | |
| return |
| access_group_id: string; | ||
| access_group_name: string; | ||
| description: string | null; | ||
| access_model_ids: string[]; |
There was a problem hiding this comment.
Backend/UI field name mismatch
The backend schema and Python types were renamed from access_model_ids to access_model_names in this PR (see schema.prisma, litellm/types/access_group.py, and access_group_endpoints.py), but the UI AccessGroupResponse interface and all components that reference it still use access_model_ids. The API will return JSON with the key access_model_names, so access_model_ids will be undefined in the UI and model data will silently disappear.
This affects at least: useAccessGroups.ts, useCreateAccessGroup.ts, useEditAccessGroup.ts, AccessGroupsPage.tsx, AccessGroupsDetailsPage.tsx, AccessGroupEditModal.tsx, AccessGroupCreateModal.tsx, and their test files.
| access_model_ids: string[]; | |
| access_model_names: string[]; |
| original_guardrails = data["metadata"].get("guardrails") | ||
| data["metadata"]["guardrails"] = [step.guardrail] |
There was a problem hiding this comment.
original_guardrails saved but never restored
original_guardrails is saved at line 156 but is never restored after the guardrail executes. This means data["metadata"]["guardrails"] remains set to [step.guardrail] after _run_step completes. In a multi-step pipeline, each step overwrites this value (which is fine since it's re-set per step), but after the pipeline finishes, the caller's metadata is left mutated. Although execute_steps copies data and data["metadata"] at the top level, _run_step receives and mutates the working copy's metadata without cleanup — and if the pipeline result returns modified_data, downstream code may receive metadata with a stale single-guardrail list instead of the original.
Consider adding a finally block to restore:
finally:
if original_guardrails is not None:
data["metadata"]["guardrails"] = original_guardrails
elif "guardrails" in data.get("metadata", {}):
del data["metadata"]["guardrails"]- Add check in common_checks() to block users with scim_active=False - Fixes issue where SCIM PATCH to set active=false didn't prevent authentication - Add unit tests for scim_active validation - Raises ProxyException with 401 when deactivated user attempts to authenticate Resolves: #16427 (related SCIM deactivation issue)
#21117) When a shared ClientSession is passed to LiteLLMAiohttpTransport, calling aclose() on the transport would close the shared session, breaking other clients still using it. Add owns_session parameter (default True for backwards compatibility) to AiohttpTransport and LiteLLMAiohttpTransport. When a shared session is provided in http_handler.py, owns_session=False is set to prevent the transport from closing a session it does not own. This aligns AiohttpTransport with the ownership pattern already used in AiohttpHandler (aiohttp_handler.py).
|
This is #21307 cleaner |
Relevant issues
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewCI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Type
🆕 New Feature
🐛 Bug Fix
🧹 Refactoring
📖 Documentation
🚄 Infrastructure
✅ Test
Changes