Commit graph

12648 commits

Author SHA1 Message Date
mateo-berri
5cf291a3ef Merge branch 'litellm_internal_staging' into litellm_gemini_36_flash_introductory_pricing 2026-08-17 14:46:26 -07:00
mateo-berri
97b7eaad5c fix(mcp): keep issuer-anchored slots on reload, skip discovery for stamped M2M challenge
Registry-swap reconciliation used bool(server.url) while registration uses _requires_oauth_discovery, dropping slots for issuer-anchored servers without a url. The preemptive 401 loop awaited discovery before the stamped client_credentials continue, so a deferred discovery failure could 503 requests whose challenge decision never reads metadata
2026-08-17 14:44:01 -07:00
Mateo Wang
c6fad3683d
Merge pull request #36032 from Scott-Wilson-ZocDoc/litellm_fix_responses_tool_choice_auto
fix(responses): unwrap object-form tool_choice before calling the Responses API
2026-08-17 14:37:38 -07:00
Marty Sullivan
bc977b76dc fix(batches): own deployment pricing per token direction, not per field
Filling each cost field independently let a published batch rate outrank a
standard rate the deployment configured itself: a deployment declaring only
input_cost_per_token had its batches billed at the model's published batch price
rather than half its own rate. Measured on a model that publishes both, that
billed $0.001500 where the deployment's own rate meant $0.000500.

Declaring either rate for a direction now claims that whole direction, so nothing
published can displace it, and a direction the deployment is silent on still
inherits both published rates.
2026-08-17 14:28:38 -07:00
Marty Sullivan
e7c2ce8624 test(batches): cover the deployment with no resolvable model at all
Codecov's remaining uncovered patch line was the early return taken when no model
is available to look a published entry up by, which leaves a deployment's own
declared rates standing alone. Measuring the patch lines against the coverage
report now leaves none uncovered.
2026-08-17 14:28:38 -07:00
Marty Sullivan
800e1d4f35 fix(cost): treat a batch rate configured as zero as free, not unset
batch_cost_calculator gated the batch rate fields on truthiness, so a deployment
that configures input_cost_per_token_batches or its output twin as 0.0 was read
as having configured nothing and that token direction fell through to half the
standard rate. Layering declared rates over published ones made this reachable:
a deployment declaring only a zero batch rate previously kept a fabricated zero
on the standard field, which happened to bill nothing.

The two batch fields are now gated on presence. Verified no cost-map entry
changes behavior: the only three carrying a zero batch rate are embeddings, whose
standard output rate is also 0.0, so both paths yield the same zero.

Adds a parametrized regression over an explicit zero, an explicit non-zero, and
unset, plus coverage for the deployment id get_model_info cannot resolve, which
were the lines Codecov flagged.
2026-08-17 14:28:38 -07:00
Marty Sullivan
b593cef758 fix(batches): keep published rates for a side the deployment leaves unset
Substituting a deployment's pricing wholesale billed the token direction it did
not configure at zero: get_model_info fills an absent cost with 0, and any
non-None pricing field suppressed the global fallback. A deployment declaring
only input_cost_per_token therefore billed output at nothing.

Each of the four batch cost fields now falls back to the model's published rate
when the deployment leaves it unset, so a one-sided override applies to the side
it configures and only that side.

Adds a parametrized regression over input-only, output-only, and both-zero, plus
coverage for a deployment whose model has no published entry. Annotates the new
test helpers per the repo's type-coverage rule and drops the narrative banner
comment from the batch tests.
2026-08-17 14:28:38 -07:00
Marty Sullivan
727905dfc3 fix(batches): only use deployment pricing when the deployment declares it
The router registers a model_info entry for every deployment, priced or not, and
get_model_info fills absent costs with 0. Resolving deployment pricing through it
therefore reported a free deployment for any ordinary one, which priced its batches
at $0 while usage stayed correct: the same silent under-count this branch set out
to remove, widened from bedrock to every provider.

