Commit graph

44741 commits

Author SHA1 Message Date
mateo-berri
b97d5e77eb fix(model_prices): raise bedrock_mantle gpt-5.5 and gpt-5.4 max_input_tokens to Mantle's enforced 1050000 2026-08-26 10:42:00 -07:00
Mateo Wang
cdb60af024
Merge pull request #38269 from BerriAI/litellm_together_structured_outputs
fix(together_ai): fail open on response_format instead of dropping it for unregistered models
2026-08-26 09:34:56 -07:00
Mateo Wang
c81ceba431
Merge pull request #38232 from BerriAI/litellm_e2e_bedrock_customer_matrix
test(e2e): cover the Bedrock provider-feature cells customers run
2026-08-26 09:34:07 -07:00
ryan-crabbe-berri
597b4bb239
Merge pull request #38327 from BerriAI/litellm_tiered_pricing_rate_fallbacks
test(cost-calc): pin the rate fallbacks inside a tiered-pricing tier
2026-08-26 09:20:56 -07:00
Mateo Wang
40423e6ec0
Merge pull request #38325 from BerriAI/litellm_fix_responses_id_stream_route
fix(proxy): encrypt streamed responses ids on /openai/v1/responses and /responses aliases
2026-08-26 02:38:24 -07:00
Mateo Wang
4185c8af07
Merge pull request #38320 from BerriAI/litellm_passthrough_object_ownership
fix(passthrough): record ownership of streamed responses under managed ids
2026-08-26 02:15:12 -07:00
mateo-berri
95f8373e3c test(responses): drive streamed-id regression via production ResponseCompletedEvent shape
The streamed-id regression test built a bare BaseLiteLLMOpenAIResponseObject with a
top-level id, hitting the wrong _encrypt_response_id branch. A real streamed create
emits ResponseCompletedEvent, whose client-visible id lives on event.response.id, so
the test now drives that production event shape and reads collected[0].response.id.
Mutating the alias route gate or disabling the .response.id encryption branch both
fail the test.
2026-08-26 01:52:01 -07:00
Yuneng Jiang
54cbc44705
test(cost-calc): pin the rate fallbacks inside a tiered-pricing tier
_get_tiered_base_costs documents that tiered pricing is all-or-nothing: a
tier is picked from the request's input tokens, and any rate that tier does
not declare falls back to the tier's own input rate so one request is never
priced from two tiers.

Nothing checked that. Every existing tiered test supplies a fully populated
tier, so the fallbacks were never reached: deleting them from the source
left the whole suite green. The fallbacks are not hypothetical either. Of
the 66 tiered rows shipped in model_prices_and_context_window.json, 54
declare no cache-creation rate and 44 declare no cache-read rate, so the
fallback is what prices their cached tokens today.

Adds three tests on the generic path:
  - a tier with no cache rates bills cached and cache-creation tokens at
    that tier's input rate, ignoring the model's top-level cache rates
  - a tier with no above-1hr rate bills 1h cache writes at the tier's
    cache-creation rate rather than zero
  - a tier with no input rate is not a priced tier at all, so the model's
    flat rates still apply instead of billing input at zero

