Commit graph

45564 commits

Author SHA1 Message Date
ryan-crabbe-berri
243f8317f4 style(ui): drop decorative section banners from the access group budget hooks 2026-08-29 16:47:50 -07:00
ryan-crabbe-berri
7c0e58ed06 fix(ui): stop offering access group budget writes that the proxy refuses
An Admin Viewer and a group whose name contains a slash both reached an
enabled Set budget action that could only ever come back 403 or 404. Gate
the row actions on proxy admin and on the name being addressable, with the
reason in the tooltip.
2026-08-29 16:45:48 -07:00
ryan-crabbe-berri
a5cd3fae81 fix(ui): name the tab Model Access Group Budgets and keep sub-cent budgets readable
Marks the tab New, and stops a budget under a cent rendering as "of $0.00"
next to an over-budget meter.
2026-08-29 16:38:58 -07:00
ryan-crabbe-berri
0777e37849 feat(ui): set a model access group's shared budget from the dashboard
Model access group budgets shipped API-only, so the only way to give a group a
budget was a curl. Adds an Access Group Budgets tab under Models & Endpoints
that lists every group with the spend drawn against its shared pool, and a
modal to set, edit or clear the budget.

/access_group/list now carries each group's budget and spend inline, so the
table renders from one read instead of one follow-up request per row.
2026-08-29 16:32:28 -07:00
ryan-crabbe-berri
cd5f154985
Merge pull request #35854 from BerriAI/litellm_window_spend_schema
feat(proxy): add LiteLLM_BudgetWindowSpend table for per-window budget spend
2026-08-29 16:25:28 -07:00
yuneng-jiang
e4ae1c1f2e
Merge pull request #38835 from BerriAI/litellm_38816_classifier_cost_savings
fix(proxy): count auto-router classifier cost in savings and benchmarks
2026-08-29 16:23:50 -07:00
Mateo Wang
0c8321efc3
Merge pull request #38741 from BerriAI/litellm_fix_anthropic_messages_dict_detail_error
fix(anthropic_endpoints): serialize dict-detail HTTPExceptions on /v1/messages like sibling surfaces
2026-08-29 16:20:08 -07:00
Mateo Wang
6bc8dafa99
Merge pull request #38740 from BerriAI/litellm_vertex_gemini_35_transcribe
feat(vertex_ai): support gemini-3.5-transcribe on /v1/audio/transcriptions
2026-08-29 16:19:56 -07:00
ryan-crabbe-berri
4c8838696a
chore(ui): drop unrelated schema.d.ts enum reorder from the window spend schema branch 2026-08-29 16:17:14 -07:00
ryan-crabbe-berri
8829276735
chore(migrations): drop the generated comment from the budget window spend migration 2026-08-29 16:17:14 -07:00
ryan-crabbe-berri
2c2f4bbfed
feat(proxy): add LiteLLM_BudgetWindowSpend table for per-window budget spend
Multi-window budgets (budget_limits on keys/teams) currently keep window
spend only in cache. Every cold or expired counter recomputes the window
by aggregating LiteLLM_SpendLogs, which has no usable index for that
query and saturates the DB on large tables (#35766).

This adds a LiteLLM_BudgetWindowSpend table holding one row per
configured window, keyed (entity_type, entity_id, window_duration),
with window_start identifying the period the spend belongs to.
Follow-up PRs maintain these rows from the spend update writer and move
window budget enforcement reads onto them.
2026-08-29 16:17:14 -07:00
Tin Chi Lo
d3db7cebca fix(proxy): count auto-router classifier cost in savings and benchmarks
The LLM classifier's cost was recorded on the routing decision but never
reached any savings surface: per-request autorouter_savings stayed gross
and the session rollup recorded only the served request's spend, so
/auto_router/benchmarks overstated savings and understated routed spend.

Net the classifier cost into the savings figure at its one computation
owner and fold it into the rollup turn's spend, keeping
baseline_spend = spend + saved_spend. The response header's numeric
guard now shares the same reader.

Fixes #38816
2026-08-29 16:09:35 -07:00
ryan-crabbe-berri
ec934c490b
Merge pull request #38784 from BerriAI/litellm_model_access_group_budgets
feat(budgets): enforce shared budgets on model access groups
2026-08-29 16:06:54 -07:00
devin-ai-integration[bot]
3e2999f29f
fix(proxy): run SMTP send_email off the event loop with a connection timeout (#38473)
* fix(proxy): run SMTP send_email off the event loop with a connection timeout

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

* fix(proxy): format utils.py and update _create_smtp_connection tests for timeout

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

* fix(proxy): keep malformed SMTP_TIMEOUT inside the email error boundary

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

* chore: retrigger ci

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

* ci: exclude misaligned circleci coverage flag from merged codecov report

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

* chore: retrigger ci for codecov and benchmarks

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

* ci: disable carryforward for the circleci codecov flag

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

* ci: exclude carried-forward coverage from the codecov patch status

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

* ci: stop carrying forward the dead circleci codecov flag

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-29 16:05:57 -07:00
yuneng-jiang
b3235fa786
Merge pull request #38830 from BerriAI/litellm_paginated_select_deletion_query
fix(ui): keep a deleted-from search query instead of blanking the box
2026-08-29 15:57:51 -07:00
Yuneng Jiang
02046fb7b7
fix(ui): keep a deleted-from search query instead of blanking the box
The paginated search select diffs the input against the selected option's
label to recover what the user just typed, so a query started from a picked
value searches for the new text rather than the label plus the new text.
That diff can only express an insertion: it walks a common prefix and a
common suffix and returns what sits between them. A deletion leaves nothing
between them, so every deletion-only edit returned the empty string.

Backspacing once in a field showing a selected label therefore threw the
edit away. The empty result was stored as the query, the controlled input
re-rendered blank, and the server was asked for the unfiltered page instead
of the text the user left in the box.

An edit that yields no insertion but did change the value is a deletion, and
there the remaining text is the query the user means. Insertions and
whole-selection replacements are untouched.
2026-08-29 15:52:48 -07:00
ryan-crabbe-berri
e263c09e4f test(e2e): cover model access group budgets against a live proxy
Four cases in tests/e2e/quota_management/budgets, driving real OpenAI calls
through a group whose shared pool is drained to exhaustion: the spender key
stays blocked, a key that spent nothing of its own is blocked by the same
pool, a sibling group with no budget keeps serving, and the budget read
reports the spend drawn against the group.

Adds set/get/delete access group budget to BudgetClient and the four
matching rows to the coverage registry.
2026-08-29 15:46:49 -07:00
ryan-crabbe-berri
40a7fe9221 fix(budgets): make the model access group ceiling exclusive
A pool whose recorded spend has reached max_budget has nothing left to give, so
the next request is refused rather than admitted. This departs from the tag
check it otherwise mirrors and matches where keys and organizations already
draw the line.

A non-positive budget now means no budget here too, so the read-time check and
the reservation path agree on what counts as unbudgeted.
2026-08-29 15:20:10 -07:00
tin-berri
36ea28b092
fix(anthropic): emit signature-only thinking blocks on the /v1/messages bridge (#38809) 2026-08-29 15:04:22 -07:00
ryan-crabbe-berri
d7c0bc1e6d test(budgets): clear the test-quality violations this branch added
The four model access group callback tests now share one helper, so nine
patches of proxy_server internals become three, and both mock-echo assertions
go with them. The delete_access_group tests share a context manager for the
same reason.

test_group_exactly_at_its_max_budget_passes gained the assertion it was
missing: it now proves the group reached the spend comparison, which a group
skipped for a missing budget row would not. The route-allowed patch beside it
was dead, so it is gone.

What is left is suppressed with the collaborator each one cannot inject.
2026-08-29 14:44:00 -07:00
tin-berri
5c034fda74
fix(ui): allow in-place editing of classifier numeric inputs (#38803)
Backspacing the last digit of Context Window Size instantly refilled the default (3), since onChange mapped empty input to null and the handler coalesced null back to the default. The same defect affected Timeout (ms) and Context Character Budget. Add per-field raw draft state so an empty or partial value stays visible while focused, commit only finite values (rounded, clamped to each field's minimum), and clear the draft on blur so an abandoned edit falls back to the committed value. 0 stays a valid committed value for both context controls. Add stable ids and label associations; update tests to query by label
2026-08-29 14:43:20 -07:00
Mateo Wang
20cfccaf5f
Merge pull request #37208 from BerriAI/litellm_managed_batches_observability
fix(batches): aggregate reasoning tokens and per-line pass/fail counts
2026-08-29 14:43:03 -07:00
Mateo Wang
c62c2afa09
Merge pull request #38234 from BerriAI/litellm_request_timeouts
fix(proxy): give every `requests` call a timeout so a silent server cannot hang the caller
2026-08-29 14:30:46 -07:00
ryan-crabbe-berri
acf3ed7d9b fix(budgets): narrow model access group spend counters to the served deployment
The database writer already intersects the auth-matched groups with the ones
the served deployment declares, but the live spend counters got the unnarrowed
set. A caller granted two pools that both cover a model group debited both
counters while only one row moved, so the in-memory ceiling could block a pool
its persisted spend never touched.

Narrow once at the callback so both consumers read the same set.
2026-08-29 14:25:56 -07:00
ryan-crabbe-berri
7a2f6c4cc2 fix(budgets): let the model access group spend helper swallow its own failure
The helper already logs through spend_log_error, so re-raising only for
_batch_database_updates to catch and log again was double reporting. Isolate
inside the helper instead and drop the caller's wrapper.
2026-08-29 14:17:45 -07:00
ryan-crabbe-berri
6b2e7f8a1f refactor(budgets): declare route dependencies with Annotated instead of argument defaults 2026-08-29 14:10:58 -07:00
Mateo Wang
2963b47cda test: patch the Logging handler instead of the class in the poller error-file test 2026-08-29 14:09:33 -07:00
Mateo Wang
128d7e5278 refactor(batches): make count_error_file_failed_requests public for the poller import 2026-08-29 14:09:18 -07:00
ryan-crabbe-berri
06d0665f50 fix(budgets): drop the bespoke access group cache TTL and format the repository
The cache TTL for a group's budget row was a new
DEFAULT_MODEL_ACCESS_GROUP_CACHE_TTL env var defaulting to 600 seconds, which
nobody asked for and which the docs gate rightly rejected as undocumented.
Every other management object cached in auth_checks, tags included, already
reads get_management_object_ttl, so it honors general_settings
user_api_key_cache_ttl and falls back to the shared default. Group budgets now
do the same, which drops a constant, drops an env var, and makes the row expire
on the same operator knob as keys and teams.

Also formats ModelAccessGroupBudgetRepository, and teaches the FakeBatch double
in the unit of work tests about the new table. That double is read while the
cascade unit of work is constructed rather than inside the block, so three tests
that never mention access groups were failing at the async with. The new test
alongside it walks the dataclass fields, so the next dependent added to the
cascade is covered without anyone remembering to update a list.
2026-08-29 14:00:56 -07:00
ryan-crabbe-berri
fb9e76fab3 chore(budgets): refresh the lazy OpenAPI snapshot and allowlist the model access group budget routes 2026-08-29 14:00:12 -07:00
devin-ai-integration[bot]
194a3cc202
ci: build the benchmark environment outside the CodSpeed runner (#38426)
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-29 13:58:04 -07:00
devin-ai-integration[bot]
645792955d
feat(proxy): cyberark conjur secret manager configuration via Admin UI (#38445)
* feat(proxy): CyberArk Conjur secret manager configuration via Admin UI

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

* test(ui): mock networking base-url helpers in AdminPanel test

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

* fix(proxy): restore deployment CyberArk env config on delete and roll back on persist failure

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

* fix(proxy): reinit env-configured hashicorp vault manager after cyberark persist rollback

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-29 13:36:08 -07:00
Mateo Wang
8dd9c4acb1
Merge pull request #30782 from emerzon/litellm_veo_31_lite
feat(vertex-ai): add veo 3.1 lite model metadata
2026-08-29 13:36:02 -07:00
Mateo Wang
306daf13b5
Merge pull request #38752 from BerriAI/litellm_deflake_20260829
fix: bound Hugging Face config fetch and keep embedding tests off the network
2026-08-29 13:33:06 -07:00
mateo-berri
4d5205c355 fix(proxy): give the remaining CLI clients a request timeout
The keys, credentials, models, model groups, and chat clients still sent
requests with no timeout, so a proxy that accepts the connection and
never answers pinned the caller forever. They now default to the same
30 seconds as their teams and users siblings, with chat on the OpenAI
SDK's 600 second default, and Client wires its timeout through to all of
them. S113 cannot see Session methods, so each client gets a
hanging-server regression test instead.
2026-08-29 13:32:39 -07:00
mateo-berri
8aba6e9203 Merge branch 'litellm_internal_staging' into litellm_request_timeouts 2026-08-29 13:32:33 -07:00
Mateo Wang
38145c2082 test: undo the drive-by reformat below the poller error-file regression test 2026-08-29 13:17:43 -07:00
Mateo Wang
e0ed0a4c7a
Merge pull request #35017 from BerriAI/litellm_lit_4913_headroom_streaming_ccr
fix(headroom): resolve CCR retrieval on streaming /chat/completions
2026-08-29 13:01:35 -07:00
devin-ai-integration[bot]
f0340fef16
feat(mcp_gateway): add RFC 7662 introspection for gateway session tokens (#38726)
* feat(mcp_gateway): add RFC 7662 introspection for gateway session tokens

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

* fix(mcp_gateway): omit Bearer token_type for refresh introspection and allow mcp-scoped keys

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

* test(mcp_gateway): cover introspection of RS256-signed session tokens

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

* fix(mcp_gateway): load the discoverable router on a cold /introspect request

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

* chore(openapi): regenerate lazy snapshot and schema.d.ts for /introspect

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-29 12:56:04 -07:00
Mateo Wang
9ed7de6c02
Merge pull request #38670 from BerriAI/devin_ai_38659_cohere_embed_dispatch
fix(bedrock): route all cohere.embed models to the cohere embedding config
2026-08-29 12:55:32 -07:00
Mateo Wang
99884f0eaa test: fake the provider file boundary in the poller error-file regression test 2026-08-29 12:53:52 -07:00
Mateo Wang
817bbe1dc6
Merge pull request #34440 from dan2k3k4/litellm_soniox_srt_cue_grouping
fix(soniox): align synthesized SRT/VTT cues to real speech timing
2026-08-29 12:49:57 -07:00
ryan-crabbe-berri
8e1d1f1ef0 fix(budgets): write the model access group spend counter after each call
Two problems, both caught in review.

The new table only landed in the root schema.prisma. Client generation reads
litellm/proxy/schema.prisma and packaging reads the copy under
litellm-proxy-extras, so the generated client had no
litellm_modelaccessgroupbudgettable and every budget read and write against
it would have failed at runtime. The root is the source of truth; both
copies are now byte-identical to it.

Nothing incremented spend:model_access_group:{group} after a call. Only the
reservation path ever wrote it, so with disable_budget_reservation the
read-time check was reading a counter nobody maintained and falling back to
the row's spend, which is cached for up to DEFAULT_MODEL_ACCESS_GROUP_CACHE_TTL.
A caller could run well past the pool inside that window, which is precisely
the case the read-time check exists to cover.

increment_spend_counters now takes the matched groups and charges them
through _init_and_increment_unreserved_spend_counter, so a group already
covered by a reservation is skipped rather than counted twice. The cost
callback sources the names with get_request_model_access_groups, the same
reader the spend writer uses.
2026-08-29 12:49:47 -07:00
mateo-berri
2affd800ec test(headroom): cover stream conversion after deployment-level compression 2026-08-29 12:45:56 -07:00
Mateo Wang
c453920f7a
Merge pull request #38285 from BerriAI/litellm_azure_v1_image_routes
fix(azure): use /openai/v1 image routes for v1, preview and latest api versions
2026-08-29 12:45:37 -07:00
mateo-berri
886d39c3a2 test(bedrock): expect cohere embed base64 encoding_format to normalize to float 2026-08-29 12:44:01 -07:00
yuneng-jiang
d435a62ce6
Merge pull request #38782 from BerriAI/litellm_/logs-reopen-shadcn-migration-2c9526
fix(ui): restore the reopen control for the log drawer's trace sidebar
2026-08-29 12:38:26 -07:00
mateo-berri
ae1039f811 ci: rerun checks on an identical tree after a windows job infra failure 2026-08-29 12:29:31 -07:00
github-actions[bot]
183a782e57 chore: sync schema.prisma copies from root 2026-08-29 19:15:11 +00:00
ryan-crabbe-berri
d2440639d5 feat(budgets): enforce shared budgets on model access groups
A model access group could gate which models a caller reaches but never how
much that group of callers could spend in total. Capping a shared pool meant
setting a per-entity budget on every key by hand, which caps each key
separately and still leaves no way to read what the group cost.

Spend is attributed to a group only when the group's name appears on an
allowlist the caller was granted (key, team, team-member scope, project or
org) and that group serves the requested model. Asking for a model that
merely belongs to a group attributes nothing, because nothing about the
caller named the group. Levels are unioned rather than ranked, so a team
granted "*" whose member is scoped to one group still counts as gated by
that group.

Enforcement runs on both paths tags already use: a reservation counter on
the pre-call path and a read-time max_budget check inside the existing
concurrent budget gather, so the ceiling still holds under
disable_budget_reservation.

Adds LiteLLM_ModelAccessGroupBudgetTable, which is the only place a group is
ever a row: the groups themselves stay free-text strings in
model_info.access_groups, so a row exists only once someone gives that group
a budget. GET, PUT and DELETE /access_group/{name}/budget manage it, and
/access_group/{name}/info now carries the spend and budget alongside the
models.
2026-08-29 12:13:55 -07:00