Commit graph

9968 commits

Author SHA1 Message Date
user
12fe945e7b
fix: keep skills handler FastAPI-free; fold gcs deny list into the body bouncer
Two cleanups:

* ``LiteLLMSkillsHandler.create_skill`` raised ``HTTPException`` for
  identity-less callers, importing FastAPI from a ``litellm/llms/``
  module — that violates the project rule that FastAPI lives only
  under ``proxy/``. Switch to ``ValueError`` (the same shape the rest
  of the handler uses for not-found/forbidden) and update the test.

* The proxy-auth body bouncer derived its observability ban list from
  ``_supported_callback_params`` only, missing
  ``_request_blocked_callback_params`` (where ``gcs_bucket_name`` and
  ``gcs_path_service_account`` live). Two recently-merged sibling PRs
  (#27019 added the deny list, #27081 added the test asserting these
  are rejected at the request body root) crossed without folding them
  together. Union the GCS deny list into the bouncer's derivation so
  the single source of truth covers both code paths.
2026-05-04 23:54:33 +00:00
user
abcf204d38 fix(proxy): include request-blocked callback params in auth bans 2026-05-04 16:54:04 -07:00
user
b5a14f22d6
Merge remote-tracking branch 'upstream/litellm_internal_staging' into codex/skills-containers-tenant-guard 2026-05-04 23:50:29 +00:00
user
6a3f6b47de Merge remote-tracking branch 'origin/litellm_internal_staging' into fix/strip-pricing-fields-pr27071
# Conflicts:
#	litellm/proxy/litellm_pre_call_utils.py
2026-05-04 16:45:21 -07:00
user
777862a018
Merge remote-tracking branch 'upstream/litellm_internal_staging' into codex/skills-containers-tenant-guard 2026-05-04 23:40:26 +00:00
user
758b488326
fix(ownership): reject identity-less callers instead of sharing a sentinel scope
UNSCOPED_RESOURCE_OWNER_SCOPE collapsed every caller without an
identity field (no user_id / team_id / org_id / api_key / token) into
a single shared owner — a cross-tenant access primitive: any two such
callers could see and delete each other's containers and skills.

Drop the sentinel. ``get_primary_resource_owner_scope`` returns
``None`` and ``get_resource_owner_scopes`` returns ``[]`` for
identity-less callers. ``record_container_owner`` and
``LiteLLMSkillsHandler.create_skill`` now reject creates from
identity-less callers with a 403 instead of stamping the placeholder.
Read paths already deny ``owner is None`` correctly so legacy rows
(if any) are admin-only.
2026-05-04 23:40:22 +00:00
user
de682c810e
chore(container,skills): drop legacy-access opt-out env vars
LITELLM_ALLOW_UNTRACKED_CONTAINER_ACCESS and
LITELLM_ALLOW_UNOWNED_SKILL_ACCESS were operator-toggleable opt-outs
for the cross-tenant access primitive this PR closes — flipping either
on re-enabled exactly the VERIA-20 read path. Default-secure with no
escape hatch matches sibling fixes (vector-store cred isolation, semantic
cache key isolation, user_config strip): all rejected the
opt-out-of-security pattern.

Untracked containers and unowned skills (rows that pre-date this
enforcement) are admin-only. Non-admin owners need to either re-create
via the now-tracked flow or have an admin assign ``created_by`` on the
existing row. Update tests to assert the strict-only behaviour.
2026-05-04 23:22:19 +00:00
yuneng-jiang
07824b5eec
Merge pull request #26990 from stuxf/codex/semantic-cache-tenant-isolation
chore(caching): isolate semantic cache entries
2026-05-04 16:02:43 -07:00
yuneng-jiang
0c0b5e005f
Merge pull request #27082 from stuxf/fix/vector-store-cred-leak
fix(vector_store): resolve embedding config at request time, never persist creds
2026-05-04 15:55:40 -07:00
user
ec9b84d38c
chore(container,skills): LRU eviction for owner caches; widen file_purpose Literal
Two cleanups from the /simplify pass:

