Commit graph

3808 commits

Author SHA1 Message Date
Mateo Wang
b600f02fc2
Merge pull request #34788 from BerriAI/litellm_fix_s3_vectors_search
fix(vector_stores): s3 vectors search router bypass + rag query config drop + ui error swallow
2026-09-02 11:35:56 -07:00
ryan-crabbe-berri
fc1a5fd7f9
Merge pull request #39206 from BerriAI/litellm_lit_3925_clear_team_key_create
fix: stop a cleared Team field from blocking personal key creation
2026-09-01 16:21:52 -07:00
ryan-crabbe-berri
1964d92fc6 test(ui): query the clear button and the models page tabs through accessible screen queries 2026-09-01 16:04:45 -07:00
ryan-crabbe-berri
4acc1d15fb fix(ui): map a cleared Team dropdown back to an empty string in the auto-router form 2026-09-01 15:50:19 -07:00
ryan-crabbe-berri
55d638412b fix: stop a cleared Team field from blocking personal key creation
Clearing the Team combobox in the Create Key modal left team_id set to an
empty string, so /key/generate treated the request as team key generation
and failed with a team-not-found error for non-admin members.

TeamDropdown now emits null on clear, and GenerateKeyRequest normalizes an
empty team_id to None so the request runs the personal key path.
2026-09-01 15:17:00 -07:00
devin-ai-integration[bot]
846900320e
feat(alerting): slack alerts for per-user daily/monthly spend thresholds and spend anomaly detection (#38438)
* feat(alerting): slack alerts for per-user daily/monthly spend thresholds and spend anomaly detection

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

* test(alerting): use specific ValidationError matches in config rejection test

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

* fix(proxy): tolerate mocked slack alerting args when scheduling user spend scan

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

* fix(alerting): reject non-finite values in user spend alert settings

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-09-01 15:09:03 -07:00
Mateo Wang
bad55da9bf
Merge pull request #38872 from BerriAI/litellm_fix_viewer_add_model_tab
fix(ui): hide model write affordances from view-only admin sessions
2026-09-01 14:52:54 -07:00
yuneng-jiang
8bc862f52c
Merge pull request #39129 from BerriAI/litellm_/litellm-issue-39078-c025be
fix(ui): render the logs Tools panel with theme tokens
2026-09-01 13:58:03 -07:00
Yassin Kortam
aab9abdd1d
fix: keep litellm_credential_name from LiteLLM Params JSON and gate stored credential attach to proxy admins (#39047)
* fix(ui): keep litellm_credential_name from LiteLLM Params JSON when no credential is selected

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

* test(ui): drop null litellm_credential_name from AddModelPanel payload fixture

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

* fix(ui): validate JSON litellm_credential_name against accessible credentials

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

* fix(proxy): enforce proxy-admin-only credential attachment on model create/update

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

* fix(proxy): raise ProxyException for unauthorized credential attach and gate /model/update

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

* refactor(proxy): fold credential-change detection into can_user_attach_credential to satisfy complexity budget

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

* fix(proxy): decrypt stored credential name before unchanged-credential comparison

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

* test(proxy): cover credential attach rejection on add_new_model and patch_model

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

* test(proxy): annotate proxy-global patches with test-quality suppressions

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-01 13:46:18 -07:00
ryan-crabbe-berri
6d6c9af4ab
Merge pull request #39155 from BerriAI/litellm_agent_hub_search
feat(ui): add search to the Agent Hub tab and admin agents table
2026-09-01 13:36:36 -07:00
Yuneng Jiang
116efee3f7
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_ui_select_popup_race 2026-09-01 12:42:33 -07:00
Yuneng Jiang
eb53639ecb
test(ui): pick select options by role instead of by text
Clicking a Base UI select entry found by text or by a title attribute is a
race. The text node exists one render before the popup finishes entering,
and until then the positioner still carries pointer-events: none, so
user-event refuses the click and the test throws. Querying by role only
matches once the popup is exposed to the accessibility tree, which is after
that window closes.

Route the 37 remaining select interactions through chooseSelectOption, which
does the role query. Instrumenting the converted files shows the text query
resolving while the popup was still pointer-blocked on 6 of 41 samples; the
role query was never blocked.

Seven files kept their text queries because their popup entries carry no
accessible role, so there is nothing to query by.
2026-09-01 12:42:27 -07:00
mateo-berri
6012f893fa Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_s3_vectors_search 2026-09-01 12:27:29 -07:00
mateo-berri
753f3705d0 Merge litellm_internal_staging (4c3ef9ae0a) into litellm_fix_s3_vectors_search 2026-09-01 12:27:23 -07:00
Mateo Wang
435433fa07
Merge pull request #39149 from BerriAI/litellm_qwencloud_provider_aliases
feat(dashscope): add QwenCloud and Qwen AI Platform provider aliases
2026-09-01 12:18:05 -07:00
yuneng-jiang
75f0a22fc6
Merge pull request #39130 from BerriAI/litellm_dark_mode_skill_detail
fix(ui): render the skill detail page with theme tokens
2026-09-01 11:52:57 -07:00
ryan-crabbe-berri
d9f7f9ea16 feat(ui): add search to Agent Hub tab and admin agents table
Ports the Model Hub search to the AI Hub Agent Hub tab and the admin
/agents toolbar as a client-side filter over agent name and description.
Extracts the hub search matching into utils/searchUtils and fixes the
public Model Hub rendering the whole catalog when a search matches
nothing (LIT-5230)
2026-09-01 11:46:58 -07:00
mateo-berri
f3792fb700 feat(dashscope): add qwencloud and qwen_ai_platform provider aliases 2026-09-01 11:20:36 -07:00
ryan-crabbe-berri
720c1fa28c
Merge pull request #39108 from yatishgoel/bugfix/form-field-checkbox-width
fix(ui): stop checkboxes stretching to the full width of a form field
2026-09-01 11:03:36 -07:00
mubashir1osmani
fba4c1aac3 test(ui): assert the resolved checkbox layout, not just data-orientation
The invite-dialog test only read data-orientation, so a regression inside
the shared field variants could restore the full-width bar and still pass.
Assert the classes that carry the layout, cover the two SSO call sites the
fix also changed, and pin the vertical/horizontal contract on the primitive.
2026-09-01 13:54:54 -04:00
Yuneng Jiang
8acdb92087
fix(ui): keep the skill detail copy buttons transparent
bg-none only clears background-image, so the buttons fell back to the
browser's default button background instead of the transparent one the
inline style had.
2026-09-01 10:27:43 -07:00
Yuneng Jiang
a5f9410681
test(ui): wait for the select popup before clicking its option
key_edit_view opened a select and then clicked the option it found by
title text or by raw text. Both queries match the moment the option
enters the DOM, which is one render before the popup finishes entering.
Until then the positioner still carries an inline pointer-events: none,
and user-event refuses to click through it.

That is a race, and a fast machine loses it. Five of the file's 84 tests
failed on every local run while CI stayed green, which is the worst shape
for a test to have: it is only ever red on the machine of whoever is
trying to change the code.

tests/test-utils.tsx already ships chooseSelectOption for exactly this.
It finds the option by role and waits for the positioner to release
pointer events before clicking. The five call sites now use it, and the
helper takes the direct user-event API as well as a setup() instance so
callers do not have to restructure to use it.

Five consecutive full-file runs pass where every previous run failed.

Also finishes this file's screen queries, which brings
prefer-screen-queries to its target of 18.
2026-09-01 09:46:43 -07:00
Yuneng Jiang
2757399c99
fix(ui): render the skill detail page with theme tokens
The page painted every surface, border and text color inline with a
fixed light palette (#202124, #5f6368, #dadce0, #f8f9fa, #fff), so in
dark mode it drew dark text on hardcoded white cards.

Move the whole component to the foreground/muted/border/card/info
tokens, which already resolve for both themes.
2026-09-01 09:43:47 -07:00
Yuneng Jiang
5c0e3d738f
fix(ui): render the logs Tools panel with theme tokens
The tool cards hardcoded light colors as inline styles (#fff, #fafafa,
#f0f0f0, #f6ffed), so in dark mode the theme's light foreground text
landed on a white card and became unreadable.

Swap the inline hex for the existing card/muted/border/success tokens,
which already carry both light and dark values.
2026-09-01 09:41:51 -07:00
yatishgoel
054acb2223 fix(ui): stop checkboxes stretching to the full width of a form field 2026-09-01 17:05:08 +05:30
Yuneng Jiang
c5ba2b5fcf
test(ui): query the screen instead of the render result
Two changes, both about finding elements the way a user finds them.

Twenty-six test files destructured queries off render and called them
bare. Those queries are scoped to the render container, so they quietly
miss anything portalled into the body, and they read as if they were
free functions. They now go through screen.

ChatMessageBubble and the key info panel derived elements by walking
closest/parentElement/firstElementChild and then asserted on the classes
they found. A wrapper element anywhere in between broke them. The bubble
surface, the avatar and the budget reset value now publish a test id, so
the assertions survive markup changes and still fail when the styling
they check actually regresses.

Budgets drop with the counts: prefer-screen-queries 221 to 21,
no-node-access 723 to 716.

The 21 remaining prefer-screen-queries are not all fixable: 18 of them
are within(dialog) results in MCPToolsetsTab, which the rule cannot tell
apart from a render result. Target is 18, not 0.
2026-09-01 00:26:49 -07:00
Yuneng Jiang
2fbea77afa
test(ui): assert DataTable behavior instead of DOM structure
The shared DataTable test reached for elements by CSS selector and by
walking parentElement chains, then asserted on Tailwind class strings. It
had no role queries at all, so a wrapper div anywhere in the render tree
broke it while changing nothing a user sees.

Columns, rows and headers are now found the way a user finds them: by
role and by the text on screen. The compact skeleton row is compared
against the loaded row's height rather than a hard-coded h-8, so renaming
the class no longer breaks the test but shrinking the row still does.

The fillHeight and maxBodyHeight cases stay class assertions. jsdom has
no layout engine, so there is nothing behavioural to assert there. What
they no longer do is derive their elements from incidental nesting: the
three layout wrappers and the header now publish a stable test id, which
is also why the resizer's write-only data-resizer attribute became one.

Budgets drop with the counts: no-container 150 to 133, no-node-access 760
to 723.
2026-09-01 00:19:27 -07:00
tin-berri
db46973ec4
feat(ui): modality routing toggle on the auto-router create and edit forms (#39059) 2026-08-31 23:08:40 -07:00
tin-berri
4a24be886d
feat(ui): one classification frequency picker for complexity auto-routers (#39042)
Classification timing and session affinity are the same operator question,
so Advanced: Classification Method now carries a single "How often to
classify" radio: every request, every new user message, or once per session.
The session choice writes session_affinity and stays disabled on custom tier
sets, where the backend rejects it. Advanced: Affinity keeps the deployment
switch alone.

The serializer always writes classification_mode, matching session_affinity
on the line below it, so an explicitly stored every_request survives an
untouched save instead of being dropped back to the backend default.
2026-08-31 22:12:59 -07:00
tin-berri
502b3a2f79
feat(ui): auto-router controls for context-window escalation (#39054)
* feat(ui): auto-router controls for context-window escalation

Adds an Advanced: Context Window Escalation section to the auto-router
form, both create and edit arms, with the toggle for
enable_context_window_escalation and a clamped decimal input for
context_window_escalation_buffer. An untouched control keeps both keys
out of the payload so the router tracks the backend defaults; an
explicit opt-out (false) survives the edit round-trip through the
managed-keys projection and the hydrator, and preset prefill maps both
keys straight through so a preset cannot silently drop them

Resolves LIT-6601

* fix(ui): clearing the context-window buffer removes it from the payload

Both review bots converged on the same defect: an emptied buffer field
early-returned in commitBuffer, the draft was discarded on blur, and the
stale number reappeared and stayed in the saved config, contradicting
the copy that an empty field tracks the backend default. An empty commit
now removes the key, which the managed-keys projection propagates as a
real deletion on edit. Also trims the narrative comments the review
flagged as restating behavior
2026-08-31 20:02:08 -07:00
tin-berri
0565d33fa5
fix(ui): let the auto-router scoring tier list follow the theme (#39040)
* fix(ui): let the auto-router scoring tier list follow the theme

* test(ui): assert the tier list carries the muted-foreground token
2026-08-31 19:55:16 -07:00
tin-berri
8d6d7f9ce9
feat(complexity_router): opt-in modality-based capability routing for image requests (#39032) 2026-08-31 19:51:41 -07:00
Yassin Kortam
b473339ac0
Revert "fix(ui): keep litellm_credential_name from LiteLLM Params JSON when n…" (#39046)
This reverts commit 33cc9c1c48.
2026-08-31 18:00:29 -07:00
devin-ai-integration[bot]
33cc9c1c48
fix(ui): keep litellm_credential_name from LiteLLM Params JSON when no credential is selected (#39005)
* fix(ui): keep litellm_credential_name from LiteLLM Params JSON when no credential is selected

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

* test(ui): drop null litellm_credential_name from AddModelPanel payload fixture

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-31 17:55:53 -07:00
Yuneng Jiang
3eb1eee1fa
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/flaky-e2e-tests-d022f6 2026-08-31 15:57:51 -07:00
tin-berri
296bde0d0d
feat(complexity-router): add classification_mode to skip classifier on continuation turns (#38861) 2026-08-31 15:50:04 -07:00
Yuneng Jiang
9c577c6045
test(e2e): assert user-observable behavior instead of DOM structure
The UI e2e suite had a class of assertions that pin how the dashboard is
built rather than what it does, so an ordinary refactor turns them red
without any user-visible change.

Geometry. The auto-router template select had two tests made of pixel
arithmetic plus a data-side="bottom" check, which is Base UI's own
positioner signal. The regression they guard (#38554) is a popup opening
on top of the control that spawned it, so both cases collapse to one
invariant: the options never cover the trigger. It now runs at both
viewport heights and reads the popup as role=listbox. The models header
test compared the tabs and refresh centers within 2px, which a padding
change flips; it now asserts the two share a row.

Structure. The logs drawer test walked xpath=../../.. from a text node
and read collapsed state off chevron icon classes. SectionHeader now
renders a real disclosure button with aria-expanded, and its two copy
buttons carry distinct names instead of both being "Copy". Sidebar group
toggles expose aria-expanded too, so the migration spec can ask for a
collapsed group by state rather than by nesting depth.

Positional lookups. keyRow.locator("button").first(), row.locator("td")
.first() and getByTestId(grid).locator("div").first() all named a
position where they meant an action; they now name the control. Table
scoping moves from "table tbody" to role=row.

Timing. Nine waitForTimeout calls are gone. Every assertion that followed
them already retried to its own timeout, so the sleeps only slowed the
run down.

Both files under tests/users/ were wrapped in test.skip("...", () => {}),
which registers one skipped test and never runs the body, so the four
tests inside had never executed and were written against a UI that has
since changed (the search placeholder is "Search by email…", the ID
filters moved into a drawer, pagination is labelled "Go to previous
page"). Rewritten against the current surface: the suite goes from 104
collected tests to 107.

Left in place deliberately: the chip and dialog-footer data-slot
selectors, because the accessible names they work around live in
components/ui/, which is shadcn CLI-managed and not hand-edited.
2026-08-31 14:04:15 -07:00
mateo-berri
59732f068b Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gigachat_passthrough_25886 2026-08-31 13:16:41 -07:00
devin-ai-integration[bot]
f079e4061b
fix(proxy): deliver budget alerts on webhook-only alerting and accept ALERTING_WEBHOOK_URL (#38441)
* fix(proxy): deliver budget alerts on webhook-only alerting and accept ALERTING_WEBHOOK_URL

ProxyLogging.budget_alerts forwarded to the alerting pipeline only when
'slack' was in general_settings.alerting, so alerting: ['webhook'] plus
WEBHOOK_URL silently never delivered a budget alert (the config
/health/services?service=webhook exists to test). Forward when 'webhook'
is present too; SlackAlerting.send_alert already fans out per channel.

Also accept a provider-neutral ALERTING_WEBHOOK_URL env fallback for the
Slack-format channel (any Slack-compatible receiver works), mark it as a
sensitive var, and de-brand the admin UI alerting copy.

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

* fix(ui): format settings.tsx with prettier

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

* chore(ui): regenerate schema.d.ts for updated alerting description

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

* ci: retrigger checks after ALERTING_WEBHOOK_URL docs merged

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-31 09:22:36 -07:00
mateo-berri
70e2f4e68f Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gigachat_passthrough_25886
# Conflicts:
#	litellm/llms/gigachat/chat/transformation.py
2026-08-29 22:08:54 -07:00
mateo-berri
74fb398f9b fix(ui): hide model write affordances from view-only admin sessions 2026-08-29 21:40:28 -07:00
Yuneng Jiang
795c036279
fix(ui): drop stray text next to Close in the model connection test dialog
The Add Model page's connection test dialog rendered a literal ", ]" beside the Close button, left over from converting an array of footer buttons into JSX children.
2026-08-29 17:26:38 -07:00
Mateo Wang
ff2f06e37f
Merge pull request #38444 from BerriAI/litellm_mcp_connector_bulk_import
feat(mcp): bulk-import Anthropic MCP connectors via API and admin UI
2026-08-29 17:21:57 -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
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
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-berri
177463e9b0 Merge branch 'litellm_internal_staging' into litellm_mcp_connector_bulk_import
Regenerates the lazy OpenAPI snapshot and dashboard schema.d.ts from the merged tree.
Passes list/dict copies into NewMCPServerRequest from the connector conversion and switches the
server-managed NewMCPServerRequest fields to keyword defaults so the basedpyright budget gate stays flat.
2026-08-29 12:49:45 -07:00
Yuneng Jiang
08c83c12e9
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/logs-reopen-shadcn-migration-2c9526 2026-08-29 11:55:20 -07:00
Yuneng Jiang
4a3dcd5e8e
refactor(ui): give the collapsed log drawer its own sidebar toggle
Open, the trace sidebar is byte-identical to before: the toggle sits over its
header exactly where it did, and the header keeps the padding that makes room
for it. Collapsed, that button has nowhere to live, so the drawer header shows
one instead, on the model row or the request id row when the log names no
model.

Both come from SidebarToggle, so they cannot drift in design. The chevrons now
point the way the sidebar will move: right while it is open, left while it is
collapsed.
2026-08-29 11:53:14 -07:00
Yuneng Jiang
20e6d6457a
refactor(ui): show the log drawer's sidebar toggle only where it has a row
Putting the toggle in the drawer header unconditionally stranded it on its own
line: the model row renders empty for a log that names no model or provider, so
the chevron sat alone above the request id.

The sidebar keeps the toggle whenever it is open, in its own header. Collapsed,
the toggle moves into the drawer header and joins the model row, or the request
id row when there is no model to join. Shared between both through
SidebarToggle so the two call sites cannot drift.
2026-08-29 11:48:04 -07:00