Commit graph

43876 commits

Author SHA1 Message Date
Mateo Wang
69be083146
Merge pull request #37346 from BerriAI/litellm_lit_5755_client_side_timeout
fix(proxy): stop leaking the client_side_timeout marker to providers
2026-08-18 14:01:45 -07:00
Mateo Wang
3324122f45
Merge pull request #34445 from ayaangazali/litellm_azure_ai_strip_non_openai_message_fields
fix(azure_ai): strip non-OpenAI-spec message fields before request
2026-08-18 14:00:21 -07:00
mateo-berri
f8cc26a51f test(anthropic): pin one content_block_stop per tool_use block on the Responses adapter 2026-08-18 13:57:23 -07:00
mateo-berri
ec35098108 fix(main): forward store and prompt_cache_key on the MCP gateway early-return 2026-08-18 13:57:07 -07:00
mateo-berri
c1c23bf39a fix(proxy): reserve measured input tokens for multimodal project ITPM
Image, file, video, and previous_response_id requests reserved the whole
project ITPM limit up front, so any window with existing usage rejected
them and one in-flight multimodal request blocked the entire project.
Reserve the token_counter estimate instead, like every other request;
post-call reconciliation already charges actual usage.
2026-08-18 13:51:47 -07:00
mateo-berri
4e8efa041d fix(advisor): exclude in-sequence system rows from the advisor sub-call context 2026-08-18 13:51:01 -07:00
mateo-berri
39c5ccaed4 test(responses): inject a mocked http client instead of patching AsyncHTTPHandler.post 2026-08-18 13:45:48 -07:00
mateo-berri
76a2340685 test(router): drop docstrings from the new chained-proxy file upload tests 2026-08-18 13:45:36 -07:00
mateo
ac17352594 fix(cost_calculator): recognize the ultrafast service tier in cost calculation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-18 20:43:55 +00:00
Mateo Wang
035bd76669
Merge pull request #33767 from BerriAI/litellm_lit_4561_bedrock_passthrough_content_type
fix(proxy): forward Bedrock event-stream content-type on unbuffered passthrough
2026-08-18 13:43:47 -07:00
mateo-berri
e3a93c40be fix(proxy): stop leaking the client_side_timeout marker to providers 2026-08-18 13:37:07 -07:00
mateo-berri
89e563d3da fix(tinyfish): keep hidden-params header stashing within lint budgets 2026-08-18 13:37:03 -07:00
mateo-berri
93f08ed938 refactor(advisor): collapse router resolution to is_recognized_model plus wildcard check 2026-08-18 13:36:29 -07:00
mateo-berri
61625723a7 fix(responses): strip the responses/ routing prefix on the Responses API path
openai/responses/<model> deployments reached OpenAI as the literal model id
responses/<model> on /v1/responses and on /v1/messages (which rides the
Responses API for the openai provider) and 400ed with model_not_found, while
/v1/chat/completions already stripped the prefix. Strip a leading responses/
right after provider resolution so every Responses API entrypoint (HTTP,
websocket, compaction, the /v1/messages adapter) sends the real model id
2026-08-18 13:28:22 -07:00
mateo-berri
c6b40e9232 fix(azure_ai): keep the stripped message list and field tuple final 2026-08-18 13:28:11 -07:00
mateo-berri
c18d50b521 fix(batches): accept litellm_proxy in files and batches provider type literals 2026-08-18 13:28:06 -07:00
mateo-berri
8dc8cae0ec refactor(fireworks): name the Foundry deployment id prefix instead of commenting it 2026-08-18 13:17:44 -07:00
ryan-crabbe-berri
ceeab01b0d
refactor(ui): retire the tremor date range picker in favour of the shared advanced picker (#37302)
* refactor(ui): retire the tremor date range picker in favour of the shared advanced picker

UsageDatePicker was the last tremor DateRangePicker surface. Its three call sites in the old usage page and the caching dashboard now render AdvancedDatePicker, which already had the same prop interface, preset list and idle-callback day-boundary adjustment. AdvancedDatePicker drops its own tremor Button and Text for the shadcn Button and a plain paragraph, and it now applies the className prop it already declared so the mb-4 the tag-based usage tab passes keeps landing on the picker root. usage_date_picker.tsx and its calendar-grid test are removed, and the two no-restricted-imports suppressions those files carried are pruned

* fix(ui): let the advanced date picker anchor its panel to the trigger's left edge

The picker's dropdown is 600px wide and right-anchored to a 300px trigger, which was fine while every caller sat at the right edge of its row. The two old usage tabs place it in the left column, so the preset column landed left of the main scroll container and was clipped. AdvancedDatePicker gains an align prop (default right, unchanged for existing callers) and the old usage call sites pass left. The caching dashboard grid gives the picker an auto track instead of a third equal share, so the fixed-width trigger no longer spills past the card at laptop widths

* fix(ui): give the advanced date picker a real focusable trigger

The picker's display was a click-only div, so tabbing through the usage,
old usage, caching, cost optimization and guardrails monitor pages skipped
the date range control entirely and its focus ring classes never fired. It
is now a type="button" element carrying aria-expanded, which restores the
keyboard and screen reader access the tremor picker had. The panel also
reports its anchoring as data-align so the test can assert intent instead
of a Tailwind class

* fix(ui): make date picker relative-range presets keyboard-operable

The presets were non-focusable divs with click handlers, so a keyboard-only admin tabbed past Today / Last 7 days / Last 30 days / MTD / YTD and had to type both dates by hand. They are now buttons carrying aria-pressed.
2026-08-18 13:17:18 -07:00
mateo-berri
6bbc45ddaa Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_chained_proxy_file_upload
# Conflicts:
#	litellm/router.py
2026-08-18 13:14:30 -07:00
mateo-berri
842bb7e917 Merge branch 'litellm_internal_staging' into feature/bedrock-mantle-quota-project-itr1 2026-08-18 13:14:14 -07:00
tin-berri
340d30867e
feat(ui): plan-mode override tier in the auto-router create and edit forms (#37319)
* feat(ui): plan-mode override tier in the auto-router create and edit forms

The backend plan_mode_min_tier field (#37230) was API-only. Both forms now
carry an Advanced: Plan-Mode Override panel in the shared complexity config
component: a toggle derived from field presence, so on writes the highest
tier that has models and off deletes the key, and a tier select limited to
tiers with models because the backend rejects a floor at an empty tier. The
edit modal manages the key on every save, so clearing it actually clears the
stored config instead of the preserved copy resurrecting it, while unmanaged
keys like plan_mode_patterns still round-trip untouched

* refactor(ui): hoist the eligible plan-mode tier list out of the panel JSX

* refactor(ui): move tierOptions into complexity_router_tiers, the shared tier-utility module
2026-08-18 13:13:21 -07:00
yuneng-jiang
00e1f25e9b
refactor(ui): migrate the login, onboarding and search tool forms to react-hook-form and shadcn (#37334)
* refactor(ui): migrate login, onboarding and search tool forms to react-hook-form and shadcn

Moves four forms off antd Form and Tremor widgets onto react-hook-form plus
the shadcn kit, and onto semantic colour tokens so the screens are dark-mode
ready. antd Modal and Alert stay as the shells.

The submit payload is unchanged in all four. Each unit is pinned by a
characterization test that was proven green against the antd original before
any production code changed, and the pre-existing test files pass unedited.

Extracts the search tool payload builder, which was duplicated verbatim
between the create and edit forms, into searchToolPayload.ts with unit tests,
and adds a shared PasswordInput so the four reveal toggles antd and Tremor
gave for free are preserved on one component.

* refactor(ui): keep the search tool Test Connection button an implicit submit

Tremor's Button renders no type attribute, so inside a form it defaults to
submit. The Test Connection button therefore fires both its own onClick and
the form's onFinish today, which creates the search tool as a side effect of
testing the connection. shadcn's Button renders type="button", so the naive
swap silently dropped that second path.

Restores parity with an explicit type="submit" and pins it with a test, so
the double submit is recorded rather than quietly changed. Fixing it belongs
in its own change.

Also prunes the two now-stale eslint suppression counts for the migrated
search tool files, scoped to those keys only.

* refactor(ui): announce the login button spinner the way antd did

antd's Button renders its loading indicator as role="img" with aria-label
"loading", so a screen reader announces the request in flight. The shadcn
spinner is a bare svg, which drops that. Labels it on the login button to
match, as already done on the onboarding submit button.

* fix(ui): drop noValidate from the migrated login, onboarding and search-tool forms

antd's Form renders no novalidate attribute and its required rules emit
aria-required rather than the native required attribute, so nothing in
these four forms was ever gated by native constraint validation. The only
type="email" input is disabled and readOnly, which bars it from validation
in every browser. Measured in jsdom and again in Chrome against a live
proxy: form.checkValidity() is true with the fields empty, a native submit
reaches react-hook-form, and zod blocks it with the same messages.

Removing the attribute keeps the rendered form faithful to antd, and keeps
a constraint added later behaving the way antd would have behaved instead
of being silently suppressed.

* fix(ui): accept a null api_key when seeding the search tool edit form

The list endpoint declares api_key as str | None and search_tool_info as
dict | None, and the masking helper returns non-string values untouched, so
a tool stored without an API key comes back as "api_key": null. zod's
optional() accepts undefined and rejects null, so the edit form for any
such tool failed with "expected string, received null" and could never be
submitted. antd carried no schema and forwarded whatever the server sent.

nullish() restores that, and the payload still forwards the null rather
than coercing it to an empty string. The new case seeds both null vectors
and fails without this change.

* chore(ui): drop the narration comments from the search tool forms

These restate the state change or the JSX block directly below them, which
the repo's comment policy rules out, and both files are rewritten by this
change rather than merely touched.
2026-08-18 13:12:27 -07:00
mateo-berri
7b60bd89c9 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr34445_local 2026-08-18 13:09:41 -07:00
mateo-berri
0c5fcde883 Revert "feat(key_management): let any authenticated user resolve a raw key via /key/info"
This reverts commit d0c1d2be8a.
2026-08-18 13:08:28 -07:00
Mateo Wang
852368d72f
Merge pull request #37333 from BerriAI/litellm_lit_5726_auto_router_header_tags
fix(router): route Responses API input through the auto-router
2026-08-18 13:04:32 -07:00
mateo-berri
34db226dcc Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr32448_tinyfish_headers 2026-08-18 13:03:33 -07:00
mateo-berri
0e0768df9f Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_pr_33195_head
# Conflicts:
#	litellm/main.py
#	litellm/utils.py
#	tests/test_litellm/test_main.py
2026-08-18 13:03:04 -07:00
mateo-berri
addb77a9ea Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_lit_5307_advisor_router 2026-08-18 13:02:24 -07:00
mateo-berri
791b478d77 fix(router): only resolve structured input when messages is absent
Keeps an explicit empty messages list on the pre-existing path (default
model, provider validation error) instead of dropping the routing
decision and surfacing a misleading tags 401.
2026-08-18 12:18:53 -07:00
yuneng-jiang
6d32d4081d
refactor(ui): drop the unreachable user edit modal (#37327)
EditUserModal was rendered by the users dashboard but nothing could ever
open it. Its two pieces of state, editModalVisible and selectedUser, were
only ever set to false and null, so the modal short-circuited to null on
every render.

The edit path users actually reach goes through the row actions menu,
which routes to the user detail view and its edit form, so removing this
leaves no capability behind. The submit handler that fed the dead modal
goes with it, along with the imports it was the last consumer of.
2026-08-18 19:16:01 +00:00
mateo-berri
dd18389365 fix(router): route Responses API input through the auto-router
Auto-router strategy hook returned None whenever the request carried
input instead of messages, so tagged /v1/responses requests (Codex CLI)
never picked a tier and tag filtering left nothing to route to. Resolve
input through the shared prompt-template helper before matching routes.
2026-08-18 12:04:27 -07:00
yuneng-jiang
aa90828811
refactor(ui): migrate prompt, UI access, plugin and MCP filter forms to react-hook-form and shadcn (#37297)
* refactor(ui): migrate prompt, UI access, plugin and MCP filter forms to react-hook-form and shadcn

Moves four more admin dashboard forms off antd Form onto react-hook-form with the
shared shadcn form kit, keeping the submitted payload byte-identical in every case.

Each form was pinned with a characterization test proven green against the antd
original before any production code changed, then re-run unedited afterwards.

Behaviours that needed reproducing by hand rather than falling out of the port:

- antd onFinish reports only mounted fields, so UIAccessControlForm blanks a seeded
  but hidden restricted_sso_group at submit time instead of sending it
- antd InputNumber returns null on empty and clamps on blur, so MCPSemanticFilterSettings
  keeps top_k as null when cleared and clamps to [1, 100] rather than sending "" or NaN
- PluginSettings seeds plugin_key blank on edit so an untouched save preserves the
  stored credential instead of overwriting it with the redacted placeholder
- antd's url rule and zod's .url() disagree in both directions, so the async-validator
  pattern is ported verbatim to avoid silently changing which URLs are accepted

Forms with no onFinish keep preventDefault so no Enter-to-submit is introduced, and
the plugin key regains a reveal toggle built on InputGroup.

* chore(ui): prune stale eslint suppressions left by concurrent form-migration PRs

* Revert "chore(ui): prune stale eslint suppressions left by concurrent form-migration PRs"

This reverts commit e36bcc5862.

* fix(ui): keep the embedding model unclearable, matching the antd Select

The antd Select for embedding_model had no allowClear, so an admin could never
empty it. SearchSelect renders a clear button whenever a value is set and emits
an empty string, so the migration silently added a way to persist an empty
embedding_model and break semantic filtering.

Adds an opt-out to SearchSelect that defaults to the current behaviour, leaving
the other twenty callers unaffected, and opts this one field out. Pinned with a
test that fails when the opt-out is removed.
2026-08-18 18:47:06 +00:00
yuneng-jiang
d6fe9712fa
refactor(ui): migrate guardrail and vector store forms to react-hook-form and shadcn (#37306)
* refactor(ui): migrate guardrail and vector store forms to react-hook-form and shadcn

Ports four antd forms in the guardrails and vector stores pages onto
react-hook-form with zod resolvers and the shadcn field kit, and takes the
files they live in off light-only Tailwind colors

VectorStoreForm and vector_store_info now build their payloads from typed
form values instead of an antd FormInstance, seeding the edit view through an
explicit mapper rather than spreading the whole server record. The submit
modal in TeamGuardrailsTab moves to the same shape, and its URL rule is
reproduced exactly: src/lib/forms/antdUrl.ts compiles the pattern
async-validator uses for `type: "url"`, with a test asserting the compiled
source and flags match, so a protocol-less www host keeps passing and a bare
domain keeps failing

CompetitorIntentConfiguration had no FormInstance at all: its antd Form was a
layout wrapper with no named items and no onFinish, so it moves onto the field
primitives directly rather than gaining form state it never had. Its tag and
threshold controls are replaced by local TagsInput and ThresholdInput
components that reproduce what antd did, comma token separators plus commit on
blur for tags, and clamp-on-blur with step-precision display for the
thresholds, without introducing the native number constraints that would
newly block the surrounding guardrail form

Every payload is pinned by a characterization test that was proven green
against the antd original before the swap and then re-run unedited

* fix(ui): keep the vector store edit form saving when the server sends null

The proxy returns null for an unset vector_store_name or
vector_store_description rather than omitting the key, and both columns are
nullable. z.string().optional() accepts undefined but rejects null, so
loading any store whose name or description was never set left the edit form
stuck on "Invalid input: expected string, received null" and it could not
submit at all. nullish() accepts both and forwards null unchanged, which is
what the antd version did

Pinned by an untouched-save case that seeds both fields null and clicks Save
without typing anything. It fails against the optional() schema with zero
requests sent, and passes against both the fix and the antd original, sending
vector_store_name and vector_store_description as null

Also drops the deep import into @rc-component/async-validator, an undeclared
transitive dependency that failed the knip gate. The URL parity assertion now
compares against a checked-in snapshot of the pattern async-validator 5.1.0
compiles, so it stays an exact-equality check, and removes a comment that only
restated the networking layer's error handling
2026-08-18 18:44:15 +00:00
yuneng-jiang
7d97bab405
refactor(ui): migrate auto router and credential forms to react-hook-form and shadcn (#37304)
* refactor(ui): migrate auto router and credential forms to react-hook-form and shadcn

Moves four antd Form surfaces onto useZodForm plus the shared FormField and
FieldGroup primitives: the routing group modal, the auto router edit modal, the
add auto router tab, and the reuse credentials modal. Field labels that carried
an antd tooltip= keep it as a hover Tooltip on a help icon, and hardcoded greys
give way to semantic color tokens.

Two Base UI combobox wrappers come out of the two auto router surfaces that
shared the same antd controls: AccessGroupTagsCombobox replaces mode="tags" for
model access groups, and ModelChoiceCombobox replaces the searchable single
select for default and embedding models.

Payload building for the routing group modal moves to routingGroupPayload.ts so
the JSON args parsing and the four bound fields can be asserted directly
instead of through a render.

handle_add_auto_router_submit now takes a resetForm callback rather than an antd
form instance, which drops one any from its signature.

No change to what any of these forms submit. The reuse credentials payload keeps
the same key set, with the stored credential values rendered read-only and
merged back in at submit rather than copied into form state.

* refactor(ui): type the auto router create payload boundary

handleAddAutoRouterSubmit took its values as any, so a change to either side
of the auto router create payload passed static checking. It now takes an
exported AddAutoRouterValues, and add_auto_router_tab annotates the object it
builds with that same type, so the producer and the consumer cannot drift.

Its model_info is built in one shot rather than assigned into after the fact,
which drops the second any and keeps the two conditional keys exactly as they
were.

Adds a routing group case that saves an untouched edit of a group whose stored
arguments are null, which is the shape the proxy returns for an unset field.
2026-08-18 18:43:47 +00:00
yuneng-jiang
e20e31e985
refactor(ui): migrate CloudZero and cost tracking forms to react-hook-form and shadcn (#37312)
* refactor(ui): migrate CloudZero and cost tracking forms to react-hook-form and shadcn

Moves four forms off antd Form onto react-hook-form with the shadcn field
primitives, keeping the request payloads byte identical.

The two CloudZero modals were near duplicates, so the payload builder and the
API key input now live in shared modules next to them. The Update modal keeps
its redaction behaviour: the key field arrives empty with a "leave empty to
keep existing" hint, and an untouched save omits api_key from the request so
the stored secret survives. There is a test that fails if that regresses.

add_provider_form had no Form instance of its own, and its Form.Item wrappers
carried no name, so nothing was registered in the parent store. The parent in
cost_tracking_settings still owns an antd Form element, which stays for now,
and the migrated button keeps type="submit" so the parent's onFinish path
behaves exactly as before.

Each unit got characterization tests written against the antd version first,
then re-run unedited against the migration. Payload parity was also checked
side by side with toStrictEqual across seven scenarios.

* test(ui): guard the CloudZero null connection id against a zod type error

The proxy returns connection_id as null rather than omitting it, and a plain
z.string() rejects null. The seeding coalesces it to "" so an untouched save
reports the friendly required message instead of "expected string, received
null". Dropping that coalesce fails this test.
2026-08-18 18:42:58 +00:00
yuneng-jiang
b134c61300
refactor(ui): migrate the regenerate key and team member forms to react-hook-form and shadcn (#37300)
* refactor(ui): migrate the regenerate key and team member forms to react-hook-form and shadcn

Moves RegenerateKeyModal and EditMembership off antd Form onto react-hook-form
plus the shadcn field kit, and onto semantic color tokens so both are dark-mode
ready. The antd Modal shell and Alert stay as they are.

The submitted payload is unchanged on both. Payload construction is extracted
into regenerateKeyPayload.ts and memberFormValues.ts and unit tested there, and
each component keeps an integration test that was written against the antd
original and proven green before any source changed.

RegenerateKeyModal keeps antd InputNumber's precision=2 rounding of max_budget.
The rounding is string-exact rather than float based, so 1.005 still submits as
1.01 the way antd did. Submission stays on the modal footer button, so Enter
still does nothing.

EditMembership omits noValidate. Its numeric fields are already native number
inputs carrying min and step, so browser constraint validation blocks a bad
submit today and continues to. That is pinned by tests.

* fix(ui): accept null-valued fields the proxy returns for keys and members

The proxy returns null rather than omitting the key for an unset
key_alias, user_email or user_id. antd had no schema and forwarded
whatever came back, but z.string().optional() accepts undefined and
rejects null, so regenerating an alias-less key or editing a member
with no email failed validation and silently never submitted.

Widen those three fields to nullish() and pin each with a test that
seeds null and submits without touching the field. Each test passes
against the pre-migration antd component and failed against the
migration before this commit, and the payloads it asserts are the
ones antd put on the wire.
2026-08-18 18:42:33 +00:00
yuneng-jiang
2ee15a6efb
refactor(ui): migrate user, policy, and margin forms to shadcn (#37305)
* refactor(ui): migrate user, policy, and margin forms to shadcn

Move four dashboard forms off antd Form and Tremor onto the shadcn field
kit, with react-hook-form where the form owns its own submit. Submit
payloads are unchanged: edit_user still emits exactly six keys with spend
as a number and max_budget as a string, policy_test_panel still omits
empty context keys, and add_attachment_form still builds the same
attachment body.

add_margin_form had no Form of its own and no bound field names, so its
Form.Item rules were inert; it keeps its parent-owned state props and
only swaps the presentation.

Adds characterization tests for edit_user and policy_test_panel, both
proven green against the antd originals before the migration, plus a case
pinning the provider value add_margin_form reports upward. The existing
add_attachment_form and add_margin_form suites pass unedited.

Extracts TokenSelect for the tag and alias inputs shared across the
policy forms, keeping antd's token separators and blur-commit behavior.

* refactor(ui): seed the user edit form by remount instead of an effect

Key the form on the edited user so react-hook-form seeds from its
defaults on each user, replacing the effect that reset the form and the
exhaustive-deps suppression that came with it. Cancel and submit still
reset, so reopening the same user shows stored values.

* test(ui): pin that the user edit form forwards null fields unchanged

The proxy returns null rather than omitting unset fields, and antd
forwarded whatever it received. The only fixture seeded every field, so
nothing proved the migrated form still emits null instead of an empty
string. Proven against the antd original first, and it fails if
toFormValues coerces.
2026-08-18 18:42:16 +00:00
yuneng-jiang
5e2d6addc4
refactor(ui): migrate user, logging and policy forms to react-hook-form and shadcn (#37303)
* fix(ui): stop the policy modal cancelling its own save

The Create Policy and Update Policy buttons are Tremor buttons rendered
inside an antd Form. Tremor does not set a type, so both default to
type="submit" and a click ran two things at once: handleSubmit's own
form.validateFields(), and rc-field-form's onSubmit, which calls
formInstance.submit() and validates a second time.

rc-field-form keeps only the newest validation promise, so the first one
resolved as outOfDate and rejected with an empty errorFields list.
handleSubmit read that as a failure, so it never called createPolicy or
updatePolicy and instead reported "Failed to save policy". Creating and
editing a simple policy from the UI could not succeed.

Marking both footer buttons type="button" leaves the submit path solely
with handleSubmit. The new test file pins the request bodies for create
and update, and fails without this change.

* refactor(ui): migrate user, logging and policy forms to react-hook-form and shadcn

Moves four antd Form units onto react-hook-form plus the shadcn kit and
semantic color tokens, keeping every submit payload byte-identical.

- Settings/AdminSettings/LoggingSettings
- CreateUserButton
- users/_components/user_edit_view
- policies/_components/add_policy_form

* chore(ui): drop the eslint suppressions the migrated forms no longer need

* fix(ui): keep users with null optional fields editable

The proxy returns null rather than omitting user_alias, user_role,
budget_duration and metadata, and the new zod shape only allowed
undefined, so opening any such user and saving failed validation.
2026-08-18 18:42:12 +00:00
ryan-crabbe-berri
9ec0145986
feat(proxy): add /team/daily/activity/aggregated and switch the Usage team tab to it (#36562)
* feat(proxy): add /team/daily/activity/aggregated and use it in the Usage UI

The Team Usage tab drained row-paginated pages client side, which painted
newest days first and drew duplicate bars when a day's rows straddled a
page boundary. Serve the whole range in one SQL GROUPING SETS pass instead:
the aggregated query gains optional per-entity rollup levels (entity as the
most-significant GROUPING bit) so breakdown.entities keeps per-team spend,
aliases, and per-key splits. The endpoint shares the paginated route's
scoping via _resolve_team_daily_activity_scope, accepts the timezone the UI
already sends, and the api_key filter now takes a list so non-admin member
scoping works. The dashboard tries the aggregated endpoint first and falls
back to page draining on failure.

* chore: ratchet B008 budget down by the endpoint converted to Annotated Depends

* chore: keep mutable-ok suppressions on their annotation lines after formatting

* fix(proxy): reject malformed or over-wide ranges on team aggregated activity

The aggregated endpoint has no pagination bounding its work, so validate
start_date and end_date as real dates and cap the span at 400 days. The
dashboard's widest presets fit well inside the cap, and an over-cap range
falls back to the paginated flow. Also trim implementation comments that
restated the grouping-set code.

* fix(proxy): parse aggregated range bounds as UTC to satisfy DTZ007

* refactor(proxy): fetch entity rollups with a companion query instead of extending the main one

The entity-as-extra-GROUPING-bit approach made the bitmask layout
mode-dependent: the same constant meant (date) for normal rows and
(date, entity) for entity rows, disambiguated by masking. Split it out:
the shared WHERE builder feeds both the untouched main query and a small
per-entity rollup query keyed by GROUPING(api_key), run concurrently, and
a fold writes breakdown.entities onto the built response.

* refactor(proxy): share the daily-activity error and entity-metadata shapes

The type-discipline ceiling for LIT002 ratcheted down on staging, so the new
aggregated endpoint had to stop hand-rolling collections the codebase already
builds elsewhere. Funnel the `{"error": ...}` detail through one construction
site, turn the range validator into an error-as-value, reuse a single
entity-metadata lookup for both breakdown paths, and widen
get_api_key_metadata to any set so callers stop copying frozensets.
2026-08-18 11:29:57 -07:00
ryan-crabbe-berri
83ae623733
refactor(ui): codemod every toast call site onto lib/toast and delete the antd-era facades (#37253)
MessageManager and NotificationManager were thin facades over lib/toast since #37207. This
rewrites their ~750 call sites (226 files) to import { toast } from @/lib/toast directly:
success/info/warning/error keep their names, fromBackend becomes fromError, destroy/clear
become dismiss. The one config-object caller (CreateMCPServer's admin-review branch) becomes
an explicit toast.success(message, { description }). Behaviour is unchanged: no production
caller passed a duration, so every toast keeps the same kind, title and default duration.

Tests: the global vitest mock now targets @/lib/toast (toast.test.ts opts back out with
vi.unmock), so the per-file vi.mock boilerplate for the facades is deleted and assertions read
toast.success / toast.fromError. The two facade files, their test and their filename-case
suppressions are removed, along with the commented-out facade calls left in networking.tsx
2026-08-18 18:24:49 +00:00
tin-berri
8159f240c4
feat(complexity_router): plan-mode tier floor for coding-agent clients (#37230)
* feat(complexity_router): plan-mode tier floor for coding-agent clients

Claude Code and Copilot signal plan mode only through client-injected prompt
text, which the ask-extraction path deliberately strips, so the router could
never see it. Detect the sentinels on the raw wire body and route those
requests to at least plan_mode_min_tier.

The floor is raise-only and transient: classifier results above it still win,
it overrides a session-affinity pin only on turns carrying the sentinel
without rewriting the pin, and plan_mode decisions are not pinnable, so the
first turn after plan mode exits routes as if plan mode had never happened.
Classification is skipped when the floor is the top configured tier. On
adaptive routers the floor rides _soft_floor_pick as a hard_floor that
excludes below-floor candidates, closing the adaptive_eligible=all gap where
a request classified at or above the floor could still route below it.
Detection is staleness-aware: only leading system content and the newest-ask
tail count, so sentinels surviving in history after plan mode exits, built-in
or operator-supplied, never fire. Custom tier sets are supported with
severity from the tier_definitions list order, same as keyword_tier_rules.
Off by default; decisions are recorded with the new plan_mode cause and the
matched sentinel in matched_keyword

* fix(complexity_router): gate pin writes and the failure exit on sentinel presence, not the floor binding

A plan-mode turn classified at or above the floor keeps its ordinary cause,
but pinning it would carry a plan-mode-shaped choice past plan mode's exit
(on adaptive routers the hard floor constrained that pick), so no
sentinel-carrying turn writes the session pin. The default_model failure
exit is skipped for sentinel turns for the same reason: default_model's
placeholder tier can equal the floor while default_model itself sits in no
pool the floor can vouch for
2026-08-18 10:24:11 -07:00
yuneng-jiang
e09bbe9a14
refactor(ui): migrate tag and memory forms to react-hook-form and shadcn (#37266)
Moves CreateTagModal, the tag detail editor and MemoryEditModal off antd Form
onto react-hook-form with the shadcn field kit, and onto semantic colour
tokens so the pages follow the dashboard theme.

Submitted payloads are unchanged and pinned by tests. The collapsible budget
sections keep values typed into them when collapsed and reopened, matching
what antd's store did, rather than reverting to the seeded default.
2026-08-18 09:05:53 -07:00
yuneng-jiang
b08032c5f7
refactor(ui): migrate budget and skill forms to react-hook-form and shadcn (#37262)
* refactor(ui): migrate budget and skill forms to react-hook-form and shadcn

Moves three dashboard forms off antd Form onto react-hook-form plus the shared
shadcn field kit, and onto semantic color tokens so they render correctly in dark
mode. The submitted request bodies are unchanged.

Budget create and edit previously relied on antd InputNumber precision={2}, which
rounds the submitted value rather than only the display. That rounding is now an
explicit shared helper so the wire payload stays identical, and the helper carries
unit tests covering key presence, null passthrough, negatives and non-finite input.

Characterization tests for both budget modals were written against the antd
implementation first and pass unchanged against the migrated components, which is
what pins the payload. They are named .integration.test.tsx per the dashboard test
tiers, with the pure rounding logic unit tested separately.

* fix(ui): keep collapsed Optional Settings values so reopening does not lose them

react-hook-form shouldUnregister deletes a field's value when its section
unmounts, so typing a budget, collapsing Optional Settings and reopening it
submitted the seeded default instead of what was typed. antd reported only
mounted fields in onFinish but preserved their values in its store, so the
two behaviours have to be reproduced separately.

Drop shouldUnregister, drive the section from controlled state, and blank the
section's fields at submit while it is closed. Seed the edit form from the
five form fields rather than the whole budget record, which shouldUnregister
had been masking.
2026-08-18 08:51:22 -07:00
yuneng-jiang
0896015927
test(ui): await the playground model combobox before clicking it (#36850)
The ChatUI playground test helper looked up the model combobox with a
synchronous getByPlaceholderText. That control renders its placeholder
from the model-loading flag, so the text is "Loading models..." until
the mocked fetch resolves, and the element the helper wants does not
exist yet. Under a loaded full-suite run the query could land inside
that window and fail with "Unable to find an element with the
placeholder text of: Select a Model", while the same test passed in
isolation every time.

Switch the helper to findByPlaceholderText so it waits for the control
to come back after loading.
2026-08-18 08:43:25 -07:00
Devin AI
3d523d6d81 fix(model_prices): add provider-announced deprecation_date to 205 registry entries
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-18 13:14:42 +00:00
Mateo Wang
4fd7a73ef5
Merge pull request #36599 from daniel-meismer-zocdoc/bugfix/mcp-oauth-startup-discovery
fix(mcp): oauth discovery must not cause outages
2026-08-17 22:32:00 -07:00
Mateo Wang
333ccf244c
Merge pull request #37247 from BerriAI/litellm_guardrail_usage_retry_safe_errors
fix(guardrails): retry usage upserts only on connection errors
2026-08-17 21:01:26 -07:00
mateo-berri
23bbb1d242 refactor(mcp): pass materialized server tuples to oauth discovery helpers
Annotate _prime_oauth_metadata_discovery_for_servers and
_reconcile_oauth_discovery_slots_for_servers with Sequence and snapshot
registry views with tuple() at the call sites. This drops the Iterable
addition to the collections.abc import, restoring that line to its base
spelling so the branch merges cleanly with litellm_internal_staging,
which adds Mapping on the same line
2026-08-17 20:56:36 -07:00
yucheng-berri
a738c45fc7
fix(proxy): strip callback credentials from the auth object stamped into request metadata (#37233)
Some checks failed
Publish basedpyright base counts / publish (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
Unit Tests: Core Utilities / core-utils (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Enterprise, Google GenAI & Routing / enterprise-routing (push) Waiting to run
Unit Tests: Integrations (Callbacks & Logging) / integrations (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: LLM Provider Transformations / Vertex AI (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (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-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: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
* fix(proxy): strip callback credentials from the auth object stamped into request metadata

* style(proxy): drop the restating half of the stamp-site comment

* test(proxy): pin that the stamped auth copy carries header-derived identity
2026-08-17 19:50:05 -07:00
mateo-berri
15823b1be3 fix(guardrails): degrade usage units to empty when the units table is missing
GET /guardrails/usage/overview and GET /guardrails/usage/detail/{id} 500ed on a
database that has not applied 20260817143646_add_daily_guardrail_usage_units yet
(pip installs on litellm-proxy-extras 0.4.86 with DISABLE_SCHEMA_UPDATE=true).
Both endpoints now return their metrics with empty units and log one warning
until the migration lands.
2026-08-17 19:38:43 -07:00