* ``_CONTAINER_OWNER_CACHE`` and ``_SKILL_CACHE`` now LRU-evict via
  ``OrderedDict.popitem(last=False)`` instead of full ``clear()`` at
  capacity. Full clears converted a steady-state cached workload into a
  periodic full-DB-load oscillation as the cache repopulated from zero
  and cleared again. Reads now ``move_to_end`` so the just-touched
  entry survives the next eviction. Mirrors the pre-existing LRU
  pattern in ``_remember_container_owner``.

* ``LiteLLM_ManagedObjectTable.file_purpose`` Literal now includes
  ``"container"`` so Pydantic validation accepts rows written by the
  ownership store.
2026-05-04 22:52:54 +00:00
yuneng-jiang
e4ac46b5d1
Merge pull request #27081 from stuxf/fix/strip-callback-fields
chore(proxy): close callback-config and observability-credential side channels
2026-05-04 15:45:42 -07:00
user
a2473ef0c2
chore(caching): remove allow_legacy_unscoped_cache_hits opt-in
The flag was an opt-in escape hatch for the cross-tenant leak the rest
of the patch closes — flipping it on (env var or constructor param)
re-enables exactly the VERIA-54 primitive on either backend. There is
no operational need that the secure path doesn't already meet:

- Qdrant: legacy points without ``litellm_cache_key`` payload are
  excluded by the must-clause filter and treated as misses; new sets
  populate the cache key, so cold-start lasts only as long as the
  natural cache rebuild.
- Redis: existing unscoped index can't carry the new schema; the init
  path falls back to ``{name}_isolated`` (and recreates it on stale
  schema), leaving the legacy index untouched.

Drop the constructor param, env-var fallback, ``_using_legacy_unscoped_index``
flag, the legacy-reuse branch in ``_init_semantic_cache``, and the
matching guards in set/get paths. Update tests to drop the legacy-mode
cases and assert the secure-only behaviour.
2026-05-04 22:16:30 +00:00
Yassin Kortam
f9ae559c1e
Merge pull request #27022 from BerriAI/litellm_fix/routing-strategy-model-filter
feat: selectively apply routing strategy according to model name
2026-05-04 15:06:22 -07:00
Michael-RZ-Berri
1a17c438b6
Merge pull request #27133 from BerriAI/litellm_zeroBudgetTreatedAsNoCap
[Fix] Treat 0 team_member_budget as no cap
2026-05-04 15:05:18 -07:00
yuneng-jiang
2aa4301fe7
Merge pull request #27027 from stuxf/fix/mcp-server-url-redact-non-admin
fix(proxy): redact MCP server URL and headers for non-admin viewers (VERIA-8)
2026-05-04 15:05:05 -07:00
yuneng-jiang
07807f760f
Merge pull request #27019 from stuxf/codex/cloud-storage-file-guard
fix(files): constrain cloud storage file paths (VERIA-45, VERIA-59)
2026-05-04 14:59:47 -07:00
Mateo Wang
196dbb4b43
Merge pull request #27074 from BerriAI/litellm_fix_reasoning_effort_followup-0f97
fix(anthropic,bedrock,vertex): forward output_config.effort + 400 on garbage reasoning_effort
2026-05-04 14:59:27 -07:00
yuneng-jiang
e1083b1353
Merge pull request #27014 from stuxf/fix/activity-endpoint-tenant-scoping
fix(proxy): scope team and agent activity endpoints per-entity (VERIA-43)
2026-05-04 14:51:45 -07:00
yuneng-jiang
6f5678bcd8
Merge pull request #27007 from stuxf/fix/admin-viewer-write-route-blocklist
fix(auth): block missing write routes for proxy admin viewers
2026-05-04 14:45:14 -07:00
Michael Riad Zaky
28bf4647ef Treat 0 team_member_budget as no cap 2026-05-04 14:45:13 -07:00
user
af7794272b Add semantic cache legacy migration flag 2026-05-04 14:42:53 -07:00
yuneng-jiang
e995156462
Merge pull request #26953 from stuxf/chore/audit-log-cache-vault-settings
chore(audit): audit-log /cache/settings + /config_overrides/hashicorp_vault mutations
2026-05-04 14:42:23 -07:00
yuneng-jiang
c38e23e6d3
Merge pull request #26915 from stuxf/codex/provider-url-destination-guard
chore(providers): guard URL-valued model destinations
2026-05-04 14:38:37 -07:00
yuneng-jiang
c064170a18
Merge pull request #26819 from stuxf/fix/team-callback-idor
chore(team): require team-management role on /team/{id}/callback endpoints
2026-05-04 14:31:59 -07:00
user
abbefccad4
fix(guardrails): align banned_keywords + azure_content_safety call_type gates with runtime route_type
The hooks gated on ``call_type == "completion"`` but the proxy ingress
passes ``route_type`` straight through as ``call_type`` —
``"acompletion"`` for /v1/chat/completions and ``"aresponses"`` for
/v1/responses. Tests passed because they used the literal sync
``"completion"`` value, masking the gap.

