Commit graph

3219 commits

Author SHA1 Message Date
Ishaan Jaffer
bf6945bc42 test(router): add coverage tests for _is_complexity_router_deployment and init_complexity_router_deployment 2026-02-21 15:19:45 -08:00
Ishaan Jaff
9f459c5c57
fix(logging): preserve pass-through endpoint response_cost (#21844)
* fix(logging): preserve pass-through endpoint response_cost in async_success_handler

Two places in the logging pipeline were overwriting response_cost that
pass-through handlers (Gemini/Vertex) had already calculated:

1. _process_hidden_params_and_response_cost fell through to
   _response_cost_calculator which returns None for pass-through calls
2. async_success_handler pass-through branch unconditionally set
   response_cost = None (introduced in PR #19887)

Now both places check if response_cost is already set before overwriting.

* test: add regression test for pass-through endpoint response_cost preservation
2026-02-21 15:09:45 -08:00
Ishaan Jaff
59e5b7e8c6
fix(tests): use monkeypatch.setenv for Redis pool max_connections tests (#21834)
Replace patch('litellm._redis._get_redis_client_logic') with monkeypatch.setenv
in test_max_connections_url_config and test_max_connections_url_config_string_value.

The mock was unreliable in CI (REDIS_URL is set to the real Redis Cloud server),
causing the pool to silently use the real config instead of the test config.
Using monkeypatch.setenv tests the full env-var→pool chain more robustly and
matches the actual production code path.
2026-02-21 14:38:28 -08:00
Ishaan Jaff
fb4249005e
fix(tests): add atexit.register mock to prevent Click isolation stream closure in test_use_prisma_db_push_flag_behavior (#21829) 2026-02-21 14:28:02 -08:00
Ishaan Jaff
494aad4a68
fix(tests): isolate auth in vertex passthrough and spend logs date range tests (#21824)
test_vertex_passthrough_with_default_credentials and
test_view_spend_logs_with_date_range_summarized fail intermittently when a
prior xdist worker sets master_key — auth then rejects the unauthenticated
test requests before the code under test is reached.

- mock user_api_key_auth in test_vertex_passthrough_with_default_credentials
  (same pattern used for test_vertex_passthrough_with_no_default_credentials
  in #21810)
- wrap test_view_spend_logs_with_date_range_summarized in
  app.dependency_overrides[ps.user_api_key_auth] with try/finally cleanup
  (same pattern used for the other spend log tests in #21810)
2026-02-21 14:14:50 -08:00
Ishaan Jaff
dd6a74da63
fix(tests): isolate litellm.cache and CLI env vars in flaky tests (#21821)
- TestSpendLogsPayload: save/restore litellm.cache in setup_method/teardown_method
  so tests that run after a cache-setting test don't see a non-None cache and get
  a hash instead of "Cache OFF" in the cache_key field
- test_use_prisma_db_push_flag_behavior: apply clean_env pattern (strip DATABASE_URL/DIRECT_URL,
  then set DATABASE_URL to test value) inside the with block instead of using @patch.dict
  decorator, matching the pattern from test_skip_server_startup to avoid Click 8.3.x
  StreamMixer stream lifecycle issues in CI
2026-02-21 14:11:48 -08:00
Ishaan Jaff
6acfa1c71d
fix(tests): clear ANTHROPIC_BASE_URL/ANTHROPIC_API_BASE in spend log api_base tests (#21820)
Tests hardcode expected api_base as https://api.anthropic.com/v1/messages but
if ANTHROPIC_BASE_URL is set in the environment the recorded api_base changes,
causing a mismatch. Clear both env vars via monkeypatch at the start of each test.
2026-02-21 14:11:18 -08:00
Ishaan Jaff
6ec16d583d
fix(test): add timeout to flush() call to prevent 300s hang in CI (#21819)
GLOBAL_LOGGING_WORKER.flush() calls queue.join() which blocks until all
items are task_done(). In CI with pytest-asyncio, each test gets a fresh
event loop so the worker reinitializes its queue - items from a previous
test never get task_done(), causing an infinite hang.

Fix: wrap flush() with asyncio.wait_for(..., timeout=10.0).
2026-02-21 14:10:57 -08:00
ryan-crabbe
b17d37eceb
Merge pull request #21815 from BerriAI/litellm_fix_openai_init_params_immutable
fix: make cached OpenAI init params immutable and fix import ordering
2026-02-21 13:33:03 -08:00
Ryan Crabbe
9e1d83e3de fix: make LITELLM_CLIENT_SPECIFIC_PARAMS a tuple to prevent TypeError
tuple + list raises TypeError in get_openai_client_cache_key. Also add
test coverage for get_openai_client_cache_key to catch type mismatches.
2026-02-21 13:25:23 -08:00
shin-bot-litellm
1be30f5129
feat(router): Add complexity-based auto routing strategy (#21789)
* feat(router): Add complexity-based auto routing strategy

Adds a rule-based routing strategy that classifies requests by complexity
and routes them to appropriate models - with zero API calls and sub-millisecond
latency.

## Features

- **Zero external API calls** - all scoring is local
- **Sub-millisecond latency** - typically <1ms per classification
- **Weighted multi-dimensional scoring** across 7 dimensions:
  - Token count (short=simple, long=complex)
  - Code presence (code keywords → complex)
  - Reasoning markers ("step by step" → reasoning tier)
  - Technical terms (domain complexity)
  - Simple indicators ("what is" → simple, negative weight)
  - Multi-step patterns (numbered steps)
  - Question complexity (multiple questions)
- **Configurable tier boundaries** and model mappings
- **Reasoning override** - 2+ reasoning markers force REASONING tier

## Usage

```yaml
model_list:
  - model_name: smart-router
    litellm_params:
      model: auto_router/complexity_router
      complexity_router_config:
        tiers:
          SIMPLE: gpt-4o-mini
          MEDIUM: gpt-4o
          COMPLEX: claude-sonnet-4
          REASONING: o1-preview
```

Inspired by ClawRouter: https://github.com/BlockRunAI/ClawRouter

## Files Added

- litellm/router_strategy/complexity_router/complexity_router.py - Main router class
- litellm/router_strategy/complexity_router/config.py - Configuration and defaults
- litellm/router_strategy/complexity_router/__init__.py - Package exports
- litellm/router_strategy/complexity_router/README.md - Documentation
- tests/test_litellm/router_strategy/test_complexity_router.py - Test suite (37 tests)

## Files Modified

- litellm/router.py - Integration with pre_routing_hook
- litellm/types/router.py - New config params

* feat(router): Add complexity-based auto routing strategy

Adds a new rule-based routing strategy that classifies requests by complexity
and routes them to appropriate models - without any external API calls.

## Features
- Weighted scoring across 7 dimensions: token count, code presence, reasoning
  markers, technical terms, simple indicators, multi-step patterns, questions
- Maps to 4 tiers: SIMPLE, MEDIUM, COMPLEX, REASONING
- Each tier configurable to a different model
- Zero API calls, <1ms latency
- Inspired by ClawRouter

## Configuration
```yaml
model_list:
  - model_name: smart_router
    litellm_params:
      model: auto_router/complexity_router
      complexity_router_config:
        tiers:
          SIMPLE: gemini-2.0-flash
          MEDIUM: gpt-4o-mini
          COMPLEX: claude-sonnet-4
          REASONING: claude-opus-4
```

## Use Cases
- Cost optimization: route simple queries to cheaper models
- Quality optimization: route complex queries to capable models
- Zero configuration: works out of the box with sensible defaults

* feat(router): Add complexity-based auto routing strategy

Adds a new rule-based routing strategy that classifies requests by complexity
and routes them to appropriate models - without any external API calls.

- Weighted scoring across 7 dimensions: token count, code presence, reasoning
  markers, technical terms, simple indicators, multi-step patterns, questions
- Maps to 4 tiers: SIMPLE, MEDIUM, COMPLEX, REASONING
- Each tier configurable to a different model
- Zero API calls, <1ms latency
- Inspired by ClawRouter

```yaml
model_list:
  - model_name: smart_router
    litellm_params:
      model: auto_router/complexity_router
      complexity_router_config:
        tiers:
          SIMPLE: gemini-2.0-flash
          MEDIUM: gpt-4o-mini
          COMPLEX: claude-sonnet-4
          REASONING: claude-opus-4
```

- Cost optimization: route simple queries to cheaper models
- Quality optimization: route complex queries to capable models
- Zero configuration: works out of the box with sensible defaults

* feat: add enterprise presets for complexity router

Adds preset configurations for different cloud providers:
- bedrock: AWS Bedrock (Claude models)
- vertex: Google Vertex AI (Gemini models)
- azure: Azure OpenAI (GPT + o1)
- standard: Direct API (OpenAI + Anthropic)
- cost_optimized: Maximum savings (Gemini Flash + cheaper models)

Usage:
```yaml
complexity_router_config:
  preset: bedrock  # or vertex, azure, standard, cost_optimized
```

* feat(ui): update auto router submit handler for complexity router

- Handle complexity_router model type in submit handler
- Generate correct litellm_params for complexity router:
  - model: auto_router/complexity_router
  - complexity_router_config: { tiers: { SIMPLE, MEDIUM, COMPLEX, REASONING } }
- Keep existing semantic router handling intact
- Add success notification with router type name

* docs: update PR description with UI changes

* chore: remove preset feature, keep simple tier config

* fix: exclude complexity_router from auto_router check

The _is_auto_router_deployment() was matching all auto_router/* models,
causing complexity_router to fail initialization. Now it explicitly
excludes auto_router/complexity_router which has its own handler.

* fix(complexity_router): Address Greptile review feedback

Fixes 5 issues flagged in code review:

1. **Mutable singleton mutation bug** - Now always creates a new
   ComplexityRouterConfig instance instead of reusing DEFAULT_COMPLEXITY_CONFIG
   singleton, preventing cross-instance config pollution.

2. **Substring matching false positives** - Added word boundaries (spaces)
   to short keywords like 'ok', 'try', 'api', 'git', 'node', 'java', 'vue'
   to prevent matching within longer words (e.g., 'capital' matching 'api').

3. **Redundant message extraction** - Simplified to single reverse loop that
   extracts both last user message and last system prompt efficiently.

4. **Unused imports** - Removed unused DEFAULT_CREATIVE_KEYWORDS and
   DEFAULT_MULTI_STEP_PATTERNS imports.

5. **Missing async_pre_routing_hook tests** - Added comprehensive tests for:
   - Multi-turn conversations
   - List-type content handling
   - No user message case
   - Empty string content
   - Message preservation
   - Singleton mutation prevention

* fix(complexity_router): Address Greptile review feedback

- Use word boundary matching for short keywords (<5 chars) to avoid
  false positives (e.g., 'api' matching 'capital', 'git' matching 'digital')
- Remove 'ok' from simple keywords (too many false positives)
- Add tests for keyword false positive prevention
- Fix test expectations for edge cases (empty string content, list content)

Addresses: 2/5 Greptile score feedback on PR #21789

* docs(auto_routing): Add complexity router documentation

- Add Complexity Router section to auto_routing.md
- Include comparison table with semantic auto router
- Add Python SDK and Proxy Server configuration examples
- Document all configuration options (tier boundaries, token thresholds, dimension weights)
- Explain how complexity scoring works

* feat(complexity_router): Add eval suite + tune scoring parameters

Added comprehensive evaluation suite with 29 test cases covering:
- SIMPLE tier: greetings, definitions, factual questions
- MEDIUM tier: technical explanations, comparisons, debugging
- COMPLEX tier: architecture design, complex coding
- REASONING tier: explicit reasoning requests
- Regression tests: substring false positive prevention

Tuned scoring parameters based on eval results:
- Lowered tier boundaries (0.15/0.35/0.60) for better tier distribution
- Increased code/technical weights (0.30/0.25) for complex prompts
- Reduced simple indicator weight (0.05) to avoid over-penalizing
- Fixed 'hey'/'hi' keywords to require leading space

Eval results: 29/29 passed (100%)

* fix(complexity_router): Address Greptile review round 2

1. **Empty user message handling** - Changed from falsy check to None check
   to properly distinguish 'no user message' from 'empty string message'

2. **ReDoS prevention** - Changed 'first.*then' to 'first.*?then' (non-greedy)
   to prevent regex backtracking on pathological inputs

3. **Documentation sync** - Updated README.md to match actual config values:
   - Tier boundaries: 0.15/0.35/0.60 (not 0.25/0.50/0.75)
   - Dimension weights: tokenCount=0.10, codePresence=0.30, technicalTerms=0.25,
     simpleIndicators=0.05, multiStepPatterns=0.03, questionComplexity=0.02

4. **Missing UI component** - Added ComplexityRouterConfig.tsx with:
   - Tier-to-model dropdown selectors
   - Descriptions and examples for each tier
   - How classification works explanation

5. **Inline import comment** - Added explanation for why ComplexityRouter
   import is inline (matches AutoRouter pattern, avoids circular imports)

* docs(auto_routing): fix dimension weights and tier boundaries to match config.py defaults

* fix(complexity_router): skip empty string content in async_pre_routing_hook

* fix(router): remove or {} masking None complexity_router_config

* fix(config): remove unused DEFAULT_MULTI_STEP_PATTERNS and DEFAULT_CREATIVE_KEYWORDS exports

* fix(complexity_router): use word boundary matching for all single-word keywords, avoid double-scanning reasoning keywords

* fix(router): clarify circular import comment for ComplexityRouter

* docs(README): fix token thresholds to match config.py defaults

* test(complexity_router): add false positive tests for error/class/merge keyword matching

* fix(complexity_router): align .get() fallbacks with config.py defaults, document system prompt scoring

* fix(config): deduplicate keywords across code and technical lists

---------

Co-authored-by: OpenClaw Assistant <assistant@openclaw.ai>
Co-authored-by: Ishaan Jaffer <ishaanjaffer0324@gmail.com>
2026-02-21 13:23:37 -08:00
Ryan Crabbe
bbbec23c8b fix: update tests to match tuple return type for cached init params 2026-02-21 13:18:03 -08:00
Ishaan Jaff
8483477512
fix(test): add asyncio.sleep(0) before flush() to prevent hang in test_async_no_duplicate_spend_logs (#21813) 2026-02-21 13:09:36 -08:00
Ishaan Jaff
b281181448
fix(tests): isolate auth in spend logs and vertex passthrough tests (#21810)
* fix(tests): add app.dependency_overrides for auth in spend logs tests

test_ui_view_spend_logs_with_status, test_ui_view_spend_logs_with_model,
test_ui_view_spend_logs_with_model_id, and test_view_spend_logs_summarize_parameter
all send Bearer sk-test without mocking user_api_key_auth. When a prior test
in the same xdist worker sets master_key, the auth check fails for sk-test
and the test fails intermittently.

Fix: use app.dependency_overrides[ps.user_api_key_auth] to bypass auth,
same pattern as other tests in the same file.

* fix(tests): mock user_api_key_auth in test_vertex_passthrough_with_no_default_credentials

vertex_proxy_route calls user_api_key_auth internally. When a prior test in the
same xdist worker sets master_key, the auth check fails for the test request
and create_pass_through_route is never called, causing assert_called_once_with to fail.

Fix: patch user_api_key_auth as an AsyncMock in the with mock.patch() block.
2026-02-21 12:51:38 -08:00
ryan-crabbe
da8f038178
Merge pull request #20789 from ryan-crabbe/perf/cache-openai-init-params
perf: pre-compute OpenAI client __init__ params at module load
2026-02-21 12:47:54 -08:00
Ryan Crabbe
5bcaeabfd8 Merge origin/main into litellm_fix_streaming_connection_pool_leak
Resolve conflict in test_proxy_server.py: keep both async_data_generator
cleanup tests and store_model_in_db DB config override tests.
2026-02-21 12:44:50 -08:00
ryan-crabbe
53f3dfa989
Merge pull request #20354 from ryan-crabbe/perf/callback-registration-routing
perf: move async/sync callback separation from per-request to registration
2026-02-21 12:41:28 -08:00
Ryan Crabbe
ea32ad72c6 Merge origin/main into perf/callback-registration-routing
Resolve conflicts:
- logging_callback_manager.py: keep PR's MAX_CALLBACKS, _is_async_callable, Callable type
- test_utils.py: keep both TestCallbackAsyncSyncSeparation and TestMetadataNoneHandling
2026-02-21 12:40:23 -08:00
Ishaan Jaff
02670582c5
fix(tests): replace asyncio.sleep(1) with event-based wait in metadata callback tests (#21805) 2026-02-21 12:40:06 -08:00
Miguel Armenta
0fe3145e83
Fix/presidio controls (#21798)
* check should_run_guardrail in sync logging hook path

* Add tests for CustomGuardrail logging behavior

Added tests to ensure CustomGuardrail logging behavior based on the guardrail execution state.

---------

Co-authored-by: Miguel Armenta <ma826r@att.com>
2026-02-21 12:39:17 -08:00
ryan-crabbe
f5139716a1
Merge pull request #20882 from ryan-crabbe/perf/optimize-model-dump-preserved-fields
perf: optimize model_dump_with_preserved_fields
2026-02-21 12:36:02 -08:00
Ishaan Jaffer
0b69c21eca Revert "fix(http_handler): bypass cache when shared_session is provided for aiohttp tracing (#20630)"
This reverts commit 7ee36c2a3a.
2026-02-21 12:27:46 -08:00
ryan-crabbe
d7b3b2eb9e
Merge pull request #20374 from ryan-crabbe/perf/cache-access-groups
perf: cache get_model_access_groups() no-args result on Router
2026-02-21 12:25:45 -08:00
ryan-crabbe
469951466e
Merge pull request #20541 from ryan-crabbe/perf/cost-calculator-optimizations
Perf/cost calculator optimizations
2026-02-21 12:18:38 -08:00
ryan-crabbe
a8dbcb1a30
Merge pull request #20526 from ryan-crabbe/perf/add-litellm-data-to-request-optimizations
Perf: add_litellm_data_to_request optimizations
2026-02-21 12:16:05 -08:00
ryan-crabbe
d04e5c6a3e
Merge pull request #20448 from ryan-crabbe/perf/optimize-completion-cost
perf: optimize completion_cost()
2026-02-21 12:15:48 -08:00
Ryan Crabbe
dc2c835e7b perf: optimize completion_cost() — eliminate enum overhead, reduce function call indirection
Pre-resolve CallTypes enum values into module-level frozensets to avoid
repeated .value attribute access in the elif chain. Inline the hot-path
_store_cost_breakdown_in_logging_obj as a direct dict literal. Remove
unnecessary cast(CallTypesLiteral, call_type) call. Guard
_get_additional_costs() with azure_ai-only check since no other provider
implements additional costs.

Line profile shows 20.5% reduction in completion_cost() total time
(7.14s → 5.68s across 6,006 calls). The four targeted bottlenecks
dropped from 2.82s to 0.28s combined.
2026-02-21 12:14:55 -08:00
ryan-crabbe
be016b683b
Merge pull request #20440 from ryan-crabbe/perf/skip-duplicate-logging-payload
perf: skip duplicate get_standard_logging_object_payload for non-streaming req's
2026-02-21 12:07:31 -08:00
ryan-crabbe
1ab11396f0
Merge pull request #20434 from ryan-crabbe/perf/prometheus-asgi-middleware
Perf/prometheus asgi middleware
2026-02-21 12:07:07 -08:00
Ryan Crabbe
498dad0af1 test: add backwards compatibility tests for PrometheusAuthMiddleware
Add tests verifying non-metrics requests pass through unaffected and
don't trigger auth even when auth is enabled.
2026-02-21 12:06:31 -08:00
Ishaan Jaff
87feca0b4a
fix: 2 failing CI tests in litellm_mapped_tests_proxy_part2 (#21797)
* fix(test): remove deprecated Click mix_stderr param in test_use_prisma_db_push_flag_behavior

Click 8.2+ removed the mix_stderr parameter from CliRunner. Use CliRunner() without it.

* fix(test): use app.dependency_overrides for auth mock in test_role_mappings_stored_and_retrieved

monkeypatch.setattr doesn't affect FastAPI's Depends() resolution in parallel
test execution. Use app.dependency_overrides which is the proper FastAPI pattern.
2026-02-21 12:04:58 -08:00
Ishaan Jaff
a939fa37ae
fix(proxy): restore broad is_database_connection_error; add is_database_transport_error for reconnect (#21796)
Any PrismaError should be treated as a DB connection error for the
allow_requests_on_db_unavailable feature and 503 responses. The narrow
keyword-based check is now in is_database_transport_error, which is
what the reconnect logic in auth_checks.py should use.

Fixes test_delete_access_group_503_on_db_connection_error and
test_handle_authentication_error_db_unavailable failures caused by
PR #21706 narrowing is_database_connection_error.
2026-02-21 12:04:00 -08:00
Ryan Crabbe
461a01311b perf: skip duplicate get_standard_logging_object_payload for non-streaming requests
- Add early return in _get_assembled_streaming_response for non-streaming
  requests, preventing duplicate standard_logging_object computation
- Move emit_standard_logging_payload into _process_hidden_params_and_response_cost
  so non-streaming requests still emit the debug payload
- Add emit_standard_logging_payload for dict/list result edge cases
2026-02-21 12:01:21 -08:00
Ishaan Jaff
c6a8034184
fix(tests): isolate flaky tests - restore global state in setup/teardown (#21791)
* fix(tests): isolate flaky files endpoint tests from global proxy state

* test(secret_managers): add mocked unit test for write/read JSON secret cycle

* fix(tests): restore litellm.callbacks in TestSpendLogsPayload setup/teardown

* fix(tests): clear app.openapi_schema in TestSwaggerChatCompletions setup/teardown

* fix(tests): add flaky marker to test_async_increment_tokens_with_ttl_preservation
2026-02-21 11:30:35 -08:00
Ishaan Jaff
21a549d78d
fix(tests): isolate flaky files endpoint tests from global proxy state (#21788)
* fix(tests): isolate flaky files endpoint tests from global proxy state

* test(secret_managers): add mocked unit test for write/read JSON secret cycle
2026-02-21 11:20:32 -08:00
Ryan Crabbe
c071e01fb6 fix: address PR review comments for model_dump_with_preserved_fields
- Restore preserve_fields param for backward compatibility (deprecated)
- Use zip() instead of index-based iteration to prevent IndexError
- Add backward compatibility test
2026-02-21 10:48:10 -08:00
Ishaan Jaff
3e67cb5287
fix: resolve flaky test failures in health, spend logs, and CLI tests (#21769)
* fix: reset db_health_cache in source module to prevent stale cache hits

The test was reassigning db_health_cache via `global` in the test module,
which doesn't affect the _health_endpoints module's variable. When a prior
test set the cache to "connected" within 2 minutes, _db_health_readiness_check
returned early without calling health_check(), causing assert_called_once to fail.

Also use PrismaError with a connection message so it's properly recognized
as a connection error by PrismaDBExceptionHandler.is_database_connection_error.

* fix: replace asyncio.sleep with polling loop in spend logs tests

The GLOBAL_LOGGING_WORKER processes callbacks via an async queue, so
asyncio.sleep(1) is a race condition - under CI load the worker may not
have processed the queued task within 1 second. Replace with a polling
helper that waits up to 10 seconds for the mock to be called.

Also add metadata.attempted_retries and metadata.max_retries to
ignored_keys since these are new fields.

* fix: isolate test_skip_server_startup from CI environment

Remove mix_stderr=False (unsupported in some Click versions). Strip
DATABASE_URL/DIRECT_URL from environment during the test to prevent
real prisma operations when these are set in CI.
2026-02-21 10:02:24 -08:00
yuneng-jiang
425f4e53f1
Merge pull request #21502 from milan-berri/fix/ui-model-credentials-batch-files
fix: resolve credentials for UI-created models in batch file uploads
2026-02-21 09:05:00 -08:00
Harshit Jain
e463fc22d9
Merge pull request #21763 from Harshit28j/litellm_feat_sticky_sessions
feat: add session_id to have better routing
2026-02-21 21:21:52 +05:30
Harshit Jain
f3ff9bf54f
Merge pull request #21009 from BerriAI/litellm_docker-count-no-req
add tests for hotpath & docker container
2026-02-21 20:57:28 +05:30
Harshit Jain
456d8f5524 feat: add session_id to have better routing 2026-02-21 18:45:50 +05:30
yuneng-jiang
1fb7320b6d
Merge pull request #21745 from BerriAI/litellm_org_member_email_ui
[Feature] UI - Organization Info: Show member email, AntD tabs, reusable MemberTable
2026-02-20 21:49:27 -08:00
yuneng-jiang
b61537cd0f feat: expose user_email in organization members response
Add user_email field to LiteLLM_OrganizationMembershipTable with a model_validator
that populates it from the nested user object, and update the /organization/info
Prisma query to select user_email from the related user record.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 21:41:53 -08:00
yuneng-jiang
9f3e20510d feat(usage): prefix credential tags and update Usage page banners
- Prefix credential name tags with "Credential: " to distinguish them
  from user-defined tags when litellm_credential_name is injected
- Remove stale "new feature" banners from Organization, Customer, and
  A2A usage views
- Add closable info banner to Tag usage view noting that reusable
  credentials are automatically tracked and appear as "Credential: <name>"
2026-02-20 20:55:57 -08:00
yuneng-jiang
b7efca22a2
Merge pull request #21723 from BerriAI/litellm_fix_cost_token_masking
[Fix] Model Info: input_cost_per_token masked in UI
2026-02-20 20:36:22 -08:00
Krish Dholakia
e8d0afd7cb
Guardrail - competitor name blocker (#21719)
* feat: add competitor name blocker guardrail

* fix: fix batch test endpoint for compliance playground

* fix(airline.py): add list of all known airlines to airline competitor name detector

prevent competitor discussion on company chatbot

* feat: ui tweaks for prod
2026-02-20 18:52:40 -08:00
yuneng-jiang
ac7446bb76 fix: don't mask cost_per_token fields in SensitiveDataMasker
Fields like input_cost_per_token contain "token" as a key segment,
which incorrectly matched the sensitive patterns list and caused values
like 3.6e-06 to be displayed as "3.60*******e-06" in the model info UI.

Add a non_sensitive_overrides set (defaulting to {"cost"}) so that any
key containing "cost" as a segment is never masked, regardless of other
matching patterns.
2026-02-20 18:13:27 -08:00
Ishaan Jaff
e0129710c8
fix(proxy): self-heal Prisma connection for auth and runtime (#21706)
* fix(proxy): add prisma reconnect primitive and db watchdog

* fix(proxy): start and stop prisma watchdog in lifecycle

* fix(auth): retry key lookup once after prisma reconnect

* test(proxy): add prisma self-heal watchdog coverage

* test(auth): cover reconnect-once behavior for key lookup

* refactor(auth): extract db reconnect helper and remove inline import

* fix(proxy): apply reconnect cooldown after attempt and add auth timeout path

* fix(auth): bound reconnect latency on key lookup path

* test(auth): assert reconnect timeout argument in key lookup

* test(proxy): verify reconnect cooldown timestamp set after attempt

* fix(proxy): harden prisma reconnect cycle semantics

* test(proxy): cover watchdog reconnect + timeout budget

* fix(proxy): bound watchdog probe and reconnect paths

* test(proxy): cover watchdog timeout and probe behavior

* fix(proxy): narrow prisma db connection error classification

* fix(proxy): add auth reconnect lock timeout budget

* fix(auth): pass lock timeout for db reconnect retries

* test(proxy): cover narrow prisma connection error detection

* test(proxy): add reconnect lock-timeout behavior coverage

* test(auth): assert reconnect lock timeout argument

* fix(proxy): avoid lock leak race in reconnect lock timeout path

* test(proxy): cover reconnect lock-timeout race cleanup
2026-02-20 18:11:36 -08:00
Ishaan Jaff
5246e64b98
Add topic blocker guardrail with keyword and embedding implementations (#21713)
* Add keyword-based topic blocker implementation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add embedding-based topic blocker using MiniLM

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add topic blocker package init with exports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add synthetic engine eval set (34 cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment questions eval set (207 cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add engine eval synthetic policy config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add engine keyword blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment keyword blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding blocker eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding MiniLM eval results

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment embedding MPNet eval results (historical)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add investment TF-IDF eval results (historical)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add unified eval runner with confusion matrix reporting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add benchmarks comparison table in markdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Clean up topic blocker: remove unused blockers, add phrase_patterns to content filter

- Remove embedding_blocker.py, api_embedding_blocker.py, nli_blocker.py,
  tfidf_blocker.py, onnx_blocker.py (heavy deps not in Docker, inferior accuracy)
- Remove airline_off_topic_restriction policy template and its test
- Fix __init__.py to only export DeniedTopic and TopicBlocker (no eager import crash)
- Add phrase_patterns support to ContentFilterGuardrail for regex-based paraphrase detection
- Rewrite denied_financial_advice.yaml with conditional matching (identifier + block word),
  always-block keywords, phrase patterns, and exception phrases
- Clean up test_eval.py: only keyword blocker + content filter tests remain (no network calls)
- All 207 eval cases pass at 100% F1, 0 FP, 0 FN, <0.1ms latency

Addresses all Greptile review comments:
- Eager import crash (embedding deps) → fixed
- Undeclared dependencies → fixed (files deleted)
- lru_cache memory leak → fixed (file deleted)
- Real network calls in tests → fixed (embedding tests removed)
- Unused Dict import → already fixed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add LLM-as-judge eval and update BENCHMARKS.md

- Add TestInvestmentLlmJudgeGpt4oMini and TestInvestmentLlmJudgeClaude
  test classes that use litellm.completion() to classify messages
- System prompt instructs LLM to act as airline chatbot content moderator
- Tests skip gracefully when API keys aren't set
- Update BENCHMARKS.md with production results table, historical comparison,
  and instructions for running LLM judge evals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move evals and benchmarks to guardrail_benchmarks folder

Move eval runner, eval data (JSONL), and results from
tests/test_litellm/.../topic_blocker/ into the guardrail implementation
folder at litellm/.../litellm_content_filter/guardrail_benchmarks/.

This keeps benchmarks co-located with the guardrail code they test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove standalone topic_blocker package, consolidate into content_filter

The standalone keyword_blocker.py was redundant with content_filter.py +
denied_financial_advice.yaml. Removed the entire topic_blocker/ package,
engine eval files, and old keyword blocker results. Simplified test_eval.py
to only test ContentFilter + LLM judge baselines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix compliance playground batch scoring bug, add display_name support

The compliance playground was sending all texts in a single batch API call,
but the content filter raises HTTPException on the first blocked text. This
caused a single blocked/allowed result to be applied to all rows, producing
incorrect scores (e.g. 41% instead of 100%). Fix by sending each text
individually to get per-text results with progressive UI updates.

Also add display_name field support for category YAML files so
denied_financial_advice shows as "Denied Financial / Investment Advice"
in the UI dropdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add block_investment CSV eval set and update benchmark result JSON

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* address greptile review feedback (greploop iteration 1)

Fix stale test path in denied_financial_advice.yaml comment.
Other comments were on files already deleted in prior commits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 18:02:04 -08:00
yuneng-jiang
5084fe9538
Merge pull request #21715 from BerriAI/litellm_credential_tag_usage
[Feature] Inject Credential Name as Tag for Usage Page Filtering
2026-02-20 17:51:28 -08:00