Commit graph

10183 commits

Author SHA1 Message Date
Dmitriy Alergant
e1bf114591
fix(budget): align budget table reset times with standardized calendar schedule (#25440)
Budget table entries (team members, end-users) used duration_in_seconds()
for a sliding-window reset, while keys/users/teams used calendar-aligned
get_budget_reset_time(). This made "30d" and "1mo" mean different things
depending on entity type. Now both paths use get_budget_reset_time() for
consistent calendar-aligned resets (e.g. "30d" → 1st of next month).

Fixes #25432

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:45:23 -07:00
Utsab Dahal
e3d160f158
fix(embedding): omit null encoding_format for openai requests (#25395) 2026-04-11 19:39:19 -07:00
Darien Kindlund
17e145a083
fix(proxy): use model_group for model_max_budget spend tracking cache key (#25549)
The model_max_budget limiter tracks spend in one code path
(async_log_success_event) and enforces budget limits in another
(is_key_within_model_budget via user_api_key_auth). These two paths
used different model name formats to build cache keys:

- Tracking used standard_logging_payload["model"], which is the
  deployment-level model name (e.g. "vertex_ai/claude-opus-4-6@default")
- Enforcement used request_data["model"], which is the model group
  alias (e.g. "claude-opus-4-6")

Because the cache keys never matched, the enforcement path always read
None for current spend, silently allowing all requests through even
after the budget was exceeded. This affected any provider that decorates
model names with provider prefixes or version suffixes (Vertex AI,
Bedrock, etc.).

Fix: use model_group (the user-facing alias) from StandardLoggingPayload
for spend tracking, falling back to model when model_group is None.
This aligns the tracking cache key with the enforcement cache key.

Fixes the same root cause reported in #15223 and #10052.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:37:58 -07:00
Darien Kindlund
f54e4e664b
fix(proxy): use _hash_token_if_needed for cache invalidation in bulk update and key rotation (#25552)
Two code paths in key_management_endpoints.py call hash_token()
unconditionally when invalidating the user_api_key_cache after a key
update.  When the caller passes a pre-hashed token ID (not an sk-
prefixed key), hash_token() double-hashes it, producing a cache key
that does not match the actual cached entry.  Cache invalidation
silently fails.

This is compounded by update_cache() which writes the stale cached key
object back with a fresh 60s TTL after every successful request,
preventing natural TTL expiry.  The stale entry (with outdated fields
like max_budget=None) persists indefinitely under load.

PR #24969 fixed this in update_key_fn but missed two other call sites:
- _process_single_key_update (bulk update path)
- _execute_virtual_key_regeneration (key rotation path)

Fix: replace hash_token() with _hash_token_if_needed() in both
locations, matching the pattern already used elsewhere in the file.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:36:40 -07:00
Ishaan Jaffer
9be7b4c07c
test(advisor): add integration tests for full dispatch path, max_uses, provider bypass 2026-04-11 18:16:56 -07:00
Ishaan Jaffer
fa5258466d
test(advisor): add unit tests for max_uses=0, missing model, default fallback 2026-04-11 18:16:56 -07:00
Ishaan Jaffer
844e34b68b
test(advisor): remove live e2e test file (tests run locally via script) 2026-04-11 17:52:06 -07:00
Ryan Crabbe
3d72e2a6f3
fix(guardrails): address PR #25575 review feedback + sync kill switch with opt-out list
Renames the new per-guardrail opt-out field from `disabled_global_guardrails`
to `opted_out_global_guardrails` to eliminate the one-character collision with
the legacy `disable_global_guardrails` boolean kill switch. Adds a type guard
on the new gate so a misnamed bool can't crash the guardrail check. Filters
duplicates out of the team-edit guardrail display for legacy teams that have a
global name persisted in `metadata.guardrails` from before this PR. Drops the
unused `isGuardrailsLoading` and `guardrailsError` destructures left in
AddModelForm after the hook refactor.

Adds Python tests for the new gate behavior (root, litellm_metadata, metadata,
non-matching name, empty list, malformed bool value, opt-in coexistence) and
extends useGuardrails.test.ts to exercise the global / optional partition
logic that the rebuilt hook performs in its `select` transform.

Wires the legacy kill switch and the new opt-out list together in the team
edit form so they can never fall out of sync:

- Toggling the kill switch reactively updates the Guardrails Select via
  `onValuesChange` — switch on strips all globals from the selection, switch
  off re-adds them. Existing opt-in extras are preserved either way.
- When the switch is on, global options in the Select are individually
  disabled (greyed out) so the user can still manage opt-in guardrails but
  cannot accidentally re-enable a global the kill switch is bypassing.
- The save handler writes both fields together: `disable_global_guardrails`
  reflects the switch, and `opted_out_global_guardrails` is set to either
  every global (when the switch is on) or the user's explicit opt-outs.
- `effectiveGuardrails` for the form's initialValues honors the kill switch
  on legacy teams so the form opens in a state that matches what the runtime
  gate is actually doing — fixes the visual lie where chips appeared active
  while the switch was bypassing them.

The backend gate already reads the list as the primary path with the bool
as a fallback, so untouched legacy teams keep working until they get edited,
at which point they migrate naturally.
2026-04-11 17:48:16 -07:00
Ishaan Jaffer
742e2fe1aa
test(advisor): add live e2e tests for advisor orchestration against real proxy 2026-04-11 17:46:17 -07:00
Ishaan Jaffer
ce3d039bcd
test(advisor): add unit tests for orchestration loop (mocked backends, 8 tests) 2026-04-11 17:43:26 -07:00
Ryan Crabbe
ef38c665ca
fix(guardrails): use plural key in get_disable_global_guardrail
Rename disable_global_guardrail → disable_global_guardrails to match
the key name used by litellm_pre_call_utils.py, the API endpoints,
and the UI when propagating key/team metadata.

The singular form was introduced in PR #16983 and has never matched
the plural form written by the rest of the codebase, so the feature
silently did nothing.

Re-applies fix originally from #25488. Original commit could not be
merged due to missing signature.

Co-Authored-By: Remi Mabon <remi.mabon@redcare-pharmacy.com>
2026-04-11 17:35:50 -07:00
Yuneng Jiang
909247785e
Merge remote-tracking branch 'origin' into litellm_internal_staging_04_11_2026 2026-04-11 15:41:03 -07:00
yuneng-jiang
9a43e32d6e
Merge pull request #25464 from BerriAI/litellm_passthrough_contenttype
fix(proxy): pass-through multipart uploads and Bedrock JSON body
2026-04-11 15:40:16 -07:00
yuneng-jiang
56e82451df
Merge pull request #25458 from BerriAI/litellm_team_members_logs
Team member permission /spend/logs for team-wide spend logs (UI + RBAC)
2026-04-11 13:55:00 -07:00
ishaan-berri
da75012a50
Merge pull request #25569 from BerriAI/litellm_harish_april11
Litellm harish april11
2026-04-11 13:26:18 -07:00
Yuneng Jiang
014ec9bf8e
[Fix] test_databricks: don't assert stream in request body when not passed
Some checks failed
Unit Tests: Proxy DB Operations / proxy-db (auth-checks, tests/proxy_unit_tests/test_auth_checks.py tests/proxy_unit_tests/test_user_api_key_auth.py, 20, 8) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (key-generation, tests/proxy_unit_tests/test_key_generate_prisma.py, 30, 0) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (remaining, tests/proxy_unit_tests --ignore=tests/proxy_unit_tests/test_key_generate_prisma.py --ignore=tests/proxy_unit_tests/test_auth_checks.py --ignore=tests/proxy_unit_tests/test_user_api_key_auth.py, 30, 8) (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
The test expected "stream": false in the serialized request body, but
stream is only included in optional_params when explicitly passed by
the caller. litellm.completion() defaults stream=None which is excluded
from non_default_params. Assert individual fields instead of the full
serialized JSON to avoid brittleness around optional field inclusion.
2026-04-11 13:19:39 -07:00
Yuneng Jiang
60d20ace5b
[Fix] test_ratelimit: skip over-limit cases that race with background RPM tracking
usage-based-routing tracks RPM in log_success_event which runs in a
background ThreadPoolExecutor. The cache update races with the next
call's routing check in both sync (tight loop) and async (concurrent
gather) modes, making over-limit detection non-deterministic.

Skip the over-limit parametrization (num_try_send > num_allowed_send).
The under-limit cases (2 sent, 3 allowed) still verify the routing
strategy works. Rate-limit enforcement is properly tested with mocks
in tests/test_litellm/test_router/test_enforce_model_rate_limits.py.
2026-04-11 13:08:59 -07:00
yuneng-jiang
150c37c47d
Merge pull request #25568 from BerriAI/litellm_yj_apr_10_2026
[Infra] Merge dev with main
2026-04-11 13:03:52 -07:00
Yuneng Jiang
218daca867
[Fix] Address Greptile review: POST /organization/info auth bypass, inline imports, team access denial tests
- Add _verify_org_access to deprecated POST /organization/info endpoint
- Move get_user_object to module-level import in organization_endpoints.py
- Add tests for _verify_team_access 403 denial path
2026-04-11 12:40:55 -07:00
ishaan-berri
c70a3c7093
Merge pull request #25450 from harish876/oom-file-fix-openai
Add file content streaming support for OpenAI and related utilities
2026-04-11 12:25:36 -07:00
ishaan-berri
5cb9b087ad
Merge pull request #25545 from BerriAI/litellm_ishaan_april10
Litellm ishaan april10
2026-04-11 12:14:08 -07:00
Ishaan Jaffer
d22a07a9ba
Merge remote-tracking branch 'origin/main' into ci-fix-april6-fixes 2026-04-11 12:04:14 -07:00
harish876
69eb34597c Refactor file content streaming handling to improve routing and support
- Introduced a new method in `FileContentStreamingHandler` to resolve streaming request parameters, enhancing the routing logic based on credentials.
- Updated the `should_stream_file_content` method to check against supported providers.
- Cleaned up type hints and imports across multiple files for better organization and clarity.
- Added comprehensive tests to validate the new routing behavior and ensure original data integrity during streaming requests.
2026-04-11 18:56:15 +00:00
Yuneng Jiang
92bbf0a0d3
Merge remote-tracking branch 'origin' into litellm_oss_staging_04_09_2026 2026-04-11 11:52:42 -07:00
ryan-crabbe-berri
eabb6a31f1
Merge pull request #25542 from BerriAI/litellm_fix-timestamp
fix(spend): session-TZ-independent date filtering for spend/error log queries
2026-04-11 10:57:25 -07:00
shreyes19
f686d33408 refactor: extract _get_cors_config() for testability, fix no-op CORS tests 2026-04-11 22:24:04 +05:30
michelligabriele
363f9fe5da
fix(proxy): preserve dict guardrail HTTPException.detail + bedrock context (#25558) 2026-04-11 09:40:39 -07:00
jimmychen-p72
2fe615b373
fix(s3): add retry with exponential backoff for transient S3 503/500 errors (#25530)
* fix(s3): add retry with exponential backoff for transient S3 503/500 errors

S3 occasionally returns 503 "Slow Down" during PUT operations when
request rates spike above partition limits. The current code makes a
single upload attempt via httpx — unlike boto3, httpx has no built-in
retry for transient S3 errors. Failed uploads permanently lose the
request's audit/logging data.

Add exponential backoff retry (3 attempts, 1s/2s delays) for S3
500/503 responses in both async_upload_data_to_s3 and
upload_data_to_s3. Logs a warning on each retry with the S3 object
key for observability.

In production we observed ~18 permanent S3 upload failures per day
(124 over 7 days) — all transient 503s that would have succeeded on
a single retry.

* test(s3): add unit tests for S3 upload retry logic

Tests cover:
- Async retry on 503 (succeeds on second attempt)
- Async retry on 500
- Exhausted retries on persistent 503 (calls handle_callback_failure)
- No retry on 4xx errors (403)
- Sync retry on 503

* style(s3): move time import to module level

Address review feedback: move `import time` from inside
upload_data_to_s3 to the top-level imports per project style guide.
2026-04-11 09:39:12 -07:00
Josh
7d2f069361
Reduce default latency histogram bucket cardinality (#25527)
* feat(prometheus): reduce default latency bucket cardinality and make configurable

* test(prometheus): add coverage for PrometheusServicesLogger latency buckets

* Revert "test(prometheus): add coverage for PrometheusServicesLogger latency buckets"

This reverts commit 1bfd004ad1.

* test(prometheus): add coverage for PrometheusServicesLogger latency buckets
2026-04-11 09:34:45 -07:00
michelligabriele
c9e4949485
fix(logging): preserve proxy key-auth metadata on /v1/messages Langfuse traces (#25448)
* fix(logging): preserve proxy key-auth metadata on /v1/messages Langfuse traces

update_from_kwargs() overwrites proxy metadata (user_api_key_hash, etc.)
with Anthropic's native metadata when both exist. Merge instead of replace.

* fix(test): update stale assertion for new metadata merge semantics

* test: add explicit conflict-resolution test for metadata merge
2026-04-11 09:29:34 -07:00
shreyes19
e01fe01d35 fix: address Greptile P1 review comments 2026-04-11 21:57:03 +05:30
Sameer Kankute
d03ecedba1
feat(containers): Azure routing, managed container IDs, delete response parsing (#25287)
* feat(containers): Azure container routing, managed IDs, and delete response wire format

- Add AzureContainerConfig and safe URL joining for paths with api-version query
- Encode/decode managed container IDs in responses, streaming, and proxy handlers
- Accept OpenAI delete response object literal container.file.deleted
- Tests for Azure URL regression and DeleteContainerFileResponse parsing

Made-with: Cursor

* fix(responses): gate response id update on parsed_chunk having response

Delta stream events do not include a response body; Mock-based tests
(and any truthy synthetic .response on transforms) must not trigger
_update_responses_api_response_id_with_model_id. Fixes
test_stop_async_iteration_not_logged_as_failure (TypeError: Mock not iterable).

Made-with: Cursor

* feat(containers): encode container IDs in SDK responses for routing

- Add ContainerRequestUtils.encode_container_id_in_response utility
- Encode container_id in create/retrieve/delete responses (SDK path)
- Fix streaming iterator: gate response ID update on parsed_chunk key
- Follows responses API pattern (encode after handler, not in handler)

Made-with: Cursor

* fix(containers): module-level imports and managed cntr_ ID encoding

- Move ResponsesAPIRequestUtils imports to module scope (utils, main, handler_factory).
- Serialize absent model_id as empty segment instead of literal None; decode empty
  and legacy "None" segments as missing for router affinity.
- Add unit tests for build/decode round-trip and legacy IDs.

Made-with: Cursor

* fix(containers): decode managed IDs in endpoint_factory SDK path

- Add decode_managed_container_id_for_request in containers/utils and reuse from main.
- Strip LiteLLM cntr_ wrappers before generic_container_handler (64-char API limit).
- Resolve provider for logging/errors; add unit test for decode helper.
- Use resolved_custom_llm_provider after decode for mypy-safe provider typing.

Made-with: Cursor

* Fix p1 concern

* Fix p1 concern
2026-04-11 09:21:01 -07:00
Yuneng Jiang
83c459225c
[Fix] CI: fix GHA timeouts and uv lock --check failures
1. exclude-newer: change from absolute "2026-04-10" to relative "3 days".
   All pinned deps were published before the 3-day cutoff. Re-locked so
   uv lock --check passes in test-mcp.yml and test-linting.yml.

2. test_eager_tiktoken_load: run all 10 env var values in a single
   subprocess instead of spawning 10 separate processes. Each cold
   import litellm takes ~78s on CI, so the old loop took ~13 min on a
   single xdist worker. Now takes ~78s total.

3. proxy-db remaining timeout: increase from 20 to 30 minutes. The
   remaining group has 51 test files and was consistently timing out at
   71% across all branches (pre-existing issue, not migration-related).
2026-04-11 09:04:49 -07:00
Sameer Kankute
40d8a25df9
feat(bedrock): skip dummy user continue for assistant prefix prefill (#25419)
When modify_params is true, Bedrock Converse setup no longer prepends or
appends the default user message if the boundary assistant turn has
prefix: true, so OpenAI-style assistant prefill reaches the API unchanged.

Made-with: Cursor
2026-04-11 09:04:15 -07:00
Sameer Kankute
c13be44e44
feat(guardrails): optional skip system message in unified guardrail inputs (#25481)
* feat(guardrails): optional skip system message in unified guardrail inputs

Made-with: Cursor

* feat(dashboard): skip_system_message_in_guardrail in guardrail UI

Add a tri-state control (inherit / yes / no) when creating or editing
guardrails so admins can set litellm_params.skip_system_message_in_guardrail
without YAML. Table edit merges existing litellm_params before PUT to avoid
wiping content-filter and other provider fields.

Document the dashboard flow in the guardrails quick start with a screenshot.

Made-with: Cursor

* fix(guardrails): type structured_messages as AllMessageValues for mypy

Use AllMessageValues in openai_messages_without_system and cast adapter
request messages so GenericGuardrailAPIInputs matches TypedDict.

Made-with: Cursor
2026-04-11 08:53:24 -07:00
Sameer Kankute
dc200c34a2
fix(responses): map refusal stop_reason to incomplete status in streaming (#25498)
* fix(responses): map refusal stop_reason to incomplete status in streaming

Fixes streaming responses API translation where Anthropic's stop_reason="refusal"
was incorrectly translated to status="completed" instead of "incomplete".

Root cause: build_base_response was unconditionally overwriting finish_reason
with None from later chunks, losing the terminal content_filter value.

Changes:
- streaming_chunk_builder_utils: skip None finish_reason values in build_base_response
- streaming_iterator: snapshot chunks before returning pending events (sync path)
- streaming_handler: treat usage-only chunks as meaningful content
- transformation: map finish_reason=refusal to status=incomplete
- tests: add regression tests for refusal handling

Made-with: Cursor

* Fix test
2026-04-11 08:48:15 -07:00
shreyes19
519095bfe5 test: add structural proxy_server CORS invariant test (Greptile review feedback)
Add test_proxy_server_cors_invariant which directly imports and checks the
module-level origins and allow_cors_credentials variables in proxy_server.py.
This catches any future drift between the mirror helper and the real code.
2026-04-11 21:13:04 +05:30
shreyes19
e079ee779f fix: harden CORS, create_views exception handling, and spend log cleanup loop
- proxy_server.py: disable allow_credentials when allow_origins=['*'] (wildcard
  + credentials is a browser security misconfiguration). Add LITELLM_CORS_ORIGINS
  env var to configure explicit allowed origins.
- create_views.py: narrow broad 'except Exception' to only catch genuine
  'view does not exist' errors; re-raise all other DB errors (auth, connection,
  etc.) that were previously silently swallowed.
- spend_log_cleanup.py: validate execute_raw() return type is int before using
  it as a deletion count; break loop safely on unexpected types to prevent
  infinite deletion loops.
2026-04-11 18:58:04 +05:30
Yuneng Jiang
d9a460277a
[Fix] CI: fix uv lock resolution and tiktoken test timeout
1. Cap requires-python to <3.14 — no deps ship 3.14 wheels yet, and
   uv's cross-version resolver fails on the Python 3.14 split.
2. Change exclude-newer from relative "30 days" to absolute "2026-04-10"
   so the lockfile stays reproducible. The relative date caused
   cryptography==46.0.7 (published April 8) to fall outside the window.
3. Parametrize test_eager_loading_env_var_values instead of looping —
   with xdist the 6 subprocess cases can run in parallel instead of all
   running sequentially on one worker (~13 min → ~2 min).
   Also removed redundant case variants (Yes/YES/On/ON) that test the
   same str_to_bool code path.
2026-04-10 22:21:15 -07:00
Yuneng Jiang
09ffc87734
fix: align org and team endpoint permission checks with existing patterns
Brings organization info and team management endpoints in line with the
access-control patterns used elsewhere in the proxy.
2026-04-10 22:17:05 -07:00
Yuneng Jiang
bc05219ba9
[Fix] CI: fix helm not found and MCP tests on Python 3.9
1. check_code_and_doc_quality: install helm before running helm lint
   (Docker image cimg/python:3.11 doesn't include helm)
2. proxy_store_model_in_db_tests: skip MCP tests on Python < 3.10
   since MCP module isn't available and functions inside the
   `if MCP_AVAILABLE:` block don't exist as module-level attributes
2026-04-10 21:32:22 -07:00
Yuneng Jiang
491aa7ea51
[Fix] CI: fix 6 more CircleCI job failures from uv migration
1. check_code_and_doc_quality: add PLR0915 ignore for sandbox_executor.py
2. auth_ui_unit_tests: add prisma generate step (entrypoint.sh only runs
   migration, not client generation)
3. proxy_store_model_in_db_tests: move does_mcp_server_exist outside
   `if MCP_AVAILABLE:` so it's importable on Python < 3.10
4. build_and_test: fix datetime.fromisoformat('...Z') on Python 3.9
   (Z suffix support was added in 3.11)
5. proxy_logging_guardrails: fix container name typo my-app-2 -> my-app-3
6. upload-coverage: use `uv tool run` instead of `uv run --with` to avoid
   resolving the full workspace (which fails for Python 3.14)
2026-04-10 21:06:25 -07:00
harish876
f523ccb2fe Update import paths in tests for StorageBackendFileService
- Changed the import path for `upload_file_to_storage_backend` in test files to reflect the new module structure.
- Ensured consistency in mocking for storage backend service tests.
2026-04-11 00:07:52 +00:00
Ryan Crabbe
c7934c460d
fix(spend): session-TZ-independent date filtering for spend/error log queries
The raw SQL queries in spend_management_endpoints.py, spend_tracking_utils.py,
and analytics_endpoints.py cast date params to ::timestamptz while comparing
against the plain-timestamp "startTime" column. Postgres resolves the type
mismatch by promoting the column using the DB session timezone, which drifts
the filter window and date_trunc buckets whenever session TZ is not UTC —
silently dropping rows at UTC day boundaries and, for narrow windows, losing
rows entirely.

Wraps every such comparison with `AT TIME ZONE 'UTC'` so the param side
resolves to a plain timestamp matching the column type. Both sides end up
as plain timestamp, Postgres does no implicit conversion, and session TZ
plays no role in the query. The fix is constant-foldable so the existing
startTime index (PR #17504) remains usable.

Also marks strptime-produced datetimes as tz-aware UTC at the call sites
for intent clarity and consistency with parse_date.

Fixes #22529 (Logs page missing recent rows under non-UTC session TZ) and
the Global Usage single-day-returns-two-days symptom reported internally.
2026-04-10 17:04:52 -07:00
ishaan-berri
02b4934e87
Merge pull request #25424 from BerriAI/litellm_fix-websearch-interception-logging
fix(websearch_interception): ensure spend/cost logging runs when stream=True
2026-04-10 16:52:22 -07:00
ishaan-berri
b049aadc96
Merge pull request #25514 from milan-berri/fix/a2a-create-a2a-client-default-timeout
fix: a2a create a2a client default 60 second timeout
2026-04-10 16:51:34 -07:00
Yuneng Jiang
9a0487553d
Merge remote-tracking branch 'origin' into litellm_oss_staging_04_09_2026 2026-04-10 16:41:27 -07:00
ishaan-berri
831083b565
Merge pull request #25525 from BerriAI/feat/anthropic-advisor-tool
feat(anthropic): support advisor_20260301 tool type
2026-04-10 16:39:34 -07:00
harish876
c5d93e67f4 Enhance error handling in FileContentStreamingHandler for custom LLM provider routing
- Added validation to ensure credentials include a custom LLM provider before routing.
- Cleaned up type casting for better readability.
- Introduced a new test to verify behavior when a non-OpenAI provider is used, ensuring proper handling of streaming responses.
- Updated imports to include necessary modules for testing.
2026-04-10 23:29:44 +00:00
harish876
d1dda3d30b Enhance file content streaming handler to support custom LLM provider routing
- Updated `FileContentStreamingHandler` to utilize `custom_llm_provider` from credentials for routing.
- Added error handling for missing `custom_llm_provider` in credentials.
- Introduced new tests to validate streaming behavior with routed providers and non-OpenAI providers.
- Cleaned up imports and ensured proper type casting for improved clarity.
2026-04-10 23:29:16 +00:00