Switch both hooks to ``is_text_content_call_type`` (matches the
canonical runtime values: completion / acompletion / aresponses) and
update existing tests to assert against runtime values, plus parametrize
a regression test that pins the gate.
2026-05-04 21:27:24 +00:00
user
9f1feaadeb Clean up Redis semantic cache isolation fallback 2026-05-04 14:23:31 -07:00
yuneng-jiang
285e103db4
Merge pull request #27126 from stuxf/codex/dependency-refresh-2026-05-04
chore(deps): refresh dependency locks
2026-05-04 14:23:22 -07:00
harish-berri
f79d3fae2d
Merge pull request #26902 from BerriAI/litellm_pyroscope_tag_wrapper
feat(proxy): add support for Grafana Cloud Pyroscope authentication
2026-05-04 14:08:17 -07:00
Yassin Kortam
516b741de1 feat: selectively apply routing strategy according to model name 2026-05-04 13:27:32 -07:00
user
0f02a5f8f6 test: keep decode token test local 2026-05-04 13:14:59 -07:00
Cursor Agent
2cb3f0f027
refactor: remove unnecessary comments from #27074
Strip out the explanatory and historical comments that don't carry
business-logic justification. Comments that simply narrate what code
does — or that explain prior behavior, what was changed, or which PR
introduced a fix — are removed. Docstrings are reduced to a one-line
summary where the long form repeated information already evident from
the code or test data.

No code-behavior changes. All 643 affected unit tests still pass.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-04 19:34:56 +00:00
Cursor Agent
56070b86a3
test(model_prices): add supports_adaptive_thinking to schema
`test_aaamodel_prices_and_context_window_json_is_valid` validates the
model-map JSON against an explicit schema with `additionalProperties`,
so the new `supports_adaptive_thinking` flag added in
98ced0ae43 needs a matching schema entry.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-04 19:11:45 +00:00
user
e96d850b84 chore(deps): address dependency review notes 2026-05-04 12:09:04 -07:00
user
7c94149aeb Merge remote-tracking branch 'origin/litellm_internal_staging' into codex/cloud-storage-file-guard
# Conflicts:
#	litellm/llms/vertex_ai/files/handler.py
#	litellm/llms/vertex_ai/files/transformation.py
2026-05-04 11:25:41 -07:00
user
a05d3b5851 Fix qdrant semantic cache miss metadata 2026-05-04 11:18:41 -07:00
harish-berri
ed3b056bc8 Implement normalize_nonempty_secret_str function to trim whitespace from secrets and treat empty values as unset. Update proxy_server to use this function for Grafana credentials. Enhance tests to validate the new normalization behavior. 2026-05-04 18:17:31 +00:00
Mateo Wang
790d8bbe1a
Merge pull request #26899 from BerriAI/litellm_suppress-spend-log-tracebacks-2208
feat(spend-logs): opt-in suppression of stack traces in spend-tracking error logs
2026-05-04 11:09:03 -07:00
mateo-berri
c1708ddbba fix(xai): fold reasoning_tokens into completion_tokens to satisfy OpenAI invariant
xAI's chat completions API accounts reasoning_tokens separately from
completion_tokens, but rolls them into total_tokens. This breaks the
OpenAI invariant total_tokens == prompt_tokens + completion_tokens
that downstream consumers (including litellm's own _usage_format_tests
in tests/llm_translation/base_llm_unit_tests.py:58) rely on.

