Commit Graph
32801 Commits
Author SHA1 Message Date
Sameer Kankute 32bfbbfbe1 Add method support for passthrough endpoints 2026-02-19 11:58:25 +05:30
e00c181f0c Mcp user permissions (#21462)
* feat(schema.prisma): add object permissions for end users

allows controlling if end user can call specific mcp servers

* feat: cleanup for customer_endpoints support of object permission id

* fix: cleanup str

* feat(customers/): enforce end user can only call allowed mcps - if configured

* docs: document customer/end user object permission usage

* feat: enforce end user permissions on MCP tool calls

This commit implements end user permission enforcement for MCP servers:

1. Always add server prefixes to MCP tool names
   - Removed conditional logic that only added prefixes when multiple servers existed
   - Now always adds server prefix for consistent tool naming across all scenarios
   - Updated 5 locations in server.py (list_tools, get_prompts, get_resources,
     get_resource_templates, get_prompt)

2. Created MCP End User Permission Guardrail Hook
   - New guardrail hook: litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission.py
   - Runs on post_call to validate tool calls in LLM responses
   - Extracts MCP server name from tool names (splits on first '-')
   - Checks if end_user_id has permissions for the MCP server
   - Raises GuardrailRaisedException if end user lacks permission
   - Supports both streaming and non-streaming responses

3. Added comprehensive tests
   - Test file: tests/test_litellm/proxy/guardrails/guardrail_hooks/test_mcp_end_user_permission.py
   - Tests cover: authorized/unauthorized tools, non-MCP tools, no end_user scenarios
   - Tests permission checking logic and exception raising

The hook integrates with the existing MCPRequestHandler._get_allowed_mcp_servers_for_end_user
to fetch end user permissions and enforce access control at the response level.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: remove redundant add_prefix variable assignments

Simplified the code by removing intermediate `add_prefix` variable
assignments and passing `True` directly to function calls since
we now always add server prefixes.

Changes:
- Removed `add_prefix = True` variable assignments in 5 locations
- Changed `add_prefix=add_prefix` to `add_prefix=True` in function calls
- Added inline comments to clarify the behavior

This makes the code more concise and clearer in intent.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(auth_utils.py): support safety_identifier as a valid way of passing the end user id for responses api

* feat(llms): ensure 'tools' is correctly updated for responses api

* fix: fix greptile feedback

* feat: transformation.py

proper responses api tool handling for guardrail translation layer

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-18 18:53:59 -08:00
Ishaan JafferandWarp 936e04e0e1 fix: add missing Field import in policy_endpoints.py
Co-Authored-By: Warp <agent@warp.dev>
2026-02-18 18:28:31 -08:00
Ishaan JaffandGitHub 91fd2b4621 Add aviation and UAE policy templates with tag-based filtering (#21518)
* add aviation and UAE regex patterns (PNR, Skywards, Emirates ID, UAE phone, flight number)

* add aviation safety topics category yaml

* add airline brand protection category yaml

* add UAE cultural sensitivity category yaml

* add UAE anti-discrimination category yaml

* add aviation, UAE, and competitor policy templates + migrate region/type to tags

* sync policy_templates_backup.json

* add /policy/templates/enrich endpoint for LLM competitor discovery

* add enrichPolicyTemplate networking call

* add TemplateParameterModal component

* handle parameterized templates and LLM enrichment in policies index

* replace region/type radio filters with tag sidebar checkboxes
2026-02-18 18:26:24 -08:00
Krish DholakiaandIshaan Jaffer a385126a7c Litellm dev compliance UI (#21457)
* feat(ui/): initial commit adding a compliance testing playground

allow proxy admins to test policies and guardrails against datasets

* feat(ui/): make score more friendly

* feat(policy_endpoints.py): new helper function for testing policies

* feat(policy_endpoints.py): expose new endpoint for testing policies and guardrails

enables compliance playground to work as expected

* feat(complianceui.tsx): show returned text
2026-02-18 18:22:43 -08:00
Ishaan JaffandGitHub 323aed7211 fix: CI failures - missing env key doc + streaming test (#21510)
* docs: add DATABRICKS_API_KEY to environment settings reference

* fix: streaming test usage check on Pydantic model

* fix: mock litellm.proxy.proxy_server in test_skip_server_startup
2026-02-18 18:20:32 -08:00
yuneng-jiangandGitHub 2c6095bdf2 Merge pull request #21511 from BerriAI/litellm_store_model_in_db_from_database
[Feature] Allow store_model_in_db to be set via database
2026-02-18 17:43:56 -08:00
yuneng-jiangandGitHub 64fe3a502e Merge pull request #21503 from BerriAI/litellm_sso_role_map
fix(sso): preserve SSO role regardless of role_mappings config
2026-02-18 17:31:49 -08:00
yuneng-jiangandClaude Opus 4.6 6356db560d [Feature] Allow store_model_in_db to be set via database
Users had to set store_model_in_db in the config YAML and restart the proxy,
causing service downtime. This change allows the value to be written to the
LiteLLM_Config table and read from the database at runtime, with DB values
overriding config file values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-18 17:25:39 -08:00
Shivam RawatandGitHub 9ceaa2cbb0 tests and route permissions (#21508) 2026-02-18 16:58:38 -08:00
jquinterandGitHub d75bb10c5f Merge pull request #21506 from BerriAI/fix/enterprise-install-wrong-venv
fix(ci): install enterprise package into main project venv, not enterprise's own venv
2026-02-18 21:31:48 -03:00
Julio Quinteros ProandClaude Sonnet 4.6 24ead9b4e1 fix(ci): install enterprise package into main project venv, not enterprise's own venv
Running `cd enterprise && poetry run pip install -e .` causes poetry to
create a separate venv in `enterprise/.venv` (since enterprise/ has its
own pyproject.toml). The main project's tests run with `.venv/bin/python`,
so the enterprise package installed in `enterprise/.venv` is never seen.

Fix: run `poetry run pip install -e enterprise/` from the repo root so
poetry uses the main project's venv. This ensures litellm_enterprise is
importable when tests run.

This explains why enterprise tests kept failing with:
  AttributeError: '_PROXY_LiteLLMManagedFiles' object has no attribute
  '_check_file_deletion_allowed'
even after --force-reinstall was added — the reinstall was going to the
wrong virtual environment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 21:24:06 -03:00
Ishaan JaffandGitHub 6486db3646 fix: improve streaming proxy throughput by fixing middleware and logging bottlenecks (#21501)
* fix(middleware): replace BaseHTTPMiddleware with pure ASGI middleware

BaseHTTPMiddleware wraps streaming responses with receive_or_disconnect
per chunk, blocking the event loop and causing severe throughput
degradation under concurrent streaming load (53% of CPU in profiling).

Converts PrometheusAuthMiddleware to a pure ASGI middleware using the
__call__(scope, receive, send) protocol.

* fix(streaming): remove expensive debug logging and optimize usage stripping

- Remove print_verbose calls that format chunk/response Pydantic objects,
  triggering millions of __repr__ calls (8% of CPU in profiling)
- Guard remaining verbose_logger.debug with isEnabledFor(DEBUG) and use
  lazy %s formatting instead of f-strings
- Replace usage stripping round-trip (model_dump + delete + reconstruct)
  with a _usage_stripped flag, deferring exclusion to serialization time

* fix(proxy): remove per-chunk debug log and use _usage_stripped flag

- Remove verbose_proxy_logger.debug that formatted every streaming chunk
- Honor _usage_stripped flag from streaming handler to exclude usage
  during model_dump_json serialization instead of reconstructing objects

* fix(proxy): remove per-chunk debug log in async_data_generator

Remove verbose_proxy_logger.debug that formatted every streaming chunk,
which triggered expensive Pydantic serialization on the hot path.

* fix indentation and add clarifying comment for usage stripping

* fix: guard calculate_total_usage against None usage in chunks

* fix: store chunk copy to preserve usage for calculate_total_usage
2026-02-18 16:16:49 -08:00
yuneng-jiangandClaude Opus 4.6 e445694a40 fix(sso): preserve SSO role regardless of role_mappings configuration
When `default_internal_user_params` was set, `insert_sso_user()` only
preserved SSO-provided roles if `role_mappings` was explicitly configured.
Roles from other valid SSO sources (Microsoft app_roles,
GENERIC_USER_ROLE_ATTRIBUTE, custom SSO handlers) were silently
overwritten with the default "internal_user" role, causing admin users
to be downgraded on first login or after user deletion.

Replace the `role_mappings_configured` gate with `_should_use_role_from_sso_response()`
which validates the role is a recognized LitellmUserRoles value regardless
of origin. Also removes an unnecessary DB round-trip to litellm_ssoconfig
on every new SSO user creation.

Fixes: admin users seeing internal-user UI after SSO login
Fixes: test_get_redirect_url_for_sso flaking due to local env vars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-18 15:24:18 -08:00
jquinterandGitHub a9058bb584 Merge pull request #21483 from BerriAI/fix/test-delattr-default-internal-user-params
fix(tests): restore default_internal_user_params instead of delattr-ing it
2026-02-18 19:07:47 -03:00
jquinterandGitHub d01adf58f5 Merge pull request #21484 from BerriAI/fix/mcp-test-isolation
fix(tests): resolve MCP test isolation failures in parallel execution
2026-02-18 19:06:59 -03:00
jquinterandGitHub b29ee632d8 Merge pull request #21481 from BerriAI/fix/enterprise-editable-install-ci
fix(ci): force-reinstall enterprise package to override PyPI version
2026-02-18 19:05:50 -03:00
yuneng-jiangandGitHub 5625fc1537 Merge pull request #21495 from BerriAI/litellm_server_root_path_non_root
[Infra] Change Server Root Path GitHub action test to non root image
2026-02-18 13:56:08 -08:00
Julio Quinteros ProandClaude Sonnet 4.6 bbbac1ae0e fix(ci): apply --force-reinstall --no-deps to enterprise install in all CI configs
The same PyPI-override issue existed in test-litellm.yml, test-mcp.yml,
and .circleci/config.yml. Also adds --no-deps (enterprise has no runtime
deps) to avoid redundant dependency resolution on every forced reinstall.

Addresses greptile review comments on PR #21481.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 18:53:45 -03:00
Julio Quinteros ProandClaude Sonnet 4.6 7b6ffbb52a fix(tests): wrap callbacks cleanup in try/finally and resolve merge conflict
- test_litellm_pre_call_utils.py: wrap test body in try/finally so
  litellm.callbacks is always restored even when an assertion fails,
  addressing greptile review comment
- test_langfuse_otel.py: resolve trivial merge conflict in comment
  ("unpatched" vs "unpatch-ed"), keeping correct spelling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 18:50:17 -03:00
jquinterandGitHub 12f5d6409c Merge pull request #21499 from BerriAI/fix/model-cost-test-contamination
fix(tests): restore litellm.model_cost after reload endpoint test
2026-02-18 18:49:11 -03:00
Julio Quinteros ProandClaude Sonnet 4.6 1c0f4302f8 fix(tests): restore litellm.model_cost after reload endpoint test
test_reload_model_cost_map_admin_access calls the /reload/model_cost_map
HTTP endpoint with get_model_cost_map mocked to return a single-entry
dict. The endpoint handler does a direct module-level assignment
(litellm.model_cost = new_model_cost_map) which persists after the
patch context manager exits, stripping all models except gpt-3.5-turbo
from the in-memory cost map and causing subsequent tests that rely on
models like gemini-1.5-flash, multimodalembedding@001, and gpt-4o to
fail with "model not mapped" errors or zero-cost spend payloads.

Fix: save litellm.model_cost before the test and restore it (along with
invalidating the case-insensitive lookup cache) in a finally block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 18:20:48 -03:00
Ishaan JaffandGitHub e8ab773ac4 fix: guard against None metadata in prometheus metrics (#21489)
* fix: guard against None metadata in prometheus metrics

Use get_litellm_metadata_from_kwargs and get_metadata_variable_name_from_kwargs
helpers to properly resolve metadata from both 'metadata' and 'litellm_metadata'
keys, with None safety.

* test: add test for None metadata in prometheus metrics
2026-02-18 12:40:45 -08:00
yuneng-jiang d1961072e8 adjusting the server root path test to non root image 2026-02-18 11:56:10 -08:00
Sameer KankuteandGitHub 69975217d2 Merge pull request #21485 from BerriAI/litellm_fix_Note
Add version in claude-code-beta-headers-incident
2026-02-18 22:55:01 +05:30
Sameer Kankute fef26cfae2 Add version in claude-code-beta-headers-incident 2026-02-18 22:54:27 +05:30
Julio Quinteros ProandClaude Sonnet 4.6 2e0a8b3cf8 fix(tests): resolve MCP test isolation failures in parallel execution
Three test isolation issues fixed:

1. test_mcp_debug.py: Replace deprecated asyncio.get_event_loop().run_until_complete()
   with asyncio.run() in TestWrapSendWithDebugHeaders. In Python 3.10+,
   get_event_loop() raises RuntimeError when no event loop is set in the
   current thread, causing test_injects_headers and test_body_messages_unchanged
   to fail in isolation.

2. test_mcp_server_manager.py: After _reload_mcp_manager_module() creates a new
   global_mcp_server_manager instance, server.py still holds a stale reference
   to the old instance. Tests in test_mcp_server.py that populate the new
   manager's registry and then call server.py functions (e.g. _get_tools_from_mcp_servers)
   get empty results because server.py reads from the old manager. Fix: update
   server.py's module-level reference after each reload.

3. test_litellm_pre_call_utils.py: test_add_litellm_metadata_from_request_headers
   sets litellm.callbacks without restoring it afterward. Add cleanup to restore
   original callbacks after the test to prevent state leaking to subsequent tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 14:08:48 -03:00
yuneng-jiangandGitHub 66a33d13a3 Merge pull request #21364 from BerriAI/litellm_ui_key_type_label
[Refactor] UI - Keys: Change Key Type Label
2026-02-18 08:54:41 -08:00
Sameer KankuteandGitHub a7da7b53f0 Merge pull request #19143 from emerzon/affinity_callback
Add deployment affinity routing callback
2026-02-18 22:21:02 +05:30
Julio Quinteros ProandClaude Sonnet 4.6 f542f92026 fix(tests): restore default_internal_user_params instead of delattr-ing it
Four finally blocks in test_internal_user_endpoints.py and one in
test_ui_sso.py used the pattern:

    if original_default_params is not None:
        litellm.default_internal_user_params = original_default_params
    else:
        delattr(litellm, "default_internal_user_params")

Since the attribute is defined in litellm/__init__.py with a default of
None, `getattr(litellm, "default_internal_user_params", None)` returns
None. The else branch then calls delattr(), permanently removing the
attribute from the module for the rest of the process.

Subsequent tests in the same pytest-xdist worker (e.g.
test_add_new_member_* in test_management_helpers_utils.py) then fail
with: AttributeError: module 'litellm' has no attribute
'default_internal_user_params'

Fix: replace all five flawed finally blocks with a simple assignment:
    litellm.default_internal_user_params = original_default_params

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 13:33:53 -03:00
Emerson Gomes 3dd55a7b61 Merge main into affinity_callback and address deployment affinity review feedback 2026-02-18 10:01:11 -06:00
Julio Quinteros ProandClaude Sonnet 4.6 262c16adf5 fix(ci): force-reinstall enterprise package to override PyPI version
poetry install includes litellm-enterprise from PyPI, then the editable
install step runs. When the same version is already installed, pip may
skip the editable install leaving the PyPI build in place - which may
lack methods added after the latest PyPI release. Adding
--force-reinstall ensures the local editable version always wins.

Fixes enterprise tests failing with AttributeError on methods that exist
locally but not in the cached PyPI-installed package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 12:02:11 -03:00
jquinterandGitHub 45d3d1adfd Merge pull request #21477 from BerriAI/fix/schema-inference-geo-property
fix(tests): add inference_geo to model prices JSON schema validator
2026-02-18 11:46:03 -03:00
jquinterandGitHub 2395734a84 Merge pull request #21479 from BerriAI/fix/prisma-json-create-many
fix(proxy): use prisma.Json for JSON fields in _rotate_master_key create_many()
2026-02-18 11:45:36 -03:00
jquinterandGitHub 63783dbfb2 Merge pull request #21478 from BerriAI/fix/vertex-rerank-merge-conflict
fix(tests): resolve merge conflict in test_vertex_ai_rerank_transformation.py
2026-02-18 11:44:53 -03:00
Julio Quinteros ProandClaude Sonnet 4.6 392bbf35b7 fix(proxy): use prisma.Json for JSON fields in _rotate_master_key create_many
Prisma's create_many() requires JSON fields to be wrapped in prisma.Json()
not passed as raw JSON strings. Lines 3099-3100 were using safe_dumps()
(which returns str) instead of prisma.Json(), causing Prisma validation
errors during master key rotation.

This is consistent with the existing pattern in the same file (line 3134
already uses prisma.Json for litellm_config env vars).

The regression test test_rotate_master_key_model_data_valid_for_prisma
was already correctly asserting isinstance(..., prisma.Json) — the test
exposed the mismatch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 11:36:15 -03:00
Harshit JainandGitHub c760318c79 Merge pull request #21449 from Harshit28j/litellm_feat_dataDog_tags
feat(datadog): add 'team' tag to logs, metrics, and cost management
2026-02-18 20:05:32 +05:30
Julio Quinteros ProandClaude Sonnet 4.6 419151dce8 fix(tests): resolve merge conflict in test_vertex_ai_rerank_transformation.py
The file had two unresolved git merge conflict markers from a merge of
litellm_oss_staging_02_17_2026 into main, causing a SyntaxError when
pytest tried to collect the test module.

Kept the instance-level mocking approach (from litellm_oss_staging) for
test_get_complete_url and test_validate_environment, which is consistent
with the rest of the file and avoids class-reference issues caused by
importlib.reload(litellm) in conftest.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 11:31:56 -03:00
Julio Quinteros ProandClaude Sonnet 4.6 d4755c8284 fix(tests): add inference_geo to model prices JSON schema
The model_prices_and_context_window_backup.json file has 'inference_geo'
fields (e.g. on 'us/claude-sonnet-4-6') for geo-prefixed Anthropic models
used in cost calculation, but the JSON schema validator in test_utils.py
did not include 'inference_geo' as an allowed property.

This caused test_aaamodel_prices_and_context_window_json_is_valid to fail
with: Additional properties are not allowed ('inference_geo' was unexpected)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 11:29:31 -03:00
jquinterandGitHub 65a79d5ed9 Merge pull request #21436 from BerriAI/fix/prisma-generate-matrix-ci
fix(ci): add prisma generate step to matrix CI workflow
2026-02-18 11:28:02 -03:00
jquinterandGitHub 34f06c4242 Merge pull request #21473 from BerriAI/fix/test-proxy-admin-expired-key-cleanup
fix(tests): restore proxy_server module attrs after test_proxy_admin_expired_key_from_cache
2026-02-18 11:22:03 -03:00
jquinterGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
0d11720586 Update tests/test_litellm/proxy/auth/test_user_api_key_auth.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-02-18 11:21:53 -03:00
Sameer KankuteandGitHub a358b7a488 Merge pull request #21475 from BerriAI/litellm_fix_mock_test
Fix mock test
2026-02-18 19:41:15 +05:30
Sameer Kankute 610bf00768 Fix:test_get_key_object_loads_object_permission 2026-02-18 19:18:15 +05:30
Sameer Kankute ee7e5437f8 Fix _rotate_master_key 2026-02-18 19:14:13 +05:30
Harshit Jain 57554833a3 fix(datadog): use .get() for safe team tag extraction 2026-02-18 18:53:39 +05:30
Sameer KankuteandGitHub c369b0f2d2 Merge pull request #21448 from BerriAI/litellm_sonnet_4_6_feat
[Feat]Add day 0 claude sonnet 4.6 feat support
2026-02-18 18:44:36 +05:30
Sameer KankuteandGitHub 3e0a72307c Merge pull request #21474 from BerriAI/litellm_incident_report_vllm
Incident Report: vLLM Embeddings Broken by encoding_format Parameter
2026-02-18 18:43:11 +05:30
Sameer KankuteandGitHub f6d3919a66 Merge branch 'main' into litellm_sonnet_4_6_feat 2026-02-18 18:40:56 +05:30
Sameer KankuteandGitHub 6f82a3ec00 Merge pull request #21456 from BerriAI/litellm_fix_delete_file_managed_access
Add File deletion criteria with batch references
2026-02-18 18:39:45 +05:30