Commit graph

118 commits

Author SHA1 Message Date
Yuneng Jiang
0253154780
build(deps-dev): bump js-yaml to 4.3.1
Closes GHSA-5p4m-2wfm-xmqj (CVSS 7.5), flagged by osv-scan against
ui/litellm-dashboard/package-lock.json. js-yaml is pinned by an exact
npm override, so the override and the lock move together.

Dev-only dependency: js-yaml reaches the tree through eslintrc, knip
and @redocly/openapi-core, none of which ship in the built dashboard.

4.3.1 published 2026-07-31, clear of the 3-day min-release-age cooldown.
2026-08-06 18:14:26 -07:00
ryan-crabbe-berri
2dc49a913c
refactor(ui): replace hand-rolled query-param routing with nuqs (#35871)
* refactor(ui): replace hand-rolled query-param routing with nuqs

The dashboard carried five copies of the same pushState-based detail
routing hook plus a shared navigateWithParams helper, each with its own
plumbing test and a copy-pasted reactive useSearchParams mock in
component tests. nuqs provides the same shallow history-API routing
behind useQueryState/useQueryStates, so the key, team and org hooks are
deleted in favor of inline useQueryState at their single consumers,
while the models and logs hooks keep their interfaces but drop their
hand-rolled internals. Component tests now mount NuqsTestingAdapter
(via renderWithProviders or locally) instead of patching window.history,
and URL assertions go through onUrlUpdate spies that can additionally
distinguish push from replace, which the old window.location checks
could not

* test(ui): assert browser back closes the log drawer after in-drawer selection

Greptile flagged that the nuqs port of the switching-logs test stopped
at asserting emitted push and replace modes. The test now replays those
recorded modes against a history stack and performs the back step, so a
regression to push-on-select or broken URL-derived drawer state fails
the test instead of passing silently
2026-08-05 13:29:58 -07:00
Yuneng Jiang
64aab7be85
ci: pin Node on the Playwright UI lanes so npm ci meets the engines floor
e2e_ui_testing and e2e_ui_testing_server_root_path run on
cimg/python:3.12-browsers, the one UI executor whose image supplies Node
rather than taking it from a cimg/node tag. That image ships Node 24.14.0,
which bundles npm 11.9.0, so both lanes have failed EBADENGINE against the
engines floor added in #35801. Every Node 24 release through 24.14.0 bundles
an npm below 11.10.0, so engines.node also rises to 24.14.1 (npm 11.11.0),
the first release where the two floors agree

The pinned install goes into /opt/node with /opt/node/bin prepended to PATH
instead of unpacking over /usr/local. On this image /usr/local already holds
npm 11.9.0, and extracting the tarball on top of it merges the two trees into
an npm that reports 11.17.0 and then exits 1 on npm ci printing no error text
at all, which is a worse failure than the one being fixed

The install moves into a reusable install_node command so the version and its
checksum have one home, shared with proxy_pass_through_endpoint_tests, and the
command refuses to run when it disagrees with ui/litellm-dashboard/.nvmrc. A
lane drifting off the version the rest of the toolchain uses is what produced
this failure, so that mismatch now stops the job instead of surfacing later as
an install error

The e2e node_modules cache key moves to v4 because the saved trees were built
by the old npm
2026-08-04 16:31:38 -07:00
yuneng-jiang
487074f602
chore(build): move the Admin UI toolchain to Node 24 (#35801)
* chore(build): move the Admin UI toolchain to Node 24

Node 18 and Node 20 both reached end of life (2025-04-30 and 2026-04-30), and
the release images along with every CI lane were still building on them. Node 24
is the current LTS through 2028-04-30, so this moves the four UI build images,
the CircleCI lanes, and the four GitHub Actions workflows onto it

Node 24 also ships npm 11.17, which is the first line that implements the
min-release-age setting this repo already carries in its .npmrc files. On npm 10
the key is parsed and discarded, so the release-age gate has had no effect
regardless of its value. Tightening the dashboard's engines range and turning on
engine-strict makes an unsupported npm fail loudly rather than skip the gate
quietly, and a new step in the UI build workflow probes an impossible cooldown
so an inert setting cannot pass unnoticed again

Node 24's bundled undici tightened its brand check on RequestInit.signal, which
rejects the AbortSignal jsdom installs and broke the two cases in
src/lib/http/api.test.ts that rebase a request onto a runtime base url. Under
jsdom the Request global comes from Node while AbortSignal comes from jsdom;
tests/jsdomFetchEnv.ts delegates to the jsdom environment and then restores
Node's native AbortController and AbortSignal so both come from one realm.
Upgrading jsdom does not address this, as jsdom still does not own Request

The workflows now read ui/litellm-dashboard/.nvmrc instead of repeating a
literal, so the Node version has a single source of truth, and ui/Dockerfile is
pinned by digest to match the other three build images. The lockfile changes are
npm 11 normalising the engines range and dropping optional peer entries it no
longer records

* fix(build): point every Admin UI build script at .nvmrc

The enterprise Docker path was left on Node 18. docker/build_admin_ui.sh runs
only when enterprise/enterprise_ui/enterprise_colors.json is present, which it
never is in the OSS tree, so neither CI nor a default image build reaches it;
it pinned nvm to v18.17.0 and then built the dashboard, which now requires Node
24, so a customized enterprise image would have failed EBADENGINE

All three UI build scripts now resolve the version from
ui/litellm-dashboard/.nvmrc rather than carrying their own pin, so the Node
version has a single home across Docker, CI, and local builds. build_ui.sh was
on v20 and build_ui_custom_path.sh on v18.17.0

Also drops the dependency-cooldown probe from the UI build workflow. The
engines floor plus engine-strict already fails an unsupported npm loudly at
install time, so the probe was redundant, and treating any nonzero exit from a
live registry call as proof of enforcement made it unsound besides
2026-08-04 12:36:07 -07:00
Yuneng Jiang
3bc4989ce4
chore(ui): update brace-expansion and postcss to current patch releases
The dashboard pins both packages exactly in `overrides`, so the lockfile
stays on whatever those pins say. Move brace-expansion from 5.0.8 to 5.0.9
and postcss from 8.5.22 to 8.5.23, both upstream patch releases, and
regenerate the lockfile.

`npm ci`, `next build`, and the 5888-test vitest suite all pass on the
updated lockfile.
2026-08-03 13:15:32 -07:00
Yuneng Jiang
c9d067fccc
chore(deps): bump gitpython to 3.1.55 and brace-expansion to 5.0.8
gitpython arrives transitively through mlflow-skinny; re-resolved with uv so the
lock moves that one package only. brace-expansion is a dev-only transitive dep
already pinned in the dashboard 'overrides' block, so the pin is bumped
alongside the lockfile to keep the change durable across reinstalls.

5.0.8 narrows its engines range from '18 || 20 || >=22' to '20 || >=22'; the
dashboard already requires node >=20.9.0 and every CI job pins node 20, so
nothing loses support.
2026-07-27 10:06:50 -07:00
Yuneng Jiang
3467871007
chore(deps): bump gitpython and postcss to advisory-clear versions
Clears five OSV findings the scanner flags on every PR: four gitpython
advisories fixed in 3.1.54, and one postcss advisory fixed in 8.5.18.

gitpython 3.1.55 and brace-expansion 5.0.8 are left for a follow-up; both
were published less than three days ago and are still inside the
dependency cooldown window.
2026-07-25 10:29:06 -07:00
yuneng-jiang
301a02b7be
chore(ui): bump next to 16.2.11 (#34329)
Moves the dashboard's next pin from 16.2.6 to the latest 16.2.x patch and bumps eslint-config-next to match. Regenerating the lock also healed in explicit bundled-dependency records under @tailwindcss/oxide-wasm32-wasi
2026-07-22 17:29:29 -07:00
ryan-crabbe-berri
0fcaadf11c
test(e2e): move Admin UI Playwright suite to tests/e2e/ui (#34196)
Relocates ui/litellm-dashboard/e2e_tests to tests/e2e/ui so all end to end
suites live under tests/e2e. The suite stays in TypeScript and becomes a
self-contained npm package with its own package.json, lockfile and tsconfig
instead of leaning on the dashboard's toolchain; the dashboard drops its
@playwright/test dependency, e2e scripts and knip/vitest/tsconfig carve-outs.

CI paths follow the move: both CircleCI jobs (main e2e and the
SERVER_ROOT_PATH migration smoke) and the test_server_root_path workflow now
install and run Playwright from tests/e2e/ui, with the node cache keyed on
both lockfiles. classify_changes.sh treats tests/e2e/ui as client so spec
edits keep skipping backend jobs. The suite's mock LLM fixture is excluded
from the e2e basedpyright zero-error gate in pyrightconfig.json since it
belongs to the TS suite, not the typed Python harness.
2026-07-22 19:43:10 +00:00
yuneng-jiang
20a4666ec6
chore(ui): bump sharp to 0.35.x via npm override (#34193)
sharp reaches the dashboard only as an optional dependency of next, which
pins it to ^0.34.5. A caret range on a 0.x version cannot resolve past
0.34.x, and every stable next through 16.2.11 still declares that same
range, so there is no transitive path to the 0.35 line. Add an overrides
entry, matching how the other pinned transitives in this package are
already handled.

The dashboard builds with output: "export" and images.unoptimized, so
sharp is never loaded; this keeps the lockfile current rather than
changing runtime behaviour.
2026-07-21 17:03:31 -07:00
yuneng-jiang
72d458e416
feat(ui): add react-hook-form + zod form infrastructure (#34170)
* feat(ui): add react-hook-form + zod form infrastructure

Introduce the shared form layer the dashboard's antd forms will migrate onto,
with no user-visible change yet.

- pin react-hook-form, @hookform/resolvers, and zod (kept on 3.25.76 and
  imported via the zod/v4 entrypoint so openai's optional zod ^3 peer still
  resolves and npm ci stays clean)
- vendor the base-vega Field family into components/shared/form as forwardRef
  components on the repo's cva.config, since base-vega ships no form primitive
  and its field source imports class-variance-authority and is React 19 style
- add a FormField bridge that binds a react-hook-form Controller to the Field
  layer and wires label, description, and error ids into aria attributes
- add pickDirty, which narrows a submitted body to the top-level keys the user
  actually touched so a partial update stops re-sending untouched fields

pickDirty reads dirtiness at the top level because react-hook-form tracks it
per leaf, so an edited array arrives as [true, false] and a cleared list as an
empty array that still carries its default-length dirty markers; the falsy
clear tokens (null, [], {}, 0, false) all survive.

Tests cover the Field primitives, the FormField aria wiring against a live
zod resolver, and pickDirty both as a unit and driven through a real
react-hook-form instance.

* test(ui): lock pickDirty behavior on a pure field-array reorder

react-hook-form compares each array element to its default positionally by
value, so useFieldArray move/swap and a reordered scalar array all mark the
moved indices dirty and pickDirty sends the whole array; a swap of two equal
elements is a value-level no-op and is correctly omitted. Covers the reorder
case a review flagged as untested.
2026-07-21 15:17:58 -07:00
Yuneng Jiang
f2ca0a149b
build(deps-dev): bump js-yaml to 4.3.0 and brace-expansion to 5.0.7
Both are dev-only build and lint tooling in the dashboard, not part of the
browser bundle. The bumps pull in upstream maintenance releases that address
inefficient handling of certain inputs

js-yaml is force-pinned through the overrides block because
@redocly/openapi-core exact-pins an older copy; a plain lockfile change would
not hold since the tree re-spawns a nested stale version on re-resolution, so
the override moves from 4.2.0 to 4.3.0. brace-expansion is added to overrides
at 5.0.7 so npm install does not leave the previously resolved 5.0.6 in place.
Both resolve to a single deduped copy after the change
2026-07-20 17:46:20 -07:00
ryan-crabbe-berri
539bc30e04
refactor(ui): migrate callback debounce sites to react-pacer with regression tests (#33043)
* refactor(ui): standardize debounce waits behind shared DEBOUNCE_WAIT_MS constant

* build(ui): bump @tanstack/react-pacer from 0.2.0 to 0.22.1

* refactor(ui): migrate straightforward value debounces to react-pacer

* refactor(ui): migrate callback debounce sites to react-pacer with regression tests

* chore(ui): restore trailing newline in eslint-suppressions.json

* test(ui): mock all pacer debounce hooks in VirtualKeysTable test

* fix(ui): update merged debounce tests for OldTeams to Teams rename
2026-07-13 15:38:34 -07:00
ryan-crabbe-berri
3a42011350
build(ui): bump @tanstack/react-pacer from 0.2.0 to 0.22.1 (#33041)
* refactor(ui): standardize debounce waits behind shared DEBOUNCE_WAIT_MS constant

* build(ui): bump @tanstack/react-pacer from 0.2.0 to 0.22.1
2026-07-13 13:38:15 -07:00
ryan-crabbe-berri
d0428cdd53
ci(ui): report only error-level knip findings in CI (#32971) 2026-07-12 21:27:55 -07:00
ryan-crabbe-berri
8c5473f198
feat(ui): adopt openapi-react-query ($api) and convert useCustomers (#32949)
* feat(ui): adopt openapi-react-query and convert useCustomers to $api

Add openapi-react-query and expose $api = createQueryClient(fetchClient)
alongside fetchClient. Rewrite useCustomers as
$api.useQuery("get", "/customer/list", {}, { enabled, select }), which
derives the query key from method + path (dropping the hand-written
createQueryKeys entry and the manual key) and forwards the request signal
for cancellation. The response type still flows from schema.d.ts as
CustomerResponse[]. Tests assert the path, the admin/token enabled gate,
and the empty-body select fallback.

* test(ui): read the last render's options in useCustomers helper

The lastCallOptions helper was named for the last call but read
mock.calls[0]. Harmless while each test renders once, but it would
silently assert against first-render options if a test ever re-renders.
Read the final call instead.
2026-07-11 18:01:33 -07:00
Yuneng Jiang
7cdf42d770
chore(ui): remove eslint-metrics.json lint-count snapshot
The eslint-metrics.json snapshot duplicated the violation counts already
enforced by eslint-budgets.json. Keeping it current added a CI drift check,
a pre-commit regenerate-and-flag step, and a standalone npm run lint:metrics
script, none of which caught anything the budget gate did not, yet all of
which failed noisily whenever the snapshot went stale. This drops the file
and that machinery while leaving eslint-budgets.json as the actual ratchet
gate
2026-07-11 11:54:42 -07:00
ryan-crabbe-berri
0bf81e2496
feat(ui): typed openapi-fetch foundation (fetchClient) + first typed caller (useCustomers) (#29884)
* feat(ui): add the typed openapi-fetch client (fetchClient) as the dashboard fetch foundation

Introduces fetchClient (openapi-fetch) bound to schema.d.ts, used inside ordinary TanStack Query hooks so path/query/body types come from the proxy's OpenAPI spec. A small runtime registry feeds the client the base URL and auth header name (registered by networking) and the session token (published by AuthContext), so call sites carry no token plumbing; auth-header injection and ApiError mapping live in openapi-fetch middleware reusing deriveErrorMessage/ApiError from client.ts, and non-2xx maps to a thrown ApiError so query functions just read .data.

The base URL default resolves from NEXT_PUBLIC_BASE_URL so a request still targets the right origin if it fires before networking registers its getter. AuthContext clears accessToken alongside the token on logout so no query fires unauthenticated after the session ends.

Foundation only; callers migrate one at a time, each fully typed, in follow-up changes.

* feat(ui): migrate useCustomers to the typed fetchClient

Converts useCustomers from allEndUsersCall to fetchClient.GET("/customer/list"); the response is typed as LiteLLM_EndUserTable[] from the schema, so the hand-written Customer/CustomersResponse types are deleted. They were also inaccurate (allowed_model_region was string but is "eu"|"us", and a budget_id the table has no field for). No cast; the schema type flows to the one consumer. First caller on the new pattern.

* fix(ui): route typed-client errors through the session-expiry handler

The typed fetchClient middleware threw ApiError without invoking the
handleError side effect that the legacy createApiClient wires via
onError, so a migrated caller hitting an expired key no longer triggered
the auto-logout. Add an error-handler seam to runtime.ts, register
handleError from networking.tsx alongside the base-url/header getters,
and call it in the middleware before throwing so both clients behave the
same. Regression test asserts the handler fires with the derived message
on non-2xx and stays silent on success

* fix(ui): point the customers EndUser type at CustomerResponse

The /customer/list response model was renamed to CustomerResponse on
staging; the merged branch still aliased EndUser to LiteLLM_EndUserTable,
so the exported type and its test mock had drifted from what the schema
actually returns. CustomerResponse is also the accurate shape (it types
allowed_model_region as 'eu' | 'us' and carries budget_id)

* chore(ui): refresh eslint-metrics baseline after staging merge

The recorded baseline predated the litellm_internal_staging merge, so its
no-explicit-any and no-large-inline-object-arg counts were higher than the
merged tree actually has. Regenerate via npm run lint:metrics so the gate
reflects current reality

* refactor(ui): source the typed client token from the session cookie, not AuthContext

The typed client read its bearer from a runtime value that AuthContext pushed
via setAuthToken, but migrated hooks gate enabled on useAuthorized, which
decodes the cookie directly. Two independent derivations of the same cookie with
different timing: on first load the query fires (useAuthorized sees the token)
before AuthContext's async effect publishes it, so the first request goes out
unauthenticated and only succeeds on a React Query retry.

Make the token a registered getter like the base-url and header-name getters,
reading the same cookie useAuthorized decodes, so the client's token and the
gate can't diverge. Revert the AuthContext changes entirely; nothing is pushed
from React state anymore.
2026-07-11 10:50:51 -07:00
ryan-crabbe-berri
e2eee36438
chore(ui): make knip trustworthy and enforce dead-code in CI (#32727)
knip was producing garbage locally and was never wired into CI, so nobody
trusted it. Two structural problems: it silently degrades when deps are
missing (a partial worktree install flagged all 436 test files as unused),
and its config had blind spots that surfaced as false positives.

Fixes so a knip run means something:

- Register every playwright config (serverRootPath + migration variants), not
  just the main one. serverRootPath.config.ts is invoked via --config in
  test_server_root_path.yml, which knip can't see; it was falsely flagged as
  an unused file
- Treat src/components/ui/** as entry points. These are shadcn design-system
  primitives, intentionally part of the palette before every one is consumed;
  knip was flagging not-yet-used ones (e.g. select.tsx) as dead files and
  their sub-exports as unused. Marking the directory as the design-system
  surface is the correct fix, not deleting components someone is about to use
- Declare @ant-design/icons as a direct dependency. It was imported in ~198
  files but only resolved via antd hoisting, so every one showed up as an
  "unlisted dependency"
- Add an explicit vitest plugin block so test-file classification no longer
  rides on auto-detection
- Stage severities via rules: gate the now-clean categories (files,
  dependencies, unlisted, unresolved) as errors and keep exports/types/
  duplicates as warnings, so CI enforces what's at zero today while the
  remaining findings ratchet down in follow-ups
- Run npm run knip in the frontend-lint CI job, which installs with npm ci so
  it never sees a partial tree

knip now exits 0 with the gated categories clean
2026-07-10 11:50:27 -07:00
ryan-crabbe-berri
592510ec18
feat(ui): shadcn charts foundation with tremor-compatible wrappers (#32668) 2026-07-09 18:18:52 -07:00
ryan-crabbe-berri
cfe9e39e55
refactor(ui): switch shadcn primitives from Radix to Base UI (#32124)
* refactor(ui): switch shadcn primitives from Radix to Base UI

shadcn made Base UI the default primitive library in July 2026 and our
only shadcn component so far is the Button canary, so this is the last
cheap moment to switch before the primitives phase adds the full set.

components.json style moves from new-york (a legacy alias that resolves
to the Radix variant) to base-vega. Button is regenerated from the
base-vega registry with the same local adaptations as before: cva beta
object form via lib/cva.config and a React 18 forwardRef wrapper. The
polymorphic asChild prop becomes Base UI's render prop.

radix-ui is replaced by @base-ui/react 1.6.0. Base UI optionally peers
on date-fns 4 while tremor pins 3, so date-fns is bumped to 4.4.0 with
an npm override; our only usage (add) is API-identical and the override
can go away when tremor does.

* refactor(ui): convert chat UI shadcn components from Radix to Base UI

The chat UI migration landed 11 components/ui files generated against
the old Radix registry config after this branch cut over to Base UI,
which would have left them importing a deleted package. All 11 (dialog,
alert-dialog, select, popover, tooltip, tabs, switch, scroll-area,
collapsible, separator, label) are regenerated from the base-vega
registry, with the repo conventions re-applied where relevant (cva beta
object form from lib/cva.config in tabs; the Button canary keeps its
React 18 forwardRef adaptation).

Chat feature call sites move from the Radix asChild pattern to Base
UI's render prop, and TooltipProvider delayDuration becomes delay.

* fix(ui): restore security override pins clobbered by the date-fns override

The date-fns 4 override was written by replacing the whole overrides
object, dropping the ten security pins (prismjs, js-yaml, glob,
minimatch, lodash, ws, braces, axios, postcss, esbuild) that keep
patched versions in the lockfile; osv-scan caught the vulnerable
versions resurfacing. Restores the pins alongside date-fns and
regenerates the lockfile.

* test(ui): pin tremor DateRangePicker behavior on date-fns 4

The date-fns 4 override forces react-day-picker 8 (authored against v3)
onto v4 at runtime, which a build or lint pass cannot validate. This
renders the shared UsageDatePicker wrapper, opens the calendar, checks
the month grid, and selects a day, so a date-fns API break in the
tremor date path fails tests instead of throwing in production. Delete
alongside the override when tremor is removed.

* fix(ui): close the alert dialog when AlertDialogAction is clicked

The base-vega registry template renders AlertDialogAction as a plain
Button with no Close binding, so confirm buttons fired their onClick
but left the dialog open; both consumers (conversation delete,
MCP credential revoke) were written against the Radix semantics where
Action dismisses on click. Binds Action to AlertDialogPrimitive.Close
via the render prop, mirroring AlertDialogCancel, and pins the
behavior with a test so a future shadcn add --overwrite cannot
silently reintroduce the template's non-closing Action.
2026-07-07 09:55:41 -07:00
Krrish Dholakia
e06adb5588
feat(ui): re-add chat UI, allow simple UI for MCP OBO auth (#31893)
Some checks are pending
GitHub Actions Security Analysis / zizmor (push) Waiting to run
2026-07-03 12:36:36 -07:00
ryan-crabbe-berri
27069bd74f
feat(ui): shadcn migration foundation: Tailwind v4, shadcn init, antd cascade fix (#31995)
* feat(ui): shadcn migration foundation: Tailwind v4, shadcn init, antd cascade fix

Upgrade the dashboard from Tailwind v3 to v4 with CSS-first config: the
official upgrade codemod renamed utilities across 151 files, and
tailwind.config.js (plus the dead tailwind.config.ts) is replaced by
@theme tokens, @source globs, and @plugin directives in globals.css. The
Tremor safelist becomes @source inline patterns and the legacy tremor
theme tokens carry over verbatim. ui_colors.json was build-time only and
fed the dying Tremor palette, so its brand values are inlined and the
file removed; runtime theming replaces that path next.

shadcn is initialized with a hand-authored components.json (rsc,
cssVariables, baseColor gray) pointing utils at the existing
lib/cva.config.ts, which now exports cn (cva beta cx + twMerge) instead
of adding class-variance-authority as a second variant library. The two
ad-hoc cn helpers fold into it. Button lands as the canary primitive,
adapted to cva beta and React 18 forwardRef, with tests covering the
variant, twMerge, asChild, and ref seams. --radius is 0.5rem so the
shadcn radius scale reproduces Tailwind defaults and legacy rounded-*
classes render unchanged.

antd v5 emits unlayered CSS-in-JS that would beat every layered v4
utility, so AntdGlobalProvider now wraps the app in StyleProvider layer
and ConfigProvider cssVar, and globals.css declares
@layer theme, base, antd, components, utilities. antd wins over
preflight but yields to utilities, which is what lets migrated shadcn
pages coexist with legacy antd pages. Preflight stays global with the
three v3 behaviors pinned (default border color, button cursor,
placeholder color).

* fix(ui): restore tremor opacity tints removed by tailwind v4

Tailwind v4 removed the *-opacity-* utilities, but the precompiled
@tremor/react dist still composes them with shade-500 palette classes
(bg-opacity-10 over bg-<color>-500 etc.), so Badge, BadgeDelta, Callout,
light Icon and Button, BarList, and ProgressBar lost their tints and
rendered solid 500-shade fills. Adversarial review caught it; the
original smoke pages only exercised antd Tags.

tremor-v3-compat.css restores exactly the pairs tremor emits: for each
of the 22 safelisted colors, bg-opacity-{10,20,40}, hover/group-hover
bg-opacity-{20,30}, and ring-opacity-{20,40} against the -500 shade,
via color-mix into the utilities layer. Tremor's colorPalette maps both
background and iconRing to 500, so the -500 pairing covers every
composition in the dist; dark: variants are inert until dark mode ships.
The shim dies with @tremor/react at the end of the migration.

The upgrade codemod also missed two hand-rolled modal scrims using
bg-black bg-opacity-{30,50} (solid black under v4); now bg-black/30 and
bg-black/50. Removed the docker/build_admin_ui.sh copy of
enterprise_colors.json into the deleted ui_colors.json; that build-time
rebrand path is retired and its runtime replacement lands with the
theming phase.

* fix(ui): pair ring-opacity-40 with shade 300 in tremor compat shim

Tremor's colorPalette maps ring to shade 300, and the only consumer of
ring-opacity-40 (Icon variant outlined) composes it with that shade,
so the shade-500 rows were dead and outlined icon rings would render
at full opacity. Latent today (no dashboard usage of the outlined
variant); caught by adversarial review. ring-opacity-20 stays at 500
(iconRing), matching Badge and BadgeDelta.
2026-07-02 19:02:27 -07:00
ryan-crabbe-berri
2a9dbc4c0d
chore(ui): remove unused dep, delete dead file, and unblock knip (#31933)
Knip flagged remark-gfm as unused and date-fns as imported-but-undeclared, so drop remark-gfm (which prunes its transitive markdown subtree from the lockfile) and declare date-fns, which keyExpiryUtils.ts imports but only received transitively. Also delete the dead memory/components/index.tsx barrel, since nothing imports it once the page pulls MemoryView from its module directly

Knip itself could not run: its Playwright plugin imports every config referenced by a --config flag in package.json scripts, and migration.serverRootPath.config.ts threw at import time when SERVER_ROOT_PATH was unset. Move that guard into a config-specific globalSetup so importing the config is side-effect-free; the check still fires loudly before any test runs when the prefix is missing
2026-07-01 20:13:58 -07:00
ryan-crabbe-berri
f2f6cacb19
feat(ui): track frontend lint counts in a committed snapshot (#31157)
Some checks are pending
LiteLLM Rust / rustfmt, clippy, test (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
* feat(ui): track frontend lint counts in a committed snapshot

Persist the eslint budget-rule counts (no-explicit-any, complexity,
max-depth) to eslint-metrics.json so the trend is queryable straight
from git history and can later feed a dashboard. A CI drift check
regenerated from the same lint report keeps the snapshot honest, so a
PR that shifts a count has to run npm run lint:metrics and commit it

* fix(ui): harden lint-metrics drift check and eslint failure handling

Make the drift comparison symmetric over the union of committed and
actual keys so a phantom rule left in eslint-metrics.json (for example
after a rule is dropped from eslint-budgets.json) is caught instead of
silently passing. Only swallow eslint's lint-errors exit code in the
generator and rethrow anything else, so a fatal eslint failure surfaces
its real output rather than a confusing ENOENT on the missing report
2026-06-24 11:35:32 -07:00
yucheng-berri
a8a1472428
fix(deps): bump osv-flagged dependencies to clear known CVEs (#31122)
Bumps the 12 packages osv-scanner flags on litellm_internal_staging, taking
the scan from 24 known vulnerabilities to zero. vcrpy goes to 8.2.1 first so
aiohttp can move to 3.14.1 (vcrpy <= 8.1.1 cannot import aiohttp 3.14), then
the two aiohttp ignore entries are dropped from osv-scanner.toml. The
langchain stack moves together since langchain 1.3.9 requires langgraph 1.2.x.
Runtime deps cryptography (48.0.1), starlette (1.3.1), python-multipart
(0.0.32), pydantic-settings (2.14.2) and pypdf (6.13.3) are bumped via relock,
and the dashboard's js-yaml, ws and form-data overrides are bumped too.

Also removes the paths filter on the OSV workflow so it runs on every PR
rather than only when a lockfile changes, which is why it never showed up on
recent code-only PRs
2026-06-23 15:50:50 -07:00
yuneng-jiang
2fad75ffda
build(ui): pin esbuild to 0.28.1 via overrides (#30390)
esbuild reaches the dashboard tree transitively through vite (the vitest
stack), and vite 7.x still requests ^0.27.0, so it never advances past
0.27.x on its own. An overrides entry forces 0.28.1, which the osv-scan
job reports as the fixed version for the dev dependency. Keeping it in
package.json (not just the lockfile) means a lockfile regeneration cannot
silently roll it back.
2026-06-13 11:52:40 -07:00
yuneng-jiang
d96ab467f1
chore(deps): bump vitest, brace-expansion, pypdf and tornado (#30220)
* chore(deps): bump aiohttp to 3.14.1 and vitest to 3.2.6

Lockfile-only bump for aiohttp (3.13.5 -> 3.14.1, within the existing
pyproject constraint) and dashboard devDependency bumps for vitest,
@vitest/coverage-v8, @vitest/ui (3.2.4 -> 3.2.6) plus transitive
brace-expansion (5.0.5 -> 5.0.6). Clears the currently published
advisories flagged by osv.dev against uv.lock and the dashboard
lockfile. Verified: 154 custom_httpx unit tests and all 3943 dashboard
vitest tests pass; live proxy completion and streaming calls succeed on
the bumped venv

* chore(deps): raise aiohttp floor to 3.14.0

The lockfile bump alone only protects environments built from uv.lock.
Raising the pyproject floor extends the same minimum to package
consumers installing litellm from PyPI, and prevents a future lockfile
regeneration from resolving below 3.14.0

* Revert "chore(deps): raise aiohttp floor to 3.14.0"

This reverts commit d6c1c9dc0c.

* revert(deps): roll back aiohttp to 3.13.5

vcrpy is incompatible with aiohttp >= 3.14 (the aiohttp_stubs module
imports a symbol removed in 3.14) and the upstream fix is merged but
unreleased, so every cassette-based test suite fails on 3.14. Hold
aiohttp at 3.13.5 until a vcrpy release ships; the vitest and
brace-expansion bumps stay

* chore(deps): bump pypdf to 6.13.1 and tornado to 6.5.7

Lockfile-only bumps clearing the advisories published for both since
this branch was opened

* chore(deps): add regression guards for the bumped versions

Raise the pypdf floor to 6.12.0 (direct dependency, applies to package
consumers too) and add uv constraint-dependencies for the transitive
pins: tornado >= 6.5.6, and aiohttp held in [3.13.5, 3.14) so a lockfile
regeneration can neither fall back below the current version nor move
onto 3.14 while vcrpy is incompatible. Constraints live in [tool.uv]
and only affect this repo's resolution, not published metadata.
Verified: uv lock -P with each out-of-range version fails to resolve;
in-range resolutions unchanged (pypdf 6.13.1, tornado 6.5.7,
aiohttp 3.13.5)
2026-06-12 17:48:00 -07:00
ryan-crabbe-berri
9e0d92c129
chore(ui): remove dead dashboard files and unused dependencies (#30047)
* chore(ui): remove dead dashboard files and unused dependencies

knip flagged seven orphaned source/config files with no importers and
five declared dependencies that nothing in the tree uses. Removing them
shrinks the dashboard bundle's source surface and keeps the manifest
honest; vite stays installed transitively via vitest, so test tooling is
unaffected.

* fix(ci): restore serverRootPath.config.ts referenced by SERVER_ROOT_PATH workflow

The dead-code sweep removed e2e_tests/serverRootPath.config.ts, but its spec
(tests/login/serverRootPathRedirect.spec.ts) and the test_server_root_path.yml
workflow step still depend on it, so the redirect e2e job failed to load a
config that no longer existed.
2026-06-09 17:54:38 -07:00
ryan-crabbe-berri
6ae8a509f0
test(ui): data-driven App Router migration E2E smoke (default + server-root-path) (#29974)
* test(ui): add a data-driven App Router migration E2E smoke

Add a growing Playwright smoke for migrated pages: for each segment it deep-links
to the path route, asserts the URL and that the dashboard shell rendered, then
clicks off to a legacy page and asserts navigation still works. Driven by
e2e_tests/fixtures/migratedPages.ts, so adding a page is one line.

Runs in two situations against the same proxy: the default mount (npm run
e2e:migration) and a non-root SERVER_ROOT_PATH mount (npm run e2e:migration:root).
globalSetup now logs in at `${SERVER_ROOT_PATH}/ui/login` so the admin storage
state is valid under a prefix. Seeded with api-reference; append the rest as their
migrations merge.

* test(ui): support headed slow-motion + watch pauses in the migration smoke

Honor SLOWMO in the server-root-path config (the default config already did),
and add an env-gated E2E_WATCH_MS pause so a headed run lingers on each state.
Both are no-ops by default, so CI behavior is unchanged.

* test(ui): make the migration smoke a sidebar-click user journey

Rework the smoke from deep-linking to a real navigation journey: start at the
landing page, click the migrated page in the sidebar (expanding submenus for
nested items), assert the path route rendered, reload it (the check a wrong
server_root_path breaks), bounce to a legacy page and back, and — once two pages
are migrated — navigate directly between two migrated pages. Verifies via URL +
shell render, driven by the same fixture list.

* test(ui): address review on the migration smoke

Escape ROOT and segment before interpolating them into RegExp URL matchers so a
future segment containing regex metacharacters can't silently widen the match.
Make the server-root-path config fail fast when SERVER_ROOT_PATH is unset instead
of silently re-running the default mount and passing without exercising the prefix.

* test(ui): drop unused watch helper and fix stale smoke README

* test(ui): run the migration smoke under a server root path in CI

* test(ui): harden + instrument the server-root-path proxy reboot in CI

* test(ui): run the server-root-path migration smoke as its own CI job

Replace the in-place proxy reboot in e2e_ui_testing with a dedicated
e2e_ui_testing_server_root_path job that boots the proxy once with
SERVER_ROOT_PATH=/litellm, matching how every other proxy variant in the
config gets its own job rather than killing and relaunching the live proxy.

The reboot was failing deterministically: after pkill -9 and relaunch the
prefixed proxy never came back up on :4000 (connection refused), so the smoke
never ran. The readiness step that was supposed to surface the cause could
never reach its boot-log tail because CircleCI runs steps under bash -eo
pipefail and the preceding `curl -sv ... | tail` aborted the step with curl's
exit 7. Booting the proxy as the job's own background step lets any boot crash
land in that step's log instead of being swallowed.

The default e2e_ui_testing job is unchanged aside from dropping the reboot,
prefixed-readiness, and prefixed-smoke steps; the migration smoke still runs at
the root mount there via the default Playwright config.
2026-06-09 10:40:01 -07:00
yuneng-jiang
bac2590b39
build(deps): bump pyjwt to 2.13.0 and ws override to 8.20.1 (#29982)
Raise the PyJWT floor in pyproject (>=2.13.0,<3.0) and re-resolve uv.lock so
the proxy installs 2.13.0 instead of 2.12.0. Bump the ws transitive-version
override in the dashboard from 8.19.0 to 8.20.1 and regenerate package-lock;
jsdom and openai both dedupe onto the single 8.20.1 copy.

Both are routine dependency maintenance bumps to keep pinned versions current.
2026-06-08 16:39:21 -07:00
ryan-crabbe-berri
e53bd7cbd1
feat(ui): generate dashboard API types from the proxy OpenAPI spec (#29816)
* feat(ui): generate dashboard API types from the proxy OpenAPI spec

Introduces the shared type foundation for the dashboard without touching any
runtime code. The proxy's FastAPI app is the source of truth; app.openapi()
emits the spec and openapi-typescript turns it into src/lib/http/schema.d.ts.

Adds an npm run gen:api script (a Python spec dump piped into openapi-typescript)
and a Check UI API Types Sync CI job that regenerates the file from the live
spec and fails if it drifts, so the committed types can never silently fall out
of step with the backend. The generated file is pinned to openapi-typescript
7.13.0 and excluded from prettier, eslint, and knip, and marked linguist-generated
so it collapses in diffs.

No openapi-fetch and no call-site changes yet; this only makes the types exist.

* chore(ui): tidy gen-api-types script per review

Write the spec dump inside a with-block and clean up the temp dir in a
finally, so repeated local runs don't leave stray ~MB JSON files behind.
2026-06-05 17:20:01 -07:00
ryan-crabbe-berri
c7f1bcfd0d
build(ui): migrate eslint to flat config and bump eslint-config-next to 16 (#29626)
ESLint 9 defaults to flat config and eslint-config-next was pinned at 15
while Next is on 16, so eslint only ran with ESLINT_USE_FLAT_CONFIG=false
and next lint is gone on Next 16. Replace .eslintrc.json with a native
flat eslint.config.mjs (config-next 16 ships flat configs, so no
FlatCompat shim is needed), bump eslint-config-next to 16.2.6, add
@eslint/js and typescript-eslint as explicit devDeps for the recommended
rule sets, and point the lint script at eslint directly.

This only makes eslint runnable on modern tooling; it does not wire it
into CI. The same rules carry over (next/core-web-vitals, eslint and
typescript-eslint recommended, prettier, unused-imports)
2026-06-03 15:50:20 -07:00
yuneng-jiang
0715ed3359
build(deps): bump next from 16.2.4 to 16.2.6 in /ui/litellm-dashboard (#27665) (#28524)
Bumps [next](https://github.com/vercel/next.js) from 16.2.4 to 16.2.6.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.2.4...v16.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 00:13:56 +00:00
user
1dcfc36393 chore(deps): align dashboard node engine 2026-05-04 13:21:03 -07:00
user
bfdd786962 chore(deps): refresh dependency locks 2026-05-04 11:36:18 -07:00
yuneng-jiang
a306092d47
Merge pull request #25463 from BerriAI/litellm_oss_staging_04_09_2026
Litellm oss staging 04 09 2026
2026-04-13 17:25:53 -07:00
Ryan Crabbe
004964f421
chore: remove deprecated tests/ui_e2e_tests/ suite
The suite was superseded by ui/litellm-dashboard/e2e_tests/ on 2026-04-08
and is no longer referenced by CircleCI, docs, or Makefile targets. Drop
the directory wholesale and remove the orphaned e2e:psql npm script that
pointed at its runner.
2026-04-13 15:40:34 -07:00
user
8d1493ed08
fix(security): bump vulnerable dependencies
pip:
- cryptography 43.0.3 → 46.0.7 (5 CVEs including CVSS 8.2 ECDH key leak)

npm:
- hono 4.1.4/4.12.7 → 4.12.12 (prototype pollution, cookie injection,
  path traversal, middleware bypass, IP matching bypass)
- @hono/node-server 1.19.6 → 1.19.13 (serveStatic middleware bypass)
- vite 7.3.1 → 7.3.2 (file read via WebSocket, path traversal, fs.deny bypass)
- lodash override 4.17.23 → 4.18.1 (code injection via _.template,
  prototype pollution via _.unset/_.omit)

mlflow left at 3.9.0 — 2 of 3 alerts have no upstream fix, and
3.11.1 is blocked by exclude-newer (transitive dep chain).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:35:19 +00:00
Yuneng Jiang
8a0ddd46d5
[Test] UI - Add Playwright E2E tests with local PostgreSQL
Add a self-contained Playwright E2E test suite that runs against a local
PostgreSQL database instead of Neon. Tests cover role-based access for all
5 user roles (proxy admin, admin viewer, internal user, internal viewer,
team admin) and authentication flows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:47:17 -07:00
stuxf
7066c895f6
chore: harden npm supply chain — pin overrides, enforce npm ci, add ignore-scripts (#24838)
* chore: harden npm supply chain — pin overrides, enforce npm ci, add ignore-scripts

Replace open-ended >= version overrides with exact pins matching lockfile
versions across all 6 package.json files. Remove dead overrides for packages
not present in lockfiles. Switch CI and devcontainer from npm install to
npm ci for deterministic lockfile-based installs.

Add .npmrc to all 7 JS project directories with ignore-scripts=true (blocks
postinstall RAT vectors like the axios@1.14.1 supply chain attack) and
min-release-age=3d (refuses packages published <3 days ago, requires npm
>=11.10). Remove Yarn-only resolutions field from docs/my-website.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: bump sharp to 0.33.5 in docs, add docs .npmrc

sharp 0.32.x uses postinstall to download native binaries, which breaks
with ignore-scripts=true. sharp 0.33+ distributes via optionalDependencies
instead, making it compatible with the new .npmrc hardening.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: remove docs .npmrc to fix Vercel deploy

Vercel's build for docs/my-website uses npm install which needs
sharp 0.32.6's postinstall script. Since we don't control Vercel's
build process, remove the .npmrc from docs rather than fight it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: Dockerfile npm ci + nvm checksum verification

- Replace npm install with npm ci in Dockerfile.non_root,
  Dockerfile.custom_ui, and spend-logs/Dockerfile for deterministic
  lockfile-based installs
- Replace curl-pipe-bash nvm install with download-then-verify pattern
  in build_admin_ui.sh, build_ui.sh, and build_ui_custom_path.sh
- Update nvm from v0.38.0 (2021) to v0.40.4 (Jan 2026) with SHA256
  checksum verification before execution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: macOS sha256sum compat + clarify min-release-age scope

- Use shasum -a 256 fallback on macOS where sha256sum is unavailable
- Clarify in .npmrc comments that min-release-age only protects local
  npm install, not npm ci (used in CI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:41:37 -07:00
Ishaan Jaffer
f636c3b3b7 pin axios 2026-03-30 20:20:23 -07:00
yuneng-jiang
3e2845181c bumping next version 2026-03-17 17:38:09 -07:00
Joe Reyna
25ee2fb3f9
fix(security): bump tar to 7.5.11 and tornado to 6.5.5 (#23602)
* fix(security): bump tar to 7.5.11 and tornado to 6.5.5

- tar >=7.5.11: fixes CVE-2026-31802 (HIGH) in node-pkg
- tornado >=6.5.5: fixes CVE-2026-31958 (HIGH) and GHSA-78cv-mqj4-43f7 (MEDIUM) in python-pkg

Addresses vulnerabilities found in ghcr.io/berriai/litellm:main-v1.82.0-stable Trivy scan.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: document tar override is enforced via Dockerfile, not npm

* fix: revert invalid JSON comment in package.json tar override

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 23:08:14 -07:00
Ishaan Jaff
f5e5d17e4a
fix(mcp): fix OpenAPI OAuth flow — transport mapping, error messages, and discovery bypass (#23315)
* fix(mcp): fix OpenAPI OAuth flow — transport mapping, error messages, and discovery bypass

Three bugs fixed to make the end-to-end OAuth flow work for OpenAPI MCP servers:

1. **Transport mapping in getTemporaryPayload**: `TRANSPORT.OPENAPI` is a UI-only concept;
   the backend only accepts `"http"`, `"sse"`, or `"stdio"`. The pre-OAuth temp-session
   call was sending `transport: "openapi"` and getting a 422. Fixed by mapping to `"http"`.

2. **deriveErrorMessage handles FastAPI 422 arrays**: FastAPI validation errors return
   `detail` as an array of `{loc, msg, type}` objects. The shared error extractor was
   returning the array directly, causing `Error: [object Object]`. Fixed to map each
   item to its `.msg` field.

3. **Skip OAuth discovery when authorization_url already provided**: `build_mcp_server_from_table`
   was unconditionally calling `_descovery_metadata(server_url)` for OAuth servers. For
   OpenAPI servers the url is the spec JSON file, not the API base — this caused a timeout
   fetching e.g. the GitHub spec (2 MB). Fixed by skipping discovery when `authorization_url`
   is already set.

Also: collapsible auth section in MCP server form, "Create OAuth App →" link next to
Client ID when a docs URL is available (e.g. GitHub OAuth App creation page), and
`extractErrorMessage` helper in `useMcpOAuthFlow` for cleaner error display.

* refactor(mcp): extract needs_discovery flag and reduceStaticHeaders helper

* feat(mcp): user OAuth connect flow — OAuthConnectModal, MCPCredentialsTab, useUserMcpOAuthFlow

Adds the user-facing MCP OAuth2 PKCE connect flow:

- OAuthConnectModal: modal that launches the PKCE flow for a user to connect to an MCP server
- MCPCredentialsTab: credentials management tab in the MCP apps panel
- useUserMcpOAuthFlow: hook that handles the full PKCE auth code exchange for user-level connections
- MCPAppsPanel: wires up the new credentials tab and connect modal
- ChatPage: further cleanup after responses-API revert
- db.py / mcp_management_endpoints.py / _types.py: backend support for storing user MCP credentials

* fix(mcp): make client_id optional in /authorize — use server's stored client_id when not provided

* address greptile review feedback

* fix(mcp): narrow bare except to RecordNotFoundError in BYOK credential delete

* refactor(mcp): move inline imports to module level in db.py

* docs(claude): add MCP OAuth, transport mapping, and browser storage patterns

* fix(security): remove accessToken from sessionStorage in OAuth flow state

The LiteLLM API key was being serialised into sessionStorage as part of
StoredFlowState. After the OAuth redirect the component re-mounts with the
same accessToken prop, so it never needed to be stored. Read it from props
in resumeOAuthFlow instead.

* fix(ui): remove duplicate extractErrorMessage, sessionStorage-only in admin OAuth hook, call delete API on disconnect

* fix(ui): guard resumeOAuthFlow against wrong hook instance consuming OAuth result

* fix(ui): separate OAuth result keys per flow, sessionStorage-only, surface revoke errors

* fix(ui): remove dead OAuthConnectModal, revert tsconfig jsx mode to preserve

* fix(mcp): guard BYOK overwrite in oauth credential store, raise clear error when client_id absent

* fix: forward OAuth error params in callback, fix BYOK guard exception handling in db.py
2026-03-11 16:16:08 -07:00
Krish Dholakia
e7714f0ce6
Fix CVEs: bump tar/minimatch/pypdf + harden Docker SBOM patching (#23082)
* fix(docker): bump tar/minimatch/pypdf for CVE fixes + harden SBOM patching

- Bump tar 7.5.8→7.5.10, minimatch 10.2.1→10.2.4, pypdf 6.6.2→6.7.3
- Add sed-based SBOM metadata patching with properly indented find/sed
- Add npm package manager cleanup (apk del / apt-get purge) to remove
  stale SBOM entries from image scanners
- Scope || true to only apk del via brace grouping { ... || true; }
- Guard npm root -g with non-empty assertion to prevent silent failures
- Scope minimatch sed regex to ^10.x to avoid matching other major versions

Addresses: CVE-2026-27903, CVE-2026-27904, GHSA-qffp-2rhf-9h96, CVE-2026-27888

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(docker): scope find to /usr/local/lib /usr/lib, drop autoremove

- Replace `find /` with `find /usr/local/lib /usr/lib` to avoid
  traversing /proc, /sys, /dev during SBOM metadata patching
- Remove `apt-get autoremove -y` from Debian-based Dockerfiles to
  prevent nodejs from being removed as an auto-installed dependency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:31:27 -08:00
Ishaan Jaff
ec600aa70a
feat(ui): add Chat UI — ChatGPT-like interface with MCP tools and streaming (#22937)
* feat(ui): add chat message and conversation types

* feat(ui): add useChatHistory hook for localStorage-backed conversations

* feat(ui): add ConversationList sidebar component

* feat(ui): add MCPConnectPicker for attaching MCP servers to chat

* feat(ui): add ModelSelector dropdown for chat

* feat(ui): add ChatInputBar with MCP tool attachment support

* feat(ui): add MCPAppsPanel with list/detail view for MCP servers

* feat(ui): add ChatMessages component; remove auto-scrollIntoView that caused scroll-lock bypass

* feat(ui): add ChatPage — ChatGPT-like UI with scroll lock, MCP tools, streaming

* feat(ui): add /chat route wired to ChatPage

* feat(ui): remove chat from leftnav — chat accessible via navbar button

* feat(ui): add Chat button to top navbar

* feat(ui): add dismissible Chat UI announcement banner to Playground page

* feat(proxy): add Chat UI link to Swagger description

* feat(ui): add react-markdown and syntax-highlighter deps for chat UI

* fix(ui): replace missing BorderOutlined import with inline stop icon div

* fix(ui): apply remark-gfm plugin to ReactMarkdown for GFM support

* fix(ui): remove unused isEvenRow variable in MCPAppsPanel

* fix(ui): add ellipsis when truncating conversation title

* fix(ui): wire search button to chats view; remove non-functional keyboard hint

* fix(ui): use serverRootPath in navbar chat link for sub-path deployments

* fix(ui): remove unused ChatInputBar and ModelSelector files

* fix(ui): correct grid bottom-border condition for odd server count

* fix(chat): move localStorage writes out of setConversations updater (React purity)

* fix(chat): fix stale closure in handleEditAndResend - compute history before async state update

* fix(chat): fix 4 issues in ChatMessages - array redaction, clipboard error, inline detection, remove unused ref
2026-03-05 18:13:04 -08:00
Harshit28j
3e6c10a071 security: fix critical/high CVEs in OS-level libs and NPM transitive 2026-02-24 19:40:09 +05:30
yuneng-jiang
1ecfbad46e adjust blog posts to fetch from github first 2026-02-23 14:45:05 -08:00
Krish Dholakia
a385126a7c Litellm dev compliance UI (#21457)
* feat(ui/): initial commit adding a compliance testing playground

allow proxy admins to test policies and guardrails against datasets

* feat(ui/): make score more friendly

* feat(policy_endpoints.py): new helper function for testing policies

* feat(policy_endpoints.py): expose new endpoint for testing policies and guardrails

enables compliance playground to work as expected

* feat(complianceui.tsx): show returned text
2026-02-18 18:22:43 -08:00