Live capture (grok-3-mini-beta, 2026-05-04):
    prompt=14, completion=10, total=336, reasoning=312
    14 + 10 = 24, NOT 336.

OpenAI's o1/o3 reasoning models include reasoning_tokens in
completion_tokens, leaving the prompt+completion=total invariant
intact. xAI deviates. This patch aligns xAI to OpenAI semantics by
folding reasoning_tokens into completion_tokens after the parent
OpenAI parser runs.

The fold is idempotent and defensive:
- Only fires when total_tokens == prompt_tokens + completion_tokens
  + reasoning_tokens (the documented xAI shape). Refuses to fold if
  the gap doesn't match, guarding against silent corruption when xAI
  changes accounting.
- Skips if completion_tokens already covers the gap (already
  normalised — e.g. cost calc replays a previously-folded Usage).

xai.cost_calculator.cost_per_token already added reasoning_tokens to
the visible completion count for billing. Post-fold the Usage block
now satisfies that invariant directly, so the cost calc would
double-bill. Updated cost_per_token to detect the OpenAI-normalised
shape (total == prompt + completion) and skip the reasoning add-on
in that case, falling through to the legacy raw-shape behaviour for
callers that bypass the transformation (e.g. proxy log replay).

Tests:
- Adds TestXAIReasoningTokenFolding covering: gap-explained-fold,
  idempotent-no-double-fold, no-reasoning-skip, gap-mismatch-skip.
- Adds test_already_normalised_usage_does_not_double_count_reasoning
  to lock the cost-calc idempotency.
- Updates 7 pre-existing cost-calc tests whose total_tokens was
  internally inconsistent (used the OpenAI-normalised total but kept
  reasoning_tokens external) to use the documented xAI raw shape
  total = prompt + visible completion + reasoning. Pre-existing
  values masked the missing-fold by accident.

Verified end-to-end against the live xAI API:
    LITELLM_LOCAL_MODEL_COST_MAP=False (CI default) +
    XAI_API_KEY set +
    pytest tests/llm_translation/test_xai.py::TestXAIChat::test_prompt_caching
        -> PASSED in 18.81s (was: AssertionError on
        usage.total_tokens == usage.prompt_tokens + usage.completion_tokens)

20/20 tests in tests/test_litellm/llms/xai/test_xai_cost_calculator.py
and 8/8 in tests/test_litellm/llms/xai/test_xai_chat_transformation.py
pass.
2026-05-04 10:34:31 -07:00
harish-berri
a470309c3b Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_pyroscope_tag_wrapper
merge parent
2026-05-04 17:17:49 +00:00
Michael-RZ-Berri
675e49ed94
Merge pull request #26894 from BerriAI/litellm_langsmithRedactApiInfo
[Fix] Remove unwanted metadata info from LangSmith
2026-05-04 09:55:59 -07:00
mateo-berri
f4d6d5953d test(anthropic/chat): force PR-local model_cost map via autouse fixture
CI runs without LITELLM_LOCAL_MODEL_COST_MAP=True, so litellm.model_cost
is loaded from main-branch JSON (default model_cost_map_url) instead of
the PR's checked-out model_prices_and_context_window.json. Tests that
assert per-model flags added in this PR (supports_max_reasoning_effort,
supports_xhigh_reasoning_effort) therefore pass locally but fail in CI
with 'AssertionError: assert False is True' on 5 cases:

  - test_anthropic_model_supports_effort_param_recognizes_supporting_models
    [anthropic.claude-mythos-preview, bedrock/.../mythos-preview,
     claude-opus-4-5-20251101]
  - test_supports_effort_level_handles_provider_prefixes
    [bedrock/invoke/us.anthropic.claude-sonnet-4-6-max-True,
     claude-sonnet-4-6-max-True]

Add an autouse fixture at tests/test_litellm/llms/anthropic/chat/conftest.py
that monkey-patches litellm.model_cost to the PR-local JSON for every test
in this directory. The parent conftest already snapshots+restores
litellm.model_cost per-function, so the mutation is contained.

