Commit graph

8121 commits

Author SHA1 Message Date
yuneng-jiang
943445dd0f Adding test 2026-01-07 11:00:07 -08:00
yuneng-jiang
9a49bb293f Merge remote-tracking branch 'origin' into litellm_key_team_routing_config 2026-01-07 10:55:38 -08:00
yuneng-jiang
7da8d5fcd5 Merge remote-tracking branch 'origin' into litellm_endpoint_usage_breakdown 2026-01-07 10:25:43 -08:00
tianduo-fh
f7212d84d5
fix: prevent duplicate User-Agent tags in request_tags (#18723)
The `_get_request_tags` function was returning a reference to the
original tags list from metadata, then mutating it with `.extend()`.
This caused duplicate User-Agent tags when the function was called
multiple times during a single request lifecycle (e.g., by logging,
prometheus, and guardrails).

The fix uses `.copy()` to create a new list before extending, ensuring
the original metadata tags are not mutated.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Tianduo Zhai <tzhai@firsthandadmins-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 21:42:27 +05:30
kothamah
1b8708fccc
Litellm embeddings calltype fix for guardrail precallhook (#18740)
* adding signoz integration to observability docs

* Fixing build

* Adding timeout for flaky test

* Fixing e2e

* add team member budget duration in team/update

* Reusable Duration Select and update team member budget UI

* feat: allow configuring project name for OpenTelemetry service name

* docs: sets ARIZE_PROJECT_NAME

* added valid callType for bedrock guardrail pre hook

This is to resolve the error when bedrock guardrails are enabled and invoke the embedding models.   {"error":{"message":"'embeddings' is not a valid CallTypes","type":"None","param":"None","code":"500"}}*

* updated the test case to reflect valid callType

---------

Co-authored-by: Goutham Karthi <goutham@signoz.io>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: YutaSaito <36355491+uc4w6c@users.noreply.github.com>
Co-authored-by: Yuta Saito <uc4w6c@bma.biglobe.ne.jp>
2026-01-07 21:40:36 +05:30
Harshit Jain
92f7789f10
feat(prometheus): add caching metrics (#18755) 2026-01-07 21:29:04 +05:30
Kris Xia
91b5c66cf2
fix(proxy): return json error response instead of sse format for initial streaming errors (#18757)
* adding signoz integration to observability docs

* Fixing build

* Adding timeout for flaky test

* Fixing e2e

* fix(proxy): return json error response instead of sse format for initial streaming errors

when the first chunk of a streaming response contains an error,
return a standard json error response instead of sse format.
this ensures clients receive properly formatted error responses
before the stream actually begins.

- rename create_streaming_response to create_response
- add logic to detect error in first chunk and return JSONResponse
- add _extract_error_from_sse_chunk helper function
- update all call sites to use the new function name
- update tests to reflect the function rename

* test(proxy): add comprehensive tests for error extraction from sse chunks

- Add new test class TestExtractErrorFromSSEChunk with 10 test cases
- Update existing tests to verify JSONResponse returned for initial streaming errors
- Add tests for error code as string, bytes input, invalid JSON, and edge cases
- Verify correct error format extraction from SSE chunks

---------

Co-authored-by: Goutham Karthi <goutham@signoz.io>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: YutaSaito <36355491+uc4w6c@users.noreply.github.com>
2026-01-07 21:26:47 +05:30
Ishaan Jaffer
6122ff9fce TestEncryptResponseId 2026-01-07 21:03:22 +05:30
Ishaan Jaffer
b855ad5541 test_encode_decode_helpers_roundtrip_in_cache_context 2026-01-07 18:23:17 +05:30
Ishaan Jaffer
dd67235d4d TestLevoIntegration 2026-01-07 18:17:22 +05:30
drorIvry
000913fa12
Hotfix - docs qualifire (#18724)
* Hotfix - docs qualifire

* Hotfix - docs qualifire

* Hotfix - docs qualifire

* Hotfix - docs qualifire

* Hotfix - docs qualifire

* Hotfix - docs qualifire

* Hotfix - docs qualifire
2026-01-07 17:23:12 +05:30
Sameer Kankute
fdb9679657 Add annotations to completions responses API bridge 2026-01-07 14:30:31 +05:30
Ishaan Jaffer
3530218930 fix aupload_container_file 2026-01-07 14:19:36 +05:30
Sameer Kankute
d3e24ab9cd Fix: Gemini generate content request with audio file id 2026-01-07 12:58:54 +05:30
Sameer Kankute
bf506378b8 Fix: tool content should be str 2026-01-07 11:01:31 +05:30
Yuta Saito
1d16a8526e feat: allow configuring project name for OpenTelemetry service name 2026-01-07 14:20:10 +09:00
yuneng-jiang
2a6f2a3fb8 add team member budget duration in team/update 2026-01-06 17:43:17 -08:00
yuneng-jiang
ccfffc5de9 Add endpoint to aggregate activity tables 2026-01-06 15:54:03 -08:00
Alexsander Hamir
bb4c01ffa0
Add LITELLM_DISABLE_LAZY_LOADING env var to fix VCR cassette creation issue (#18725) 2026-01-06 14:49:11 -08:00
Otavio Brito
18ca6b2add
Handle not supported region for vertex ai count tokens - v1/messages/count_tokens (#18665)
* Handle not supported region for vertex ai count tokens

* add unit test
2026-01-07 00:05:00 +05:30
Felipe Peter
0756b48963
Add Anthropic cache control option to image tool call results (#18674) 2026-01-07 00:03:25 +05:30
Lize Cai
fe9b05e23e
Add header for SAP AI Core Tracking (#18714)
Signed-off-by: Lize Cai <lize.cai@sap.com>
2026-01-06 23:59:02 +05:30
Krish Dholakia
7004734528
Revert "feat: Add built-in migration lock to prevent concurrent Prisma migrat…" (#18719)
This reverts commit 9f68081f6d.
2026-01-06 23:56:02 +05:30
Hamza Qureshi
9c544949f8
feat: Add Prometheus metrics for request queue time and guardrails (#17973)
* feat: Add Prometheus metrics for request queue time and guardrails

- Add litellm_request_queue_time_seconds metric to track time from request arrival to processing start
- Add guardrail metrics: latency, errors_total, and requests_total counters
- Track arrival time in litellm_pre_call_utils.py
- Calculate queue time in common_request_processing.py
- Record guardrail metrics in pre_call_hook and during_call_hook
- Add comprehensive unit tests for all new metrics

Fixes #17863

* perf: optimize timing calls for queue time and guardrail metrics

* fix: resolve conflicts in utils.py - integrate Prometheus metrics with guardrail load balancing
2026-01-06 23:50:11 +05:30
minijeong-log
9f68081f6d
feat: Add built-in migration lock to prevent concurrent Prisma migrate deploy (#14440)
* feat: prisma migrate deploy with lock
Author: Mini Jeong <mini.jeong@navercorp.com>

* fix: use redis cache from proxy server
Author: Mini Jeong <mini.jeong@navercorp.com>

* fix: add type checks and fix unit tests for migration lock

- Add DATABASE_URL validation in _create_baseline_migration() and _resolve_all_migrations()
- Fix MyPy type errors by adding None checks before using database_url in subprocess calls
- Add _resolve_all_migrations mock to failing unit tests to prevent filesystem errors
- Apply Black formatting to modified files

Fixes:
- MyPy type errors: database_url could be None when passed to subprocess
- Unit test failures: _resolve_all_migrations tried to create directories in read-only /test path

* fix: resolve MyPy type error in vertex_ai vertex_llm_base

Fix MyPy type checking error where vertex_api_version parameter type
was incompatible with function signature expectation.

* fix: Return 403 exception when calling GET responses api

* fix: added new step into rotate master key function for processing credentials table

* Add redisvl in requirements.txt

* fix: fixed the issue of handling root paths when processing Discovery protected resource metadata and authorization server metadata URLs.

* fix: added additional grant type into oauth_authorization_server response for fixing mcp auth register bad request issue

* fix: added RFC RECOMMENDED property(scopes_supported) to protected resource and authorization server metadata

* fix: removed initialize the tool name to MCP server name mapping(oauth2) on startup for avoiding 401 error

* fix: upgraded mcp sdk depency version for fixing ClosedResourceError

* Use already configured opentelemetry providers

Users that instrument using opentelemetry-instrument can now setup exporters as per their environment.

* Handle all protocols for all telemetry

* Add more tests

* feat(mcp): parallelize tool fetching from multiple MCP servers (#18627)

* feat(mcp): parallelize tool fetching from multiple MCP servers

Replace sequential tool fetching with asyncio.gather() to reduce
client timeouts when using multiple MCP servers.

Changes:
- mcp_server_manager.py: list_tools() now fetches tools in parallel
- server.py: _get_tools_from_mcp_servers() now fetches tools in parallel

Real-world impact (7 MCP servers example):
- Sequential: ~4.5+ seconds (exceeds typical 5-second client timeouts)
- Parallel: ~1.2 seconds (max of all servers)

Fixes #18626

* fix: copy oauth2_headers to avoid shared dict mutation in parallel tasks

* feat: add display_name, model_vendor, and model_version metadata

* added the option of adding langsmith tenant id in the env (#18623)

* fix(router): Validate routing_strategy at startup to fail fast with helpful error. (#18624)

Invalid routing_strategy values (e.g., "simple" instead of "simple-shuffle") previously failed silently, causing confusing "No deployments available" errors downstream. This change adds upfront validation in routing_strategy_init() to:

- Check if the provided strategy matches valid string values or RoutingStrategy enum
- Raise a clear ValueError listing valid options if invalid
- Fail fast at startup instead of at request time

Fixes behavior reported in #11330 where users had to debug cryptic errors.

Valid strategies: simple-shuffle, least-busy, usage-based-routing, latency-based-routing, cost-based-routing, usage-based-routing-v2

Co-authored-by: Flibbert E. Gibbitz <flibbertygibbitz@runelabs.ai>

* Add libsndfile to database Docker image for audio processing (#18612)

The litellm-database Docker image was missing the libsndfile system
library, which is required by the soundfile Python package for audio
file processing. This caused failures when using audio transcription
endpoints that attempt to calculate audio duration.

This adds libsndfile to the runtime dependencies in Dockerfile.database,
consistent with Dockerfile.alpine which already includes this library.

* Fix: Map Gemini cached_tokens to Langfuse cache_read_input_tokens (#18614)

* Fix: Map Gemini cached_tokens to Langfuse cache_read_input_tokens

Fixes #18520

## Problem
Langfuse integration was not capturing cached tokens from Gemini models.
Gemini returns cached tokens in `usage.prompt_tokens_details.cached_tokens`,
but Langfuse only read from top-level `usage.cache_read_input_tokens`
(which only Anthropic populates).

## Solution
Updated langfuse.py to check both locations:
1. First check top-level cache_read_input_tokens (for Anthropic)
2. Then check prompt_tokens_details.cached_tokens (for Gemini, OpenAI, others)

This ensures all providers' cached tokens are properly reported to Langfuse.

## Changes
- Modified litellm/integrations/langfuse/langfuse.py (lines 742-761)
- Added 3 unit tests in tests/test_litellm/integrations/langfuse/test_gemini_cached_tokens.py
- All existing Langfuse tests still pass (11/11)

## Testing
- test_cached_tokens_extraction: Verifies Gemini cached_tokens extraction
- test_cached_tokens_not_present: Backward compatibility (no cached_tokens)
- test_cached_tokens_is_zero: Edge case when cached_tokens = 0

* Refactor: Extract cache token logic into helper function

Address review feedback from @officer47p

- Created _extract_cache_read_input_tokens() helper function
- Reduces code bloat in _log_langfuse_v2 method
- Improves testability and reusability
- All tests still passing (11/11)

* Adding Role Mappings

* Fixing Edit SSO Settings Modal

* feat: add user_mcp_management_mode for view_all visibility

* Fixing tests

* fix: missing mcp_allow_all_ui.png

* docs: add user_mcp_management_mode

* Align responses API streaming hooks with chat pipeline

* Clarify responses API streaming context

* Address review comments

* feat: Add GigaChat provider support (#18564)

* feat: Add GigaChat provider support

Add native support for GigaChat API (Sber AI, Russia's leading LLM).

Supported features:
- Chat completions (sync/async)
- Streaming (sync/async)
- Function calling / Tools
- Structured output via JSON schema (emulated through function calls)
- Image input (base64 and URL)
- Embeddings

Closes #18515

* fix: resolve mypy type errors in GigaChat handler

- Fix _prepare_file_data return type (use 3-tuple for cleaner type flow)
- Add type annotations for lists in _process_content_parts methods
- Add type annotations in _collapse_user_messages
- Use ChatCompletionToolCallChunk for proper tool_use typing
- Add type: ignore[override] for astreaming async generator

* refactor(gigachat): migrate to BaseConfig pattern

* fix: remove unused imports

* fix: resolve mypy type errors

* fix: mypy type errors

* refactor: address review feedback for GigaChat provider

- Remove singleton pattern, reuse litellm HTTPHandler
- Move constants/errors to transformation files, delete common_utils.py
- Add models to model_prices_and_context_window.json
- Fix ssl_verify not passed to HTTP client for embeddings

* docs: update GigaChat documentation with ssl_verify requirement

* Revert "Add redisvl in requirements.txt"

* Put reasoning summary behind feat flag

* fix: model eol

* fix: anthropic claude-3-opus-20240229 EOL

* Revert "fix: model eol"

This reverts commit 5aa1665d79.

* Fix: ImportError: qualifire package is required for QualifireGuardrail. Install it with: pip install qualifire

* fix: test_secret_manager_failure_does_not_block_email

* fix: test_update_ui_settings_allowlisted_value

* fix: test_aaamodel_prices_and_context_window_json_is_valid

* fix: test_all_models_have_display_name

* fix: async def test_bedrock_apply_guardrail_blocked()

* fix: test_databricks_embeddings[True]

* fix:test_anthropic_beta_header

* fix:test_api_error_handling

* fix:mypy mcp management

* Revert "feat(model_cost): add display_name, model_vendor, and model_version metadata to model entries"

* [Feat] New API Endpoint - Responses API (v1/responses/compact) (#18697)

* init transform_compact_response_api_request

* init acompact_responses

* init async_compact_response_api_handler in llm http handler

* init transform_compact_response_api_request for openai

* init acompact_responses

* fix acompact_responses

* add OAI Compact API

* docs responses API Compact

* code qa checks

* test_openai_compact_responses_api

* fix mypy linting

* fix: remove display name

* Add the LITELLM_REASONING_AUTO_SUMMARY in doc

* fix model map

* [UI] - Feat add request provider form on UI (#18704)

* add request provider form

* fix link to github

* add button

* fix link

* fix(streaming): normalize status code extraction to prevent 4xx errors from triggering mid-stream fallback (#18698)

在流式处理错误时,添加状态码标准化逻辑,确保 4xx 客户端错误直接抛出而不是被包装成 MidStreamFallbackError。

- 新增 _normalize_status_code 函数用于从异常对象提取状态码
- 优先从异常的 status_code 属性获取,其次从 response.status_code 获取
- 当映射异常或原始异常的状态码在 400-499 范围内时,直接抛出映射异常
- 添加单元测试验证 Vertex AI 400 错误正确抛出为 BadRequestError
- 确保流式处理中的客户端错误能够正确传播,而不会触发回退机制

---------

Co-authored-by: Eric84626 <lixiannan@gmail.com>
Co-authored-by: Eric84626 <97266539+Eric84626@users.noreply.github.com>
Co-authored-by: Sameer Kankute <sameer@berri.ai>
Co-authored-by: mangabits <1457532+mangabits@users.noreply.github.com>
Co-authored-by: Costa Tsaousis <costa@tsaousis.gr>
Co-authored-by: Nik <nikolas.garza5@gmail.com>
Co-authored-by: Shivam Rawat <161387515+shivamrawat1@users.noreply.github.com>
Co-authored-by: FlibbertyGibbitz <seth@evenkeelconsultingllc.com>
Co-authored-by: Flibbert E. Gibbitz <flibbertygibbitz@runelabs.ai>
Co-authored-by: Cesar Garcia <128240629+Chesars@users.noreply.github.com>
Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com>
Co-authored-by: Yuta Saito <uc4w6c@bma.biglobe.ne.jp>
Co-authored-by: LingXuanYin <3546599908@qq.com>
Co-authored-by: YutaSaito <36355491+uc4w6c@users.noreply.github.com>
Co-authored-by: 0717376 <103773680+0717376@users.noreply.github.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: Kris Xia <xiajiayi0506@gmail.com>
Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
2026-01-06 23:46:24 +05:30
Kris Xia
5e00a49e7f
fix(streaming): normalize status code extraction to prevent 4xx errors from triggering mid-stream fallback (#18698)
在流式处理错误时,添加状态码标准化逻辑,确保 4xx 客户端错误直接抛出而不是被包装成 MidStreamFallbackError。

- 新增 _normalize_status_code 函数用于从异常对象提取状态码
- 优先从异常的 status_code 属性获取,其次从 response.status_code 获取
- 当映射异常或原始异常的状态码在 400-499 范围内时,直接抛出映射异常
- 添加单元测试验证 Vertex AI 400 错误正确抛出为 BadRequestError
- 确保流式处理中的客户端错误能够正确传播,而不会触发回退机制
2026-01-06 23:41:23 +05:30
Wiley Kestner
9e6714fe1b
Tally total_tokens in response if missing (#18468) (#18445)
Calculate `total_tokens` in usage data in Response manually if:

    - `total_tokens` is missing
    - `total_tokens` can be calculated from input and output tokens

Run the test for this feature with:

`poetry run pytest tests/test_litellm/responses/test_responses_utils.py -k "test_transform_response_api_usage_calculates_total_from_input_and_output_tokens_if_available" -v`
2026-01-06 20:34:02 +05:30
Sameer Kankute
353769d2ac
Merge pull request #18688 from BerriAI/litellm_fix_reasoning_summary_default
[Fix] Put automatic reasoning summary inclusion behind feat flag
2026-01-06 17:56:40 +05:30
Sameer Kankute
2baec27657
Revert "feat(model_cost): add display_name, model_vendor, and model_version metadata to model entries" 2026-01-06 15:29:42 +05:30
Sameer Kankute
865c7a2215 fix: test_update_ui_settings_allowlisted_value 2026-01-06 13:58:37 +05:30
Sameer Kankute
9d59d3eef6 fix: test_secret_manager_failure_does_not_block_email 2026-01-06 13:58:15 +05:30
Sameer Kankute
9f65f82c56 Fix: ImportError: qualifire package is required for QualifireGuardrail. Install it with: pip install qualifire 2026-01-06 13:52:26 +05:30
Sameer Kankute
bb00a53786 Put reasoning summary behind feat flag 2026-01-06 11:36:20 +05:30
Sameer Kankute
694e44551f
Merge pull request #17330 from nmgarza5/add-model-metadata
feat(model_cost): add display_name, model_vendor, and model_version metadata to model entries
2026-01-06 10:56:49 +05:30
Sameer Kankute
3c0248edb9
Merge pull request #18663 from BerriAI/litellm_staging_01_05_2026
Staging 01/05/2026
2026-01-06 10:46:04 +05:30
YutaSaito
a774e7899c
Merge pull request #18281 from Eric84626/main
Fix: fixed some MCP gateway oauth2 auth issues and ClosedResourceError
2026-01-06 13:22:46 +09:00
YutaSaito
31470032ad
Merge pull request #18681 from BerriAI/litellm_feat_mcp-server-visibility-configurable
[feat] mcp server visibility configurable
2026-01-06 12:53:07 +09:00
YutaSaito
ccdcb20048
Merge pull request #18279 from mangabits/fix-otel-provider
Use already configured opentelemetry providers
2026-01-06 12:49:48 +09:00
Yuta Saito
694bcb6186 feat: add user_mcp_management_mode for view_all visibility 2026-01-06 11:22:28 +09:00
yuneng-jiang
1b7b42628d Add/update for router_settings in keys / teams 2026-01-05 16:19:42 -08:00
Eric84626
f59e9cef55
Merge branch 'main' into main 2026-01-06 06:57:25 +08:00
Yuta Saito
a8092ab4c4 fix: ensure_async_clients_test error 2026-01-06 07:13:13 +09:00
yuneng-jiang
7937c8674b
Merge pull request #18666 from BerriAI/litellm_keys_create_hour_fix
[Fix] Use timedelta to Calculate Key Expiry on Generate
2026-01-05 12:57:53 -08:00
yuneng-jiang
c7345e4bfd Use timedelta to calculate key expiry 2026-01-05 12:24:34 -08:00
Urain Ahmad Shah
bf33e639ef
Fix User Invite & Key Generation Email Notification Logic (#18524)
* Fix email notification

* Update email notification tests

* moved test file
2026-01-06 01:35:52 +05:30
drorIvry
b6a64ff99a
feature/ add qualifire guardrails (#18594)
* init guardrails

* init guardrails

* some fixes

* some fixes

* ruff

* some fixes

* some fixes

* some fixes

* some fixes

* some fixes

* some fixes

* docs
2026-01-06 01:34:43 +05:30
Cesar Garcia
0e601d0bfe
Fix: Map Gemini cached_tokens to Langfuse cache_read_input_tokens (#18614)
* Fix: Map Gemini cached_tokens to Langfuse cache_read_input_tokens

Fixes #18520

## Problem
Langfuse integration was not capturing cached tokens from Gemini models.
Gemini returns cached tokens in `usage.prompt_tokens_details.cached_tokens`,
but Langfuse only read from top-level `usage.cache_read_input_tokens`
(which only Anthropic populates).

## Solution
Updated langfuse.py to check both locations:
1. First check top-level cache_read_input_tokens (for Anthropic)
2. Then check prompt_tokens_details.cached_tokens (for Gemini, OpenAI, others)

This ensures all providers' cached tokens are properly reported to Langfuse.

## Changes
- Modified litellm/integrations/langfuse/langfuse.py (lines 742-761)
- Added 3 unit tests in tests/test_litellm/integrations/langfuse/test_gemini_cached_tokens.py
- All existing Langfuse tests still pass (11/11)

## Testing
- test_cached_tokens_extraction: Verifies Gemini cached_tokens extraction
- test_cached_tokens_not_present: Backward compatibility (no cached_tokens)
- test_cached_tokens_is_zero: Edge case when cached_tokens = 0

* Refactor: Extract cache token logic into helper function

Address review feedback from @officer47p

- Created _extract_cache_read_input_tokens() helper function
- Reduces code bloat in _log_langfuse_v2 method
- Improves testability and reusability
- All tests still passing (11/11)
2026-01-06 01:34:09 +05:30
Alexsander Hamir
85a357c7e5
fix: extend case normalization to ALL guardrail types (not just tool_permission) (#18664)
This extends the previous fix to handle capitalized fields across ALL guardrail types,
including Presidio, Azure, Lakera, Bedrock, etc.

Discovery:
- Database investigation revealed the issue affects multiple guardrail types
- Found 4 affected guardrails in staging: 3 Presidio + 1 Azure
- All had default_action: 'Deny' causing the same validation failures
- The initial fix only covered ToolPermissionGuardrailConfigModel

Root Cause (Deeper):
- LitellmParams inherits from 13+ different guardrail config models
- Models use ConfigDict(extra="allow") allowing any field to be set
- Users can set default_action/on_disallowed_action on ANY guardrail type
- Only ToolPermissionGuardrailConfigModel was validating these fields

Solution:
- Added field validators to LitellmParams class (parent of all guardrails)
- Validators run for ALL guardrail types: Presidio, Azure, Bedrock, Lakera, etc.
- Added comprehensive tests covering multiple guardrail types

Changes:
- litellm/types/guardrails.py:
  * Added @field_validator for default_action in LitellmParams
  * Added @field_validator for on_disallowed_action in LitellmParams
  * Added normalization in LitellmParams.__init__ as backup
  * Imported field_validator from pydantic

- tests/test_litellm/types/test_guardrails_case_normalization.py:
  * New test file with 7 tests covering multiple guardrail types
  * Tests verify Presidio, Azure, Tool Permission, Lakera, Bedrock
  * All tests passing

Impact:
- Previous fix: Only tool_permission guardrails protected
- This fix: ALL guardrail types now protected (13+ types)
- Handles both new writes and existing database records
- Tested against actual database with Presidio/Azure guardrails

Testing:
- 7 new cross-guardrail tests (all passing)
- 27 existing tool_permission tests (all passing)
- Verified fix works for real database records
2026-01-05 11:59:00 -08:00
Krish Dholakia
b5aa7d1838
feat: Add api_key to GenericGuardrailAPI and set x-api-key header (#18647)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-01-06 01:05:51 +05:30
Alexsander Hamir
0b0a9abd90
fix: normalize case for tool permission guardrail fields to prevent validation errors (#18662)
This fixes a critical issue where capitalized values in tool_permission guardrail
configurations (e.g., "Deny" instead of "deny") caused Pydantic validation errors
during proxy startup, leading to repeated initialization failures and latency issues.

Problem:
- Users could save guardrails with capitalized values through UI/API
- Data was written to database without validation (e.g., default_action: "Deny")
- On proxy startup, loading from DB triggered strict Pydantic validation
- ValidationError caused guardrail initialization to fail in a retry loop
- This resulted in startup delays and repeated error logging

Root Cause:
- Write path had no case normalization
- Read path enforced strict lowercase Literal validation
- Asymmetry between write and read caused latent data corruption

Solution:
Added field validators to normalize case before Pydantic validation:

1. ToolPermissionRule.decision ("allow"/"deny")
   - Normalizes decision field in rules array

2. ToolPermissionGuardrailConfigModel.default_action ("allow"/"deny")
   - Normalizes default fallback action

3. ToolPermissionGuardrailConfigModel.on_disallowed_action ("block"/"rewrite")
   - Normalizes disallowed tool behavior

4. ToolPermissionGuardrail.__init__ normalization
   - Defensive normalization for direct instantiation
   - Ensures normalization regardless of code path

Impact:
- Prevents validation errors during guardrail initialization
- Eliminates startup retry loops and latency issues
- Handles existing database records with capitalized values
- Accepts case-insensitive input from all sources (UI, API, direct calls)
- Fully backward compatible with existing lowercase configurations

Testing:
- Added 3 comprehensive tests for case-insensitive handling
- All 27 existing tests still pass
- Tests verify normalization across all affected fields

Files Changed:
- litellm/types/proxy/guardrails/guardrail_hooks/tool_permission.py
  Added @field_validator decorators for case normalization
- litellm/proxy/guardrails/guardrail_hooks/tool_permission.py
  Added runtime normalization in __init__ method
- tests/test_litellm/proxy/guardrails/guardrail_hooks/test_tool_permission.py
  Added case-insensitive validation tests
2026-01-05 11:24:19 -08:00