Test-only change, no source touched.
2026-08-26 01:46:29 -07:00
Mateo Wang
5640e7c9dd
Merge pull request #38318 from BerriAI/litellm_fix_branchless_provider_status_mapping
fix(exceptions): map upstream status codes for providers with no exception_type branch
2026-08-26 01:46:25 -07:00
mateo-berri
498ba9dd62 fix(proxy): encrypt streamed responses ids on /openai/v1/responses and /responses aliases
The streaming security hook only encrypted response ids when request_route
matched "/v1/responses" exactly, so streamed creates on the /openai/v1/responses
and /responses aliases leaked the plain managed id. A second virtual key could
GET, continue, and DELETE another key's response. Normalize the route (strip the
provider prefix, accept the /responses alias) before gating, mirroring the
non-streaming hook which has no route gate.
2026-08-26 01:38:13 -07:00
mateo-berri
6a9662a5a8 fix(passthrough): recognize CR-only SSE frame delimiters when minting streamed managed ids 2026-08-26 01:36:18 -07:00
mateo-berri
6386a68c9c fix(router): fail fast on PermissionDeniedError with a single deployment 2026-08-26 01:09:14 -07:00
mateo-berri
e0c101b4da fix(passthrough): record ownership of streamed responses under managed ids 2026-08-26 01:05:15 -07:00
mateo-berri
910c41f154 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_branchless_provider_status_mapping
# Conflicts:
#	tests/test_litellm/litellm_core_utils/test_exception_mapping_utils.py
2026-08-26 00:55:42 -07:00
Mateo Wang
137311ffd6
Merge pull request #38310 from BerriAI/litellm_fix_anthropic_messages_error_mapping
fix(otel): map /v1/messages provider errors before failure logging
2026-08-26 00:49:17 -07:00
mateo-berri
53037c34ed fix(exceptions): map upstream status codes for providers with no exception_type branch 2026-08-26 00:47:28 -07:00
mateo-berri
5cfc1608f9 fix(anthropic): map only provider failures on the /v1/messages boundary 2026-08-26 00:31:18 -07:00
Mateo Wang
ef8eb98724
Merge pull request #38314 from BerriAI/litellm_together_e2e_replay_hardening
test(e2e): let the Together replayed-reasoning case survive a single provider miss
2026-08-26 00:30:01 -07:00
mateo-berri
be9c170156 test(e2e): let the Together replayed-reasoning case survive a single provider miss 2026-08-26 00:14:32 -07:00
mateo-berri
3fe65029bf fix(exceptions): map anthropic 403 to PermissionDeniedError
Now that /v1/messages routes provider failures through exception_type, an
Anthropic permission_error fell through the anthropic branch to the generic
APIConnectionError and reached the client as a 500 where the raw exception
used to answer 403. Map 403 to PermissionDeniedError so the status survives
on every route.
2026-08-26 00:09:10 -07:00
mateo-berri
d17c501e98 Merge origin/litellm_fix_anthropic_messages_error_mapping, keeping exception_type unchanged
Bugbot Autofix pushed e2e16d7e2d to split 403 out of the shared 401/403 branch in _map_openai_like_exception. That premise was the BaseLLMException fallback, which d2e4e74685 already removed, and remapping 403 for every openai-like provider is a separate contract change, so this merge resolves both files back to the base branch versions
2026-08-25 23:56:20 -07:00
mateo-berri
d2e4e74685 fix(otel): drop the generic BaseLLMException fallback from exception_type
The fallback mapped every unbranched provider error by status code on every route, which changed the exception class and HTTP status for those providers and failed four provider test suites in CI. The /v1/messages handler change alone covers the ticket, since the anthropic branch already maps its errors
2026-08-25 23:52:30 -07:00
Cursor Agent
e2e16d7e2d
fix(exceptions): map 403 to PermissionDeniedError in openai-like mapper 2026-08-26 06:51:33 +00:00
mateo-berri
666648d58c fix(otel): map /v1/messages provider errors before failure logging 2026-08-25 23:31:05 -07:00
mphilippnv
e52f05566d
feat(prometheus): configure deployment caller identity (#38221)
* feat(prometheus): configure deployment caller identity

* test(prometheus): satisfy strict caller identity lint

* fix(prometheus): align caller identity on latency metrics

* fix(prometheus): validate caller identity mode before collectors register

Fail config load on an invalid prometheus_deployment_and_latency_caller_identity
value (including null) and on include_labels entries the selected mode removes
from a target metric, instead of booting green with an empty /metrics.
Validate the mode at the top of PrometheusLogger.__init__ so an invalid value
raises before any collector lands in the process-global registry, keeping
retries free of duplicated-timeseries errors. Label-validation errors now name
the mode setting alongside the rejected label.

---------

Co-authored-by: Mark Philipp <mphilipp622@gmail.com>
Co-authored-by: Yucheng Zhu <yucheng@berri.ai>
2026-08-25 23:06:02 -07:00
yuneng-jiang
14ead1b8bf
Merge pull request #38302 from BerriAI/litellm_strip_forwardref_from_cli_primitives
refactor(ui): re-pull label, textarea, separator and skeleton from the registry
2026-08-25 23:05:37 -07:00
Yuneng Jiang
d2aea2d4e7
refactor(ui): re-pull label, textarea, separator and skeleton from the registry
These four primitives still wrapped their body in React.forwardRef, which
the dashboard has not needed since it moved to React 19: a function
component receives ref as an ordinary prop and the existing {...props}
spread already hands it to the DOM node.

Re-pulling each from base-vega drops the wrapper and its displayName.
These four were picked because the ref plumbing is their only divergence
from current upstream, so the class strings, data-slot values and exports
are untouched and nothing renders differently. The other seven primitives
that still carry forwardRef have also drifted on their class strings, so
re-pulling them would ship a visual change alongside the cleanup and they
are left alone here.

Textarea is the one with real ref call sites, roughly seventeen of them
through react-hook-form's field.ref, and ref-forwarding.test.tsx did not
cover it. Add that case next to the Label, Separator and Skeleton ones
already there.
2026-08-25 22:56:59 -07:00
yuneng-jiang
e300822483
Merge pull request #38300 from BerriAI/litellm_/notion-docs-search-1e4443
refactor(ui): install the shadcn alert primitive
2026-08-25 22:47:55 -07:00
Yuneng Jiang
a5b6f31585
refactor(ui): install the shadcn alert primitive
components/shared/Alert.tsx was base-vega's own alert.tsx copied in by
hand, carrying the same four exports and the same class strings, so
npx shadcn add could never reach it and it would drift from every
upstream fix silently. It also still wrapped each part in forwardRef,
which React 19 no longer needs.

Install the primitive into components/ui/ where the CLI can update it,
and reduce the shared file to a wrapper that adds the four status
variants (info, success, warning, error) the dashboard actually uses on
top of upstream's default and destructive.

Rendered output is unchanged: every variant produces byte-identical
classes, role and data-variant, so all 45 call sites look the same.
2026-08-25 21:24:07 -07:00
Mateo Wang
3e2927de9a
Merge pull request #38296 from BerriAI/litellm_fix_otel_provider_error_stack_trace
Some checks are pending
Postgres Tests / proxy-behavior (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests / integrations (push) Waiting to run
Unit Tests / All Other Providers (push) Waiting to run
Unit Tests / Vertex AI (push) Waiting to run
Unit Tests / misc (push) Waiting to run
Unit Tests / caching-local (push) Waiting to run
Unit Tests / core-utils (push) Waiting to run
Unit Tests / enterprise-package (push) Waiting to run
Unit Tests / enterprise-routing (push) Waiting to run
Unit Tests / proxy-auth (push) Waiting to run
Unit Tests / proxy-endpoints (push) Waiting to run
Unit Tests / proxy-extras (push) Waiting to run
Unit Tests / proxy-infra (push) Waiting to run
Unit Tests / proxy-server (push) Waiting to run
Unit Tests / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
fix(logging): keep tracebacks for provider-originated 4xx errors
2026-08-25 21:15:14 -07:00
mateo-berri
514cae1b3d fix(logging): keep the proxy's own budget rejection an expected client error
The auth handler stamps the requested model's provider onto BudgetExceededError before logging it, which made a key-over-budget 429 look provider-originated and regain its traceback (and an OTel stack_trace) after the provider 4xx carve-out. Any exception whose unified rate-limit category names litellm's own limiter is now a proxy rejection, matching the HTTPException rule.
2026-08-25 20:51:55 -07:00
mateo-berri
a6e1708e6c fix(logging): keep proxy-side rate limits as expected client errors
ProxyRateLimitError derives from HTTPException but carries an llm_provider,
so it read as provider-originated and regained its traceback. Any
HTTPException is a proxy rejection regardless of llm_provider.
2026-08-25 20:30:44 -07:00
mateo-berri
ac6deec529 fix(logging): keep tracebacks for unmapped provider exceptions too
The /v1/messages route logs the provider's raw BaseLLMException, which carries
no llm_provider, so its 4xx still counted as an expected client error and lost
its traceback. Treat BaseLLMException as provider-originated as well.
2026-08-25 20:25:38 -07:00
Mateo Wang
273b01af6c
Merge pull request #38286 from BerriAI/litellm_together_e2e_coverage
test(e2e): cover Together AI reasoning, tool calls, template kwargs, and cost through a live proxy
2026-08-25 20:16:31 -07:00
mateo-berri
68f5cbd522 fix(logging): keep tracebacks for provider-originated 4xx errors
is_expected_client_error treated every HTTP 4xx as a rejection the proxy
issued itself, so a 401 or 429 the provider returned lost its traceback in
the standard logging payload and the OTel error span dropped
litellm.provider.error.stack_trace. An exception carrying llm_provider is
an upstream or deployment problem and keeps its traceback; the proxy's own
pre-call rejections still skip it
2026-08-25 20:09:31 -07:00
yuneng-jiang
72b8b47ee8
bump: litellm-enterprise 0.1.59 -> 0.1.60, litellm 1.99.0 -> 1.100.0 (#38243) 2026-08-25 19:44:45 -07:00
Deepanshu Lulla
d16c4dad4b
feat(logging): add async_post_call_failure_deployment_hook (#36657)
* feat(logging): add async_post_call_failure_deployment_hook

CustomLogger already has async_pre_call_deployment_hook and
async_post_call_success_deployment_hook, both firing once per real
deployment attempt from wrapper_async since the router re-enters that
wrapper fresh on every retry and fallback step. There was no failure-side
counterpart; the only failure signal, async_log_failure_event, fires once
per logical client request behind a dedup gate, so fallback chain attempts
2+ were invisible to callbacks needing per-deployment-attempt granularity.

Adds async_post_call_failure_deployment_hook(request_data, exception,
call_type) to CustomLogger and a matching dispatcher in utils.py, called
from wrapper_async's except block. It needs no dedup coordination since
each real attempt naturally re-enters the wrapper once. Unlike its two
siblings, the dispatcher wraps each callback call in its own try/except
since it runs on the wrapper's own exception path and a broken callback
must never mask the exception about to be re-raised to the caller.

* feat(logging): pass fallback_depth through to async_post_call_failure_deployment_hook

Router already tracks fallback_depth internally on each fallback hop
(litellm/router_utils/fallback_event_handlers.py), incrementing it once per
target tried, but nothing surfaced it to CustomLogger callbacks. Reads it
off request_data in the dispatcher and passes it through as a best-effort
int | None keyword: None on the first, pre-fallback attempt or a bare SDK
call with no router, 1 on the first fallback hop, 2 on the second, and so
on. Verified live against a real multi-hop Router fallback chain before
adding the regression tests.

* fix(logging): fire async_post_call_failure_deployment_hook on internal calls too

The failure hook was gated behind the same not _is_litellm_internal_call
check as the request-level dedup-gated failure logging, so a failed
internal sub-call (e.g. an emulated file-search step) never reached it,
even though its async_pre_call_deployment_hook and
async_post_call_success_deployment_hook siblings already fire
unconditionally for such calls.

* chore: retrigger CI (lint job hit a transient GitHub Actions infra outage on the prior push)

* chore: retrigger CI (lint job hit the same GitHub Actions infra outage again)

* fix(logging): scope async_post_call_failure_deployment_hook to the actual model call

The hook was dispatched from the wrapper's broad outer except, which also
catches BudgetExceededError (raised before any deployment attempt),
errors from async_pre_call_deployment_hook, and errors raised after a
successful model call (post_call_processing, async_post_call_success_deployment_hook,
caching). None of those are a deployment attempt failing, so the hook
misreported them as one.

Scoped the hook to a try/except around the model call itself, so it only
fires when that specific call raises, matching its own documented contract.

* test: assert the callback actually ran in the failure-hook error-isolation test

An upstream test-quality gate (TQ001) flagged this test for asserting
nothing, so it could only fail by raising. Track whether the exploding
callback actually ran and assert on it, so the test would catch a
dispatcher that silently skipped every callback instead of isolating a
raising one.

* fix(logging): harden async_post_call_failure_deployment_hook against 5 maintainer-verified issues

A maintainer's live-proxy A/B review against base found five real
problems with the failure hook, all reproduced and fixed:

- The dispatcher called overrides with fallback_depth as a required
  keyword, so an override matching this PR's own earlier 3-arg
  proof-of-fix example raised TypeError, swallowed at debug level, on
  every call. Now checks the override's signature once per class and
  omits the keyword when unsupported.
- A callback mutating the exception it receives (e.g. status_code)
  changed what the real caller got back, since it was the same live
  object about to be re-raised. Callbacks now receive a same-class
  snapshot instead.
- request_data exposed attempted_targets, the router's own live
  fallback-walk bookkeeping shared by reference across every hop, so a
  callback calling .record() on it could make the router skip a
  deployment it never actually tried. Now excluded from what the hook
  receives.
- The hook's own await sat directly in the model-call except block, so
  a caller-side cancellation landing mid-await (e.g. asyncio.wait_for)
  replaced the real deployment exception with CancelledError/
  TimeoutError. Now isolated so hook dispatch can never mask the real
  failure.
- The timestamp used for the reported failure duration was captured
  after the hook ran, so a slow callback inflated
  async_log_failure_event's duration. Now captured before the hook
  dispatches.

* fix(logging): preserve traceback/cause/context on the failure-hook exception snapshot

Bugbot found a real gap in the previous round's exception-mutation fix:
_snapshot_exception_for_hook only copied __dict__ and args, so a
callback formatting or inspecting the failure chain saw an empty
traceback and lost chained-exception context, even though the live
exception still has them. __traceback__/__cause__/__context__ aren't
stored in __dict__, so they need copying explicitly.

* fix(logging): preserve __suppress_context__ on the failure-hook exception snapshot

Setting __cause__ has a documented CPython side effect of implicitly
forcing __suppress_context__ to True. Since the previous round's
traceback fix set __cause__ before __suppress_context__, a normal
implicit-chaining exception (no `raise ... from`, __suppress_context__
naturally False) got its context wrongly suppressed on the snapshot.
Now __suppress_context__ is set explicitly, after __cause__, so it
always reflects the real exception.

* fix(logging): use MappingProxyType for the failure-hook's sanitized request_data

A LIT002 budget check (surfaced by rebasing onto a moved base) flagged
the dict comprehension building safe_request_data as mutable
construction. MappingProxyType is also a strictly better fit here: a
genuinely read-only view, not just an immutable-looking dict, matching
the intent that callbacks should never be able to mutate what they're
handed.

---------

Co-authored-by: Deepanshu <deepanshu.lulla@alpha-sense.com>
2026-08-25 19:01:03 -07:00
mateo-berri
893482d4ac test(e2e): drop docstrings on the cost map model and its client accessor 2026-08-25 18:51:40 -07:00
mateo-berri
55e3a9785c test(e2e): trim docstrings that restate the Together tests 2026-08-25 18:45:52 -07:00
mateo-berri
cc6b3783fe test(e2e): price Together cached tokens at the registry cache read rate 2026-08-25 18:17:28 -07:00
mateo-berri
a543b0348c test(e2e): cover Together AI reasoning, tool calls, template kwargs, and cost through a live proxy 2026-08-25 18:12:33 -07:00
mateo-berri
a2c8ba7b5d Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_together_structured_outputs 2026-08-25 18:05:53 -07:00
Mateo Wang
ea6ac3dd99
Merge pull request #38283 from BerriAI/litellm_together_regression_tests
test(together_ai): regression suite across chat, responses, and messages surfaces
2026-08-25 17:58:14 -07:00
Mateo Wang
d0c527f3bb
Merge pull request #36245 from BerriAI/litellm_fix_headroom_stream_leak
fix(anthropic): buffer streamed responses carrying server-fulfilled tools so retrieval tool calls never reach the client
2026-08-25 17:48:31 -07:00
mateo-berri
602bf1c0ac test(together_ai): close the injected async client after the streaming test 2026-08-25 17:45:54 -07:00
mateo-berri
7c3da429c7 test(together_ai): regression suite across chat, responses, and messages surfaces
Adds streaming, async, /v1/responses, and /v1/messages coverage for the
Together AI overhaul (#38233, #38248, #38230, #38265, #38275), plus the
legacy api.together.xyz host and TOGETHER_AI_API_BASE through
litellm.completion. Each new test fails under a one-line mutation of the
merged code.
2026-08-25 17:40:41 -07:00
mateo-berri
8d877980e0 fix(caching): carry has_buffered_provider_output through the anthropic stream cache writer 2026-08-25 17:31:46 -07:00
Mateo Wang
99e1eaaca0
Merge pull request #38205 from BerriAI/litellm_decrease_anys_opus5_round2
refactor(repositories): type prisma table access with one generic protocol
2026-08-25 17:19:57 -07:00
mateo-berri
64d8b24c10 fix(router): deliver the hold-back retrieval error to the client instead of falling back 2026-08-25 17:00:00 -07:00
ryan-crabbe-berri
434add755a
Merge pull request #38274 from BerriAI/litellm_test_lint_os_environ
test: gate the test tree on B003 so a test cannot swap os.environ for a plain dict
2026-08-25 16:51:45 -07:00