This is a scoped workaround. The proper fix is to set the env var
globally in the test workflow once the ~10 inline self-set test files
are audited; tracking that as a follow-up issue.
2026-05-04 09:26:57 -07:00
Sameer Kankute
32a5e77adf
feat(proxy): add health_check_reasoning_effort for model health checks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 17:13:01 +05:30
mateo-berri
f8f07c5cb7 refactor(anthropic): extract _validate_effort_for_model to prevent drift
The chat completion path (`_apply_output_config`) and the /v1/messages
pass-through (`AnthropicMessagesConfig._translate_reasoning_effort_to_anthropic`)
both gate `max` / `xhigh` per model. The two sites had diverged from
near-identical copies into separately maintained blocks, creating a real
drift risk when a new model tier (e.g. Claude 4.8) lands -- a contributor
could update one site and miss the other.

Centralise the gating in `AnthropicConfig._validate_effort_for_model`,
which returns an error message string or `None`. Each call site keeps
its own provider-appropriate exception type (`BadRequestError` for the
chat path, `AnthropicError` for the /v1/messages pass-through) but the
gating decision now comes from one place. Net -11 LOC.

Adds a parametrised unit test exercising the helper directly across
4.5 / 4.6 / 4.7 model families and `max` / `xhigh` / lower-effort
inputs. Existing tests at both call sites continue to pass unchanged.

Addresses Greptile finding on PR #27074.
2026-05-04 00:47:55 -07:00
mateo-berri
4f9a3a5c9f fix(azure_ai/anthropic): promote output_config out of extra_body so validation runs
`azure_ai` is registered in `litellm.openai_compatible_providers`, so
`add_provider_specific_params_to_optional_params` (litellm/utils.py)
auto-stuffs any non-OpenAI kwarg (e.g. `output_config={"effort": "..."}`)
into `optional_params["extra_body"]`. `AzureAnthropicConfig.transform_request`
then strips `extra_body` entirely on the way out, silently dropping the
param — and `AnthropicConfig._apply_output_config` never sees it, so
`effort="invalid"` / `effort="xhigh"` on a non-supporting model
quietly reaches the model with default behavior instead of returning a
clean 400 (as the native `anthropic` provider does).

Promote the keys back to top-level `optional_params` (using `setdefault`
so explicit top-level values win) before delegating to the parent
`AnthropicConfig`. Apply in both `validate_environment` and
`transform_request` so flag detection (`is_mcp_server_used`, etc.) and
output-config validation both run.

Surfaced by the QA matrix expansion on PR #27074: 20 cells where Azure
returned 200 while `anthropic` returned 400 — all `output_config` mode
across haiku_4_5, sonnet_4_5, opus_4_5, sonnet_4_6, opus_4_6, opus_4_7
families with `effort` in {invalid, xhigh, max, low, medium, high}.

Tests:
* `test_output_config_promoted_from_extra_body`: valid effort reaches data
* `test_invalid_output_config_effort_raises_via_extra_body`: 400 on bad effort
* `test_unsupported_effort_xhigh_raises_via_extra_body`: 400 on xhigh-on-Sonnet-4.6
* `test_extra_body_promotion_does_not_clobber_top_level`: setdefault semantics
2026-05-03 23:49:01 -07:00
Sameer Kankute
87cf5107e1
test(azure): exercise image gen JSON filter via HTTP client; dedupe image edit URL
- Image generation tests patch HTTPHandler.post / get_async_httpx_client so
  make_*_azure_httpx_request runs and wire json is asserted on call kwargs.
- Azure image edit: strip model in finalize_image_edit_multipart_data using the
  same URL string the handler passes to POST (no second get_complete_url in
  transform). BaseImageEditConfig default finalize is a no-op.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 12:09:05 +05:30
Sameer Kankute
766b67cf0d
fix(azure): omit model from image generation and image edit deployment requests
Azure OpenAI routes image gen/edit by deployment in the URL; sending the
deployment id in model breaks gpt-image-2 (invalid_value). Strip model from
JSON for deployments/.../images/generations and from multipart data for
.../images/edits. Non-deployment URLs (e.g. Azure AI FLUX) unchanged.

