Commit graph

13221 commits

Author SHA1 Message Date
Yucheng Zhu
ff6c3dc7c2 test: type parametrized inputs and cover bare-string tool_result items 2026-08-25 11:35:17 -07:00
Yucheng Zhu
7a662556a9 test: trim regression test docstrings to one-liners 2026-08-25 11:04:07 -07:00
Yucheng Zhu
98db5a1f27 fix: never drop tool_result messages with unknown or empty content in anthropic adapter 2026-08-25 10:59:38 -07:00
tin-berri
31a67561ab
feat(complexity_router): bound the classifier context block, not each turn in it (#38145)
The LLM classifier capped every prior turn at 200 characters independently, so a
785 character turn was cut even when the whole block it belonged to was 353
characters. A character budget now bounds the block: turns are taken newest first
and quoted whole while they fit, older turns are dropped whole once it runs out,
and only the turn straddling the boundary is cut. The per-turn cap stays as an
optional clamp for operators who set it deliberately, defaulting to unset.
2026-08-24 22:56:00 -07:00
devin-ai-integration[bot]
a9c7b848f2
fix(logging): skip parsing redacted tool call arguments (#38169)
Some checks failed
Unit Tests: Proxy DB Operations / proxy-runtime (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 / 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 / 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 / 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 / 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 / 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
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
* fix(logging): skip parsing redacted tool call arguments

Co-authored-by: hansu650 <hansu650@users.noreply.github.com>

* test: annotate parser-warning test locals with Final

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: hansu650 <hansu650@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-24 20:59:57 -07:00
Mateo Wang
53c9d48bd2
ci(e2e): record the e2e suite weekly and replay it on weekdays with zero egress (#38163)
Adds a scheduled GitHub Actions lane on top of the merged record/replay
transport. A Saturday cron records the `replayable` e2e tests against the
real providers and publishes the fixture bundle as a private
`e2e-fixtures-bundle` artifact with a SHA-256 sidecar. Weekday crons pull
that artifact by its pinned digest, verify the checksum before extracting,
and replay it with provider credentials set to bogus values, so a run that
ever reached a real provider fails instead of passing.

An egress sentinel pins the provider hostnames to a local sink for the whole
replay job and counts every connection that reaches them; the job asserts
that count is zero, so hermeticity is proven by measurement. A red Saturday
publishes no bundle, so the next weekday finds nothing fresh and fails loudly
rather than replaying a week-old recording, and the transport's seven-day
freshness gate hard-fails any bundle that has drifted too far. The lane also
runs on demand from the Actions tab with a record/replay `mode` input.

Tests join the lane with `@pytest.mark.replayable`. The streaming Anthropic
test now counts to twenty so its recorded response banks several content
deltas, matching the assertion that the stream arrives incrementally.
2026-08-24 23:49:03 -04:00
yucheng-berri
ee68813530
fix(langsmith): keep root-run ids self-consistent so batch ingest stops rejecting header-tagged requests (#38116)
A request carrying a session/trace header fans the header value into
litellm metadata as both trace_id and session_id. LangSmith then rejected
the whole ingest batch: a root run's trace_id must equal the run id
embedded in dotted_order (400), and a run-body session_id must reference
an existing tracer session (404/422). Override caller trace_id on runs
that post as roots and drop session_id only when it mirrors trace_id,
so deliberate child-run and valid tracer-session fields still pass through.
2026-08-24 19:47:12 -07:00
Mateo Wang
539ba9f939
Merge pull request #37899 from BerriAI/litellm_ban_data_migrations
ci: ban row-rewriting DML from prisma migrations
2026-08-24 19:44:34 -07:00
Mateo Wang
da91d4b6c9
Merge pull request #38119 from BerriAI/litellm_bing_grounding_search_provider
feat(search): add Grounding with Bing Search (bing_grounding) as a search provider
2026-08-24 19:33:23 -07:00
ryan-crabbe-berri
891b23d680
Merge pull request #38156 from BerriAI/litellm_caching_error_drilldown
feat(ui): add error-code drilldown for failed requests on caching page
2026-08-24 18:30:41 -07:00
devin-ai-integration[bot]
8f6de53c92
fix(s3_v2): percent-encode object keys once so signed and sent URLs match (#38005)
Co-authored-by: yucheng <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-24 18:16:17 -07:00
Mateo Wang
82b0069f83
Merge pull request #38155 from BerriAI/litellm_forward_video_edit_source_file
fix(videos): forward uploaded source file on /v1/videos/edits to the provider
2026-08-24 18:00:29 -07:00
Mateo Wang
a28f075f45
Merge pull request #29832 from hclsys/fix/files-decode-encoded-id-in-chat-and-responses
fix(files): decode x-litellm-model encoded file_id in chat + responses
2026-08-24 17:29:00 -07:00
mateo-berri
a527275d05 fix: keep a schema-qualified call inside an index expression from reading as a relation
A quoted routine call qualified by a schema and sitting inside a CREATE INDEX
expression, ON "Foo" (public."f"(col)), walked its qualifier read-through back
across the opening paren to the ON that introduces the indexed table, so the call
was misread as a relation and dropped from the call set, leaving a rewrite in that
routine unscanned. A word now only introduces the name when nothing but whitespace
and qualifier dots lies between them, so a paren in that gap keeps ON (and any
relation-introducing keyword) from reaching across it and the call stays a call.
2026-08-24 16:04:38 -07:00
Akshay Sasi
fde307539e
fix: tolerate stream chunks without a choices key in stream_chunk_builder (#34382)
The Responses-API to /chat/completions bridge yields ModelResponseStream
chunks that carry choices followed by a trailing event object that has no
choices key. stream_chunk_builder assumed every chunk was subscriptable at
"choices", so assembling those chunks raised KeyError('choices') and was
re-wrapped as a 500 APIError building the streaming usage.

Guard each choices access with .get("choices") so choices-less chunks are
skipped instead of crashing. Behavior is unchanged for chunks that do carry
choices, since .get("choices") is truthy only for a non-empty choices list.

Adds a regression test that assembles content across chunks followed by a
trailing chunk with no choices key.

Co-authored-by: mubashir1osmani <mubashir.osmani777@gmail.com>
2026-08-24 18:53:30 -04:00
ryan-crabbe-berri
0de0e1cef6 feat(ui): add error-code drilldown for failed requests on caching page
/global/activity/cache_hits now returns an error_breakdown: failed spend
logs bucketed per call_type by error code and error class, read from
metadata->error_information. Clicking a red failed-requests segment on
the cache activity chart opens a per-code bar chart; hovering a bar
lists the error classes behind that code.
2026-08-24 15:45:45 -07:00
mateo-berri
7d0df4a062 fix(videos): forward uploaded source file on /v1/videos/edits to the provider
The video edit endpoint parsed the multipart body but dropped the uploaded
source video, only normalizing it to an id. When a raw file is uploaded it now
flows through videos.main -> the http handler -> the provider transform, which
emits multipart/form-data with the source video as a file part, matching the
official OpenAI SDK's videos.edit wire format. Edit-by-id still egresses JSON.
2026-08-24 15:34:21 -07:00
mateo-berri
c9d1b94828 fix: read through a spaced schema qualifier when telling a table from a routine call 2026-08-24 15:07:01 -07:00
Mateo Wang
25ec6827b7
Merge pull request #38136 from BerriAI/litellm_lit_5742_streaming_replay
feat(e2e): record and replay streamed provider responses chunk-for-chunk
2026-08-24 14:55:27 -07:00
Mateo Wang
fbb46b3ac6
Merge pull request #38133 from BerriAI/litellm_harden_retry_breadcrumb_credentials
fix(router): stop copying forwarded credentials into retry breadcrumbs
2026-08-24 14:55:04 -07:00
Mateo Wang
46c2328641
Merge pull request #38114 from BerriAI/litellm_fix_5997_vertex_pt_key_leak
fix(passthrough): stop leaking the caller's virtual key on credential-less Vertex passthrough
2026-08-24 14:54:53 -07:00
Mateo Wang
ccb03f567f
Merge pull request #38149 from BerriAI/litellm_fix_recursive_detector_form_flatteners
fix(ci): ignore-list recursive form-field flatteners in recursive_detector
2026-08-24 14:54:43 -07:00
mateo-berri
90a3101a45 fix: read through a schema qualifier when telling a table from a routine call 2026-08-24 14:52:55 -07:00
tin-berri
40246f43d7
fix(complexity_router): keep both ends of a clipped classifier context turn (#38141)
The LLM classifier's conversation context cut each prior turn head-only, so a turn
opening with an incident report and closing with the actual request reached the
classifier as the incident report alone. Keeping head and tail costs the same
budget and is what the truncation literature measures as best for classifying
long text.
2026-08-24 14:51:13 -07:00
mateo-berri
16a81c9ceb fix(vertex-passthrough): cover the mapped-route litellm_user_api_key header
On mapped pass-through routes, of which /vertex_ai is one,
user_api_key_auth accepts the caller key from a header literally named
litellm_user_api_key and applies it last, so it overrides every other source.
The credential-less filter neither dropped it nor resolved the caller key from
it, so a virtual key there reached Google past a real x-goog-api-key, and a
bring-your-own Authorization could be stripped when auth actually came from that
header. Drop it by name and resolve it at highest precedence.
2026-08-24 14:30:44 -07:00
Mateo Wang
0f596a5145
Merge pull request #38129 from BerriAI/litellm_autorouter_dropdown_registry
fix(auto-router): list configured auto-routers in the usage picker before they have traffic
2026-08-24 14:23:09 -07:00
mateo-berri
e018b9ce74 fix: don't read a quoted table's column list as a routine call site 2026-08-24 14:21:53 -07:00
mateo-berri
5d34b1232e fix(ci): ignore-list recursive form-field flatteners in recursive_detector
The recursive_detector code-quality gate fails on litellm_internal_staging
because _flatten_form_field and _flatten_form_data_field in
llm_request_utils.py are recursive but absent from IGNORE_FUNCTIONS. Both are
bounded structural recursion over an already-parsed JSON-shaped request body
(a finite tree, no cycles possible), matching the existing ignored walkers, so
add them to the ignore list with a justification comment.
2026-08-24 14:17:18 -07:00
ryan-crabbe-berri
380338c0b4
refactor(utils)!: delete prompt_token_calculator (#38132)
Follow-up to #38130. The function has no callers in the repo or the docs and is
not exported from `litellm/__init__.py`, and `token_counter` already does the same
job better, so keeping a second entry point only preserves a trap.

That trap is real: Greptile flagged on #38130 that `token_counter` picks the claude
tokenizer only for bare ids. `claude-sonnet-4-5` resolves to huggingface_tokenizer,
while `claude-3-opus-20240229` and `anthropic/claude-sonnet-4-5` fall back to the
OpenAI one, 24 tokens against 27 on the same string. Deleting the wrapper removes
the surface rather than papering over it; the selection gap in `token_counter`
itself is worth its own fix.

BREAKING CHANGE: `from litellm.utils import prompt_token_calculator` no longer
resolves. Use `litellm.token_counter(model=..., text=...)`.
2026-08-24 14:14:25 -07:00
Mateo Wang
463261d21d
Merge pull request #38117 from BerriAI/litellm_lit5902_managed_files_e2e
test(e2e): pin require_managed_files enforcement behind a marker-gated stack phase
2026-08-24 14:04:33 -07:00
Mateo Wang
1e9cecd05f
Merge pull request #38135 from BerriAI/litellm_lit_5704_vectorstore_upload_controls
feat(proxy): enforce vector-store upload security controls on /v1/rag/ingest
2026-08-24 14:04:22 -07:00
mateo-berri
b75609223d fix: skip comments when detecting a quoted routine call site
A quoted routine call with a SQL comment between its name and parenthesis,
`"backfill" /* reason */ ()`, is a real call that rewrites rows at boot, but the
call-site check read the raw SQL and stopped at the comment, so the routine was
read as uncalled and its rewrite slipped through. Read the call test from the
masked text instead, where every comment is already blanked to spaces, so a
comment between the name and its parenthesis is skipped exactly as whitespace is,
line, block and nested block comments alike, while a like-named non-call
identifier still opens no call and stays masked
2026-08-24 14:01:27 -07:00
mateo-berri
fcc047bf8a fix(vertex-passthrough): match get_api_key precedence for configured key headers
The resolver placed both operator-configured key headers at the top of its
precedence, but user_api_key_auth only overrides with litellm_key_header_name;
a pass_through_endpoints litellm_user_api_key is checked last. So a request that
authenticated via Authorization while also sending a pass-through header could
have the wrong value chosen, leaving the authenticated Authorization key
forwarded. Order the resolver exactly like get_api_key: override first, built-in
headers next, pass-through header last.
2026-08-24 13:57:37 -07:00
mateo-berri
e46c7226ac fix: restore only quoted routine call sites, not like-named identifiers
A migration that defines an uncalled row-rewriting routine and elsewhere
references a quoted column, table, index, or constraint sharing the routine's
name was wrongly flagged: the guard restored every double-quoted identifier
before the name search, so a like-named identifier read as a call. Restore only
quoted names that open a call, followed by "(", so a routine invoked through a
quoted identifier is still caught while a like-named non-call identifier stays
masked and no rewrite-free migration is rejected
2026-08-24 13:50:40 -07:00
mateo-berri
2fe1e7e43f fix(vertex-passthrough): cover operator-configured pass-through key headers
user_api_key_auth also accepts the caller key from a pass_through_endpoints
entry's headers.litellm_user_api_key, not just litellm_key_header_name. Drop
every operator-configured caller-key header by name and treat them as
top-precedence caller-key sources, so a virtual key sent through one is never
forwarded to Google.
2026-08-24 13:47:42 -07:00
mateo-berri
12a34a10d8 fix(logging_worker): carry queued tasks across event-loop change instead of dropping them
LoggingWorker._ensure_queue nulled self._queue on a loop change, discarding every
pending LoggingTask (each an un-awaited spend-logging coroutine) with no counter and
only a debug log. SDK callers using asyncio.run() per request and mixed sync/async
processes rebind the queue's loop and silently lose spend rows and observability events.

Drain the stale queue and move the pending tasks onto a fresh queue bound to the new
loop, warn with the carried-over count, and keep flush()/join() honest since the queue
is no longer thrown away. Adds a regression test that fills the queue before the loop
change and asserts every task survives and still executes.
2026-08-24 13:46:09 -07:00
mateo-berri
a8f24c8568 test(vertex-passthrough): send the virtual key via x-litellm-api-key in streaming tests
The LIT-4761 streaming-classification tests passed only the bring-your-own
Google OAuth token in Authorization and mocked get_litellm_virtual_key, a shape
that cannot authenticate in production. The credential-less filter now resolves
the caller key by auth precedence, so a lone Authorization value reads as the
key and is stripped. Send the virtual key in x-litellm-api-key, matching a real
request, so Authorization is preserved and the classification assertions run.
2026-08-24 13:35:34 -07:00
mateo-berri
2a4e5fc342 fix: catch a prisma routine called through a double-quoted identifier
A migration that defines a row-rewriting routine and calls it as
"backfill"() at the top level slipped past the checker, since masking
blanks double-quoted identifiers before the routine-call search runs, so
the call could not be found by name and the body read as uncalled. mask()
now returns those identifier spans and outside_definition puts them back,
so a call written through a quoted identifier reads as the call it is and
the routine's body gets scanned the same as a bare call
2026-08-24 13:34:50 -07:00
Chenglun Hu
b7aefbad08 fix(files): decode x-litellm-model encoded file_id in chat + responses
the x-litellm-model upload path returns ids wrapped with
encode_file_id_with_model (litellm:<raw>;model,<m> base64'd). chat
completions + /v1/responses forwarded the wrapped id straight to the
provider, breaking openai (file not found / >64 chars), gemini
(unknown mime), etc. wire up the existing get_original_file_id +
is_model_embedded_id helpers in update_messages_with_model_file_ids
and update_responses_input_with_model_file_ids — falls through after
the managed-files path so existing flows are unchanged. 3 new
regression tests + dem proof len 71 -> 26.
2026-08-25 04:28:50 +08:00
mateo-berri
b2f7216a6b fix(e2e): record a streamed chunk only after its downstream write lands
A downstream disconnect mid-relay was recording the chunk whose write never
landed, so replay would hand back a byte the record run never delivered. Append
each chunk after its yield returns, and label the truncation from the generator
close, so the recording holds exactly what the proxy received.
2026-08-24 13:26:58 -07:00
mateo-berri
5d8286c963 fix(vertex-passthrough): normalize caller key via canonical _get_bearer_token
The filter's own Bearer-only stripping missed the other schemes
user_api_key_auth accepts, so a virtual key echoed as `Authorization: Basic
<key>` alongside a higher-precedence auth header did not match the caller key
and was forwarded to Google. Reuse the auth module's _get_bearer_token so the
comparison strips exactly what authentication does (Bearer / bearer / Basic /
AWS4-HMAC-SHA256), falling back to the raw value for a bare token.
2026-08-24 13:21:56 -07:00
Mateo Wang
a91cac7f6c
Merge pull request #38104 from BerriAI/litellm_fix_36493_image_video_routes
fix: match OpenAI SDK wire format on image/video routes
2026-08-24 13:17:03 -07:00
mateo-berri
9a0c541b49 fix(ci): preserve offsets when re-lexing executed SQL literals
The DML scan reconstructed a DO/EXECUTE'd literal with undouble, which collapses
each doubled quote to one character and shrinks the text. Every offset after a
collapsed pair then shifted, so a row-rewrite scanned out of the literal reported
an earlier file line and could miss a data-migration-ok marker placed on its real
line. Reconstruct with defuse_escapes instead, turning each doubled quote into a
quote and a space so the pair keeps its two characters and every offset holds,
while a nested -- or /* still stays inside its string.
2026-08-24 13:08:25 -07:00
mateo-berri
f3dc339e07 fix(vertex-passthrough): value-strip the key by full auth precedence
The credential-less filter derived the caller key only from x-litellm-api-key,
Authorization, and the custom header, but the route authenticates through
Depends(user_api_key_auth), which also accepts the key from x-goog-api-key. A
virtual key sent only in x-goog-api-key therefore authenticated yet was kept as
a preserved upstream header and forwarded to Google. Resolve the caller key by
the same precedence get_api_key uses and value-strip exactly that, so a key in
x-goog-api-key is stripped while a real Google key alongside a higher-precedence
virtual key is preserved.
2026-08-24 13:06:13 -07:00
Mateo Wang
ca32321612
Merge pull request #38111 from BerriAI/litellm_fix_passthrough_router_budget_leak
fix(passthrough): attribute spend and release budget reservation on router-model /vllm and /azure routes
2026-08-24 13:05:39 -07:00
mateo-berri
a1f1aa9cb5 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_harden_retry_breadcrumb_credentials 2026-08-24 12:57:42 -07:00
mateo-berri
721227e9ee refactor(router): scrub retry-breadcrumb credentials by pattern, not a denylist
Enumerating credential-bearing kwargs in RETRY_BREADCRUMB_EXCLUDED_KWARGS is always one
new kwarg behind: it missed top-level extra_headers and provider token fields, which
log_retry still copied into router.previous_models verbatim. Scrub the breadcrumb with
mask_credentials_in_payload instead, so credential-named values are masked at any depth
(extra_headers.authorization, api_key, aws_secret_access_key, vertex_credentials,
azure_ad_token, and future kwargs), and leave the exclusion set to the request payload and
router walk state only.

This hardens the in-memory breadcrumb; it is not a fix for a reproduced SpendLogs leak. The
SpendLogs metadata allowlist and the universal previous_models stripping already keep this
breadcrumb off every persisted surface.

Parametrize the regression test over provider_specific_header, extra_headers, and api_key,
asserting the raw credential value never survives into previous_models for any shape while
the container key still reaches the breadcrumb
2026-08-24 12:57:32 -07:00
mateo-berri
15d8f0b43c refactor: drop the output-neutral pad on the executed-literal recursion
The call-detection restore splices into a fixed-position list, so its
.ljust(end - start) holds that length invariant and a test guards it. The
DML-scan recursion instead hands the undoubled literal to a fresh scan_region
as its own region, whose length feeds nothing, so the pad only appends
trailing spaces that shift no keyword and change no reported line. Drop it and
the docstring clause that claimed it kept the offsets landing
2026-08-24 12:54:57 -07:00
mateo-berri
aef7424637 fix(azure/search): reject bool and non-positive max_results for bing_grounding count
Extract a shared _valid_max_results predicate that rejects bools (an int
subclass) and non-positive values, and reuse it from both the connection-mode
request count and the response-side cap so both paths honor the same contract.
2026-08-24 12:53:44 -07:00
mateo-berri
ec47bbaaaa feat(e2e): record and replay streamed provider responses chunk-for-chunk
The record/replay harness stored a streamed provider response as one
buffered body, so a replayed stream arrived coalesced and the
/v1/messages streaming test could not be edge-wired. Keep each SSE
transfer chunk in the bundle in the order the provider sent it (a new
streamed response shape at BUNDLE_FORMAT_VERSION 4) so replay reproduces
the provider's split points, the recorded usage chunk keeps its
position, and a mid-stream upstream error replays as the same
mid-stream error rather than a clean body.

Resolves LIT-5742
2026-08-24 12:51:44 -07:00