Caught by a live batch run, where four vertex batches that price correctly today
came back at $0. The raw registration is now what decides: pricing is used only
when the deployment actually declares one of the batch cost fields, so ordinary
deployments fall back to the global cost map exactly as before.

The earlier test missed this by using a deployment id that was never registered,
where get_model_info does raise; a real deployment is always registered.
2026-08-17 14:28:37 -07:00
Marty Sullivan
f74c72eedb fix(batches): price a retrieved batch from its deployment's model and rates
Retrieving a completed batch computed its cost with no model identity: neither the
deployment's model nor its configured pricing reached the batch cost calculation.

For bedrock that left the cost model falling back to the provider's own response
model (e.g. "claude-sonnet-4-6"), which does not resolve under a bedrock provider,
so the lookup missed and cost silently became $0 while usage stayed correct.
Dropping the deployment's model info separately discarded any rates configured on
that deployment, billing a zero-cost deployment at the public rate instead.

Both are the same omission at the call site, so both are fixed by passing the
logging object's own model and the pricing the router registered for the
deployment.
2026-08-17 14:28:37 -07:00
mateo-berri
127b426991 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_azure_di_native_ocr_format 2026-08-17 14:28:17 -07:00
Mateo Wang
c1fc5983ca
Merge pull request #36482 from irosh-colombage-ZocDoc2/fix/mcp-oauth-scoped-issuer
fix(mcp): scope authorization server issuer
2026-08-17 14:27:38 -07:00
yuneng-jiang
77c8a6452f
Merge pull request #36258 from BerriAI/litellm_/elastic-ishizaka-db31e6
feat(proxy): let USE_V2_MIGRATION_RESOLVER select the v2 migration resolver
2026-08-17 14:13:04 -07:00
mateo-berri
5ddff616dc fix(mcp): keep origin issuer on the openid-configuration alias 2026-08-17 13:41:36 -07:00
Mateo Wang
5c15c097b6
Merge pull request #36033 from Scott-Wilson-ZocDoc/litellm_fix_session_resume_thinking
fix(anthropic): stop emitting empty thinking blocks on the Responses adapter
2026-08-17 13:32:34 -07:00
Mateo Wang
e11fe1d6cc
Merge pull request #36781 from daniel-meismer-zocdoc/feature/request-logs-user-id-filter
feat(ui): add user ID request log filter
2026-08-17 13:32:26 -07:00
Mateo Wang
47eaff19d3
Merge pull request #36979 from Scott-Wilson-ZocDoc/fix/anthropic-responses-optional-tool-props
fix(anthropic): preserve optional Responses tool properties
2026-08-17 13:26:14 -07:00
mateo-berri
d5a4c14577 docs(proxy): pre-fix passthrough streams omitted content-type, not octet-stream
Some checks failed
LiteLLM Rust / rustfmt, clippy, test (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
2026-08-17 13:21:28 -07:00
Mateo Wang
cde5465e6f
Merge pull request #37203 from BerriAI/litellm_batches_metadata_type_400
fix(proxy): return 400 for non-object metadata and litellm_metadata instead of silent drop or 500
2026-08-17 13:19:33 -07:00
Mateo Wang
3b6e56716a
Merge pull request #36978 from Scott-Wilson-ZocDoc/fix/mcp-guardrail-usage-monitor
fix(guardrails): record MCP tool guardrail evaluations and blocks in …
2026-08-17 13:18:03 -07:00
mateo-berri
3cdf041827 Merge branch 'litellm_internal_staging' into fix/anthropic-responses-optional-tool-props 2026-08-17 13:10:29 -07:00
mateo-berri
f86dc8f54e test(proxy): assert non-Bedrock passthrough stream emits no content-type header 2026-08-17 13:09:17 -07:00
mateo-berri
98bfbb99d2 refactor(responses): drop commentary from the tool_choice fix 2026-08-17 13:04:45 -07:00
mateo-berri
8ced9f56a1 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_lit_4561_bedrock_passthrough_content_type 2026-08-17 13:04:18 -07:00
mateo-berri
11e2341fc9 Merge branch 'litellm_internal_staging' into feature/request-logs-user-id-filter 2026-08-17 13:01:19 -07:00
mateo-berri
c7b17b6615 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr36482_head 2026-08-17 12:54:14 -07:00
mateo-berri
cba076715d Merge remote-tracking branch 'origin/litellm_internal_staging' into pr36032_drive 2026-08-17 12:52:12 -07:00
mateo-berri
ce4eaa16e8 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr36033_drive 2026-08-17 12:50:32 -07:00
mateo-berri
09c8d1f1f5 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_lit5660_batches_limit_400 2026-08-17 12:46:15 -07:00
mateo-berri
a21de07b3f fix(proxy): drop every invalid metadata field before raising so failure hooks never see them 2026-08-17 12:44:46 -07:00
mateo-berri
73ae9c65dd test(proxy): give the x-litellm-model fallback test deterministic openai env creds 2026-08-17 12:42:57 -07:00
mateo-berri
2f9d331b4c fix(proxy): retire terminal batches whose advertised output file 404s instead of retrying 2026-08-17 12:36:39 -07:00
mateo-berri
f3b0cdca43 fix(proxy): keep ProxyException status codes on /v1/moderations instead of wrapping into 500 2026-08-17 12:32:30 -07:00
mateo-berri
21984101e5 fix(proxy): bill cancelled and failed batches that still produced an output file 2026-08-17 12:23:59 -07:00
mateo-berri
c894697a2a fix(proxy): keep ProxyException status codes on /v1/messages instead of wrapping into 500 2026-08-17 12:21:12 -07:00
Mateo Wang
badd737526
Merge pull request #37199 from BerriAI/litellm_lit5657_batches_400_missing_fields
fix(proxy): return 400 naming the missing required param on POST /v1/batches
2026-08-17 12:20:25 -07:00
mateo-berri
6e55a21ebb fix(proxy): enforce batch list limit bounds on managed passthrough listings 2026-08-17 12:15:22 -07:00
mateo-berri
57e1bf41c6 fix(proxy): return 400 for non-object metadata and litellm_metadata instead of silent drop or 500 2026-08-17 12:08:56 -07:00
mateo-berri
4a7dfd75fc fix(proxy): return 404 instead of 500 for unresolvable batch and file ids on /v1/batches 2026-08-17 12:02:15 -07:00
mateo-berri
a9bb09905d test(batches): drop redundant section banner 2026-08-17 12:00:40 -07:00
Yassin Kortam
d5b91b94d3
test(e2e): replay a real tool-search assistant turn back to Bedrock Invoke (#36856)
The tool_search x bedrock_invoke cell only ever probed the first turn, so
nothing in the suite has sent a server_tool_use block back to a provider.
Every turn of a real Claude Code session after the first carries the
server_tool_use and tool_search_tool_result blocks the previous turn
produced, and that path was uncovered.

Adds probe_tool_search_multiturn, which takes the real assistant turn
back, answers any client-side tool_use with the id the model actually
emitted, and replays the whole thing as history with the tools still
declared. The assertion refuses to go green unless both server-tool
blocks made it into the replayed history, so a first turn truncated at
max_tokens reads as a failure instead of a vacuous pass.

The replay assertion's red paths never run in a green cell, so they get
markerless harness tests of their own alongside the existing
_builder_unit_tests tree.

No production code.
2026-08-17 11:59:26 -07:00
mateo-berri
e4ce526900 fix(proxy): return 400 naming the missing required param on POST /v1/batches 2026-08-17 11:55:06 -07:00
mateo-berri
f55a193628 fix(proxy): reject out-of-range limit on GET /v1/batches with OpenAI-parity 400 2026-08-17 11:54:34 -07:00
ryan-crabbe-berri
ad6a3a7b9e
fix(proxy): registry caches stop per-request tag and end-user Postgres reads in auth (#36801)
* fix(proxy): cache tag-name registry so unregistered request tags skip Postgres

Request tags are free-form attribution labels, so most have no LiteLLM_TagTable
row. get_tag_objects_batch never cached that absence: every tagged request ran
a find_many that came back empty, and under Prisma pool contention those
per-request queries queued for minutes inside user_api_key_auth.

Cache the bounded set of registered tag names under one aggregate key with the
management-object TTL. Uncached request tags are filtered against it before any
per-tag DB fetch, so unregistered tags cost zero DB reads on a warm path. An
empty registry is cached as a valid answer; DB errors are not cached and fall
back to the per-tag lookup; tables past TAG_REGISTRY_MAX_SIZE cache an overflow
sentinel that disables filtering. Tag create/update/delete endpoints now evict
the registry and per-tag keys and publish cross-worker invalidation (they
previously evicted nothing). The per-tag write-back also gains the management
TTL it was missing, and the hand-built tag:{name} key strings are replaced with
a shared builder.

* fix(proxy): skip per-request end-user DB reads via restricted-id registry

Every request carrying a user id ran get_end_user_object, and with high-cardinality
auto-created end-user rows (hundreds of thousands of ids, all restriction fields
NULL) the per-pod cache missed on nearly every request, so each one paid a Postgres
find_unique that queued behind the Prisma pool during background-job bursts. True
misses were never cached, and unknown ids paid the read twice per request.

Cache the bounded set of end-user ids that carry any restriction (blocked, budget,
region, default model, or object permission) under one aggregate key with the
management-object TTL. When an id misses the per-id cache and is absent from a
usable registry, get_end_user_object returns None with zero DB reads; restricted
ids keep today's fetch-and-cache path. The skip is bypassed whenever
litellm.max_end_user_budget_id is set (default budgets make unrestricted rows
behaviorally distinct from missing rows), validate_end_user_id_in_db is on
(existence checks need the row), or the token carries end_user_max_budget from
custom auth (the row's recorded spend seeds the budget counter). Empty registries
cache as a valid answer, DB errors are never cached, and oversized tables cache an
overflow sentinel that disables filtering. Customer create/update/block/delete now
evict the registry and per-id keys and publish cross-worker invalidation (they
previously evicted nothing), and the per-id write-back gains the management TTL it
was missing so Redis entries no longer live forever.

* refactor(proxy): single generic registry loader with error sentinel and single-flight

Code review follow-ups on the two registry caches. Registry DB errors now cache
the overflow sentinel for a short REGISTRY_ERROR_NEGATIVE_CACHE_TTL window and
log at warning, so a degraded Postgres stops paying the failing registry scan on
every request on top of the per-id fallback. Cold registry loads are single-flight
per worker behind per-registry locks with a recheck after acquire, so a TTL expiry
no longer fans out one full-table scan per in-flight request. The tag and end-user
loaders collapse into one _load_bounded_registry with per-entity fetch closures,
and the triplicated evict-then-broadcast protocol becomes one evict_and_broadcast
helper beside publish_auth_cache_invalidation, shared by the tag, customer, and
project eviction paths.

* chore(lint): suppress fail-safe registry excepts and ratchet BLE001 budget

* docs(proxy): trim registry cache commentary to single-line why docstrings

* fix(lint): move tag fetch return to else block to satisfy TRY300 budget
2026-08-17 18:52:13 +00:00
mateo
94a29e0708 fix(gemini): price gemini 3.6 flash at Google's introductory rates on every service tier
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-17 18:42:57 +00:00
mateo
1e1a2b63a4 fix(ocr): validate body req_format in the proxy endpoint and run its tests in CI
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-17 18:29:35 +00:00
Brian Cox
3b6ae75f73
fix(bedrock): preserve cache token usage when invocationMetrics replace the usage block (#36878)
Bedrock invoke /v1/messages streaming reports cache_read_input_tokens and
cache_creation_input_tokens on message_stop.usage while attaching
amazon-bedrock-invocationMetrics to the same chunk. The stream decoder
rebuilt that chunk's usage block from inputTokenCount/outputTokenCount
alone, which exclude cache reads and writes, so the cache breakdown was
destroyed before _promote_message_stop_usage could surface it and cache
tokens were billed at $0. Merge instead of replace, and also map
cacheReadInputTokenCount/cacheWriteInputTokenCount when Bedrock reports
the cache itemization inside the invocation metrics.

Co-authored-by: Brian Cox <3924351+brian5021@users.noreply.github.com>
2026-08-17 11:28:35 -07:00
Yassin Kortam
9b7ed77fcc
fix(azure): rename max_tokens to max_completion_tokens for gpt-5-chat deployments (#36857)
Azure rejects the legacy `max_tokens` key for the whole gpt-5 name family, but
`AzureOpenAIGPT5Config.is_model_gpt_5_model` deliberately excludes `gpt-5-chat*`
so those deployments fall through to `AzureOpenAIConfig`, which sends `max_tokens`
verbatim and gets a 400 back on every request that carries it, `/health` probes
included.

One predicate was answering two independent questions. Split it: the new
`AzureOpenAIConfig.requires_max_completion_tokens` covers the whole gpt-5 name
family and drives only the rename, while `is_model_gpt_5_model` keeps keying
reasoning_effort, the temperature clamp and the dropped penalties off the
reasoning question, so #13781 stays fixed.
2026-08-17 11:27:55 -07:00
Yassin Kortam
ee08b63657
feat(bedrock): forward LiteLLM identity and metadata into Bedrock requestMetadata (#36861)
Adds an opt-in operator allow-list, litellm_settings::bedrock_request_metadata_fields, that forwards LiteLLM key, team and end-user identity plus client spend_logs_metadata into Bedrock request metadata so Bedrock spend can be grouped in AWS Cost Explorer.

Covers all three Bedrock surfaces: the Converse body requestMetadata field, and a signed X-Amzn-Bedrock-Request-Metadata header on Invoke chat completions and on Invoke /v1/messages, where the header is the only viable leg.

The resolver reads both metadata variable names, reserves the whole user_api_key_ prefix against caller-supplied keys, caps the client slot budget explicitly at 16 minus the reserved count, and drops rather than rejects auto-injected values that violate Bedrock constraints. Caller-supplied requestMetadata keeps its existing 400 semantics.

The request-metadata field and header are proxy-owned whenever forwarding is enabled. A caller-supplied value, reachable through the generic extra_headers passthrough, is dropped unconditionally and compared case-insensitively, and is replaced only by the proxy's own value, so identity in the AWS billing record cannot be forged. Absence of a resolved value still means absence on the wire rather than a fallback to the caller's. The guardrail headers keep their existing no-displace behaviour.
2026-08-17 11:27:46 -07:00
yucheng-berri
1139012b45
fix(guardrails): scan text on /guardrails/apply_guardrail for Azure Content Safety (#36894)
* fix(guardrails): scan text on /guardrails/apply_guardrail for Azure Content Safety

The two Azure Content Safety guardrails never implemented apply_guardrail, so the
endpoint fell through to the base no-op and answered 200 with the caller's text
echoed back, having scanned nothing.

Implementing that method also flips the proxy's unified-vs-native dispatch, which
would move request traffic off these guardrails' own hooks. Add an opt-out that
keeps every lifecycle event on the native hooks, so only the endpoint changes.

* test(guardrails): cover the remaining native-hook opt-out dispatch sites

Adds regression tests for the parallel post-call path, the MCP post-call hook, and
the policy engine step, so every read of the opt-out flag fails when removed.
2026-08-17 11:18:40 -07:00
mateo
bfc52b94db fix(ocr): return 400 for an unknown x-req-format header value
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-17 18:11:57 +00:00