Fixes #26316.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 11:52:52 +05:30
mateo-berri
108b87fb24 fix(anthropic,bedrock,databricks): four reasoning_effort follow-ups
- claude-sonnet-4-6 + reasoning_effort=max no longer 400s. Renamed
  _is_opus_4_6_model to _is_claude_4_6_model at three sites and added
  supports_max_reasoning_effort: true to 12 model entries in the JSON
  cost map (10 sonnet 4.6 ids + OpenRouter opus 4.6/4.7).
- _map_reasoning_effort now raises BadRequestError(400) directly with
  llm_provider, instead of letting Databricks (and similar callers)
  surface its raw ValueError as a 500.
- output_config.effort on Opus 4.5 over Bedrock no longer 400s for
  missing effort-2025-11-24 beta. Flipped JSON to "effort-2025-11-24"
  for bedrock + bedrock_converse and added an auto-attach branch in
  _process_tools_and_beta for non-adaptive Anthropic + output_config
  on Converse.
- reasoning_effort=xhigh / =max on legacy budget-mode models
  (Haiku 4.5, Sonnet 4.5, Opus 4.5) now map to thinking.budget_tokens
  8192 / 16384 instead of returning 400. Added two constants in
  litellm/constants.py.

Tests updated for all four flips. Validated end-to-end via 306-cell
live proxy matrix (6 model families x 3 routes x 17 effort cases),
all pass.
2026-05-03 10:03:53 -07:00
mateo-berri
36f1f13925
fix(anthropic): drive output_config.effort support from model map flags
Replace hardcoded _EFFORT_SUPPORTING_MODEL_PATTERNS with a JSON-backed
check that uses supports_*_reasoning_effort flags from the model map.
Add supports_minimal_reasoning_effort: true to opus-4-5 and mythos-preview
entries (which previously only carried supports_reasoning) so the JSON
remains the single source of truth for effort capability.
2026-05-03 11:47:19 +00:00
Claude
09d37db8d9 feat(anthropic,bedrock): strip output_config under drop_params for non-effort models
When a proxy fronts Claude Code (which always sends `output_config.effort`)
at a pre-4.5 Anthropic model — haiku-3, sonnet-3.5, opus-3, sonnet-4 — the
forwarded knob causes a forced 400 the client can't fix. Gating a strip
behind the existing `drop_params` flag lets operators opt into silent
fixup once and stop worrying about per-model param hygiene.

Default (`drop_params=False`) still forwards and surfaces the provider's
error, preserving the strict, debuggable contract from #27074.

Per https://platform.claude.com/docs/en/build-with-claude/effort the
supporting set is Opus 4.5+, Sonnet 4.6+, and Mythos Preview; everything
else is dropped (with a verbose_logger warning so the strip is visible).
Recognition uses model-name patterns plus a fallback to any
`supports_*_reasoning_effort` flag in the model map for forward
compatibility with new entries.

https://claude.ai/code/session_01WjHq31rvXT6xYNdVmSJvRp

(cherry picked from commit 1233943e78)
2026-05-03 04:18:50 -07:00
mateo-berri
82d7405c6f fix(anthropic): stop class-attr leak; gate xhigh/max on every route
The reasoning-effort mapping dict was a public class attribute on
AnthropicConfig, so BaseConfig.get_config returned it as a request
parameter and every Anthropic-backed call (Anthropic / Azure / Vertex /
Bedrock Invoke) hit a 400 'REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT:
Extra inputs are not permitted' from the provider. Move the mapping
to a module-level constant.

_supports_effort_level only looked the model up under
custom_llm_provider='anthropic', so bedrock-prefixed model ids
(e.g. bedrock/invoke/us.anthropic.claude-opus-4-7) returned False
for both 'max' and 'xhigh' even when the underlying model entry has
the flag set. Strip known provider prefixes and retry the lookup
against litellm.model_cost directly so per-model gating works on
every route.

Mirror the per-model xhigh/max gate from
AnthropicConfig._apply_output_config in
AnthropicMessagesConfig._translate_reasoning_effort_to_anthropic so
the /v1/messages route also raises a clean 400 instead of forwarding
the unsupported tier.
2026-05-03 04:18:50 -07:00