Commit graph

5061 commits

Author SHA1 Message Date
ryan-crabbe-berri
40878a1ed5
fix(proxy): allow /key/update to identify the key by key_alias (#34851)
* fix(proxy): allow /key/update to identify the key by key_alias

* fix(ui): drop machine-dependent union-order churn from generated schema.d.ts
2026-07-29 09:48:08 -07:00
ryan-crabbe-berri
fe1670fc06
fix(ui): size object permissions card grid by container width (#35019)
The card variant used viewport breakpoints (md:grid-cols-2 lg:grid-cols-3)
but every card usage sits in a one-third-width grid cell, so on desktop the
narrow card still rendered three internal columns of roughly 100px each and
the text spilled out of its boxes. Switch to Tailwind container queries so
the internal column count follows the card's own width
2026-07-29 09:47:54 -07:00
mateo-berri
802ed1c74f fix(ui): show public model names in usage breakdowns 2026-07-29 09:46:49 -07:00
yuneng-jiang
f4a68a75ff
feat(ui): mark Cost Optimization as beta in the left nav (#34984) 2026-07-28 12:04:45 -07:00
Tin Chi Lo
06a58efb2e feat(mcp): manual authorization-code delivery for headless MCP clients
The aggregate gateway DCR flow ends in a 303 to the client's loopback
redirect_uri. When the MCP client runs on a browserless machine (EC2,
SSH box, container) the user authorizes from a browser on another
machine, so the 303 dereferences the wrong loopback and the code never
reaches the client.

The connect banner now offers manual delivery for loopback clients: the
finish form posts delivery=manual and /authorize/complete renders the
callback URL on a no-store page instead of redirecting. The user pastes
it into the client (Claude Code v2.1.191+ accepts a pasted callback URL)
or fetches it from the client machine's terminal. Manual codes keep the
same sealing, PKCE binding, and single-use guard, with a 5 minute
expiry instead of 2 to survive the copy-paste hop; the used-code marker
TTL derives from the code's own remaining lifetime so the single-use
property holds for the full 5 minutes. The default redirect path is
unchanged.

Resolves LIT-4863
2026-07-28 11:23:37 -07:00
tin-berri
d91fd084f7
Fix cache leakage card layout to keep date picker on right (#34885)
* Fix cache leakage card layout to keep date picker on right and prevent content overlap

Removes flex-wrap and mt-3 to ensure date picker stays pinned to the right side of the card header regardless of zoom level, preventing it from covering card content below

* Remove overflow-hidden from Card to allow dropdowns and overlays to display fully

Fixes date picker dropdown being clipped when opened in cards like the Cache Leakage Card. By removing overflow-hidden from the Card container, popovers, dropdowns, and other overflow content can now display properly without being clipped by the card boundaries.

* Make cache leakage card descriptions consistent with line clamping

Adds line-clamp-2 to ensure both 'by model' and 'by virtual key' cards maintain consistent height. Removes conditional anthropic-specific text that caused height variations between dimensions.
2026-07-28 10:12:00 -07:00
bhuvan2134686
cabbc7ebfb feat(ui): default the SCX.ai Add Model placeholder to MiniMax-M2.7 2026-07-28 09:07:01 +10:00
tin-berri
9bb75d67af
Merge pull request #34675 from BerriAI/litellm_tool_spend_rollup
fix(proxy): roll up tool spend daily instead of scanning SpendLogs
2026-07-27 15:31:19 -07:00
ryan-crabbe-berri
0171170fc7
fix(ui): validate default team values in Default User Settings (#34815)
* fix(ui): validate default team values in Default User Settings

The Default User Settings form accepted any free-text team id, and the
proxy persisted it without checking the team exists. New users were then
silently never added to the default team because the consume-time 404
from team_member_add was swallowed at debug level.

Backend: PATCH /update/internal_user_settings now rejects unknown and
duplicate team ids with a 400 naming them, before any persistence or
team budget side effects. Team-add failures in _add_user_to_team now log
at ERROR with user and team ids.

UI: DefaultUserSettings rewritten as a shadcn + react-hook-form + zod
form following the org-settings pattern. The team id free-text input is
replaced with a searchable server-backed team picker, so only existing
teams can be selected; zod blocks empty and duplicate rows. The shared
deriveErrorMessage helper now unwraps the HTTPException detail.error
shape so backend validation errors surface readably in toasts.

* fix(ui): restore read-only view with Edit Settings toggle on default user settings

Parity with the pre-migration form: the tab renders a read-only summary
of the saved defaults, Edit Settings opens the RHF form, Cancel discards
pending edits and returns to the summary, and a successful save returns
to the summary showing the new values. Model sentinel labels in the
summary are derived from ModelSelect's now-exported special values
instead of duplicating the strings.

* refactor(ui): rename MODEL_SELECT_SPECIAL_VALUES_ARRAY to MODEL_SENTINEL_OPTIONS

* fix(ui): move Edit Settings into the card header action slot
2026-07-27 15:05:51 -07:00
yuneng-jiang
2b7e01bb7e
Merge pull request #34691 from BerriAI/litellm_/management-endpoint-standards-b1cd57
refactor(management): move the logs end-user filter onto /management/v1
2026-07-27 11:30:51 -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
2f2e1e7519
Merge pull request #34689 from BerriAI/litellm_/model-table-dropdown-truncate-2b2a3f
fix(ui): truncate long team names in the models table team dropdown
2026-07-27 09:54:34 -07:00
yuneng-jiang
19348db0a6
Merge pull request #34679 from BerriAI/litellm_/modal-size-restoration-c06977
fix(ui): restore the Add MCP Server dialog size and header spacing
2026-07-27 09:45:52 -07:00
yuneng-jiang
9354849cc8
Merge pull request #34684 from BerriAI/litellm_/model-table-divider-center-b75b6d
fix(ui): center vertical toolbar dividers
2026-07-27 09:45:29 -07:00
michelligabriele
a1514efa21
fix(vector_stores): S3 Vectors search router bypass + rag query config drop + UI error swallow 2026-07-27 17:07:58 +02:00
bhuvan2134686
8f61073af8 feat(ui): add SCX.ai to the dashboard provider list with logo 2026-07-27 17:05:06 +10:00
Tin Chi Lo
1240c1a76d fix(proxy): close the adversarial-review findings on the tool spend rollup
Three fixes from an adversarial review of this branch, each at the owning
seam rather than the report site.

The flush retried DB_CONNECTION_ERROR_TYPES, which includes ReadTimeout.
A ReadTimeout is the committed-but-unacked case: the review reproduced the
engine abandoning the transaction open on the pooled connection, the retry
stacking its statements into it, and one commit applying both increment
sets while the flush reports success. The retry now covers only
ConnectError, the one failure that proves the statements never reached the
database; post-send failures drop the batch with an error log. The
docstring no longer claims an idempotency the pattern does not have. The
same hazard exists in the untouched daily spend writer and is left for its
own change.

get_tool_calls_from_response read choices[0] only, so a tool invoked in a
later choice of an n>1 response earned spend but never reached the rollup,
the index, or the registry. Choice scope is now an explicit parameter:
accounting passes include_all_choices=True because every choice costs
money; guardrails keep the primary-choice default because they rebuild the
primary assistant message. First multi-choice fixtures in the suite pin
both scopes.

maxBarSize=64 had been added to the shared BarChart unconditionally,
resizing every existing consumer. It is now a prop; only the tool spend
charts opt in. The legend flex-wrap changes stay global because clipping
overflow was a defect, not a preference.
2026-07-26 01:55:47 -07:00
Yuneng Jiang
78e76fff4d
Merge branch 'litellm_internal_staging' into litellm_/management-endpoint-standards-b1cd57 2026-07-25 23:57:32 -07:00
Yuneng Jiang
cb78491482
refactor(management): move the logs end-user filter onto /management/v1
`/customer/aliases` shipped two days ago and has not been in a release, so its
wire contract is still free to change. This lands it on the control-plane
contract before that stops being true, since after a release the path, the param
names and the envelope would all need a permanent legacy adapter

The endpoint becomes `GET /management/v1/spend_logs/end_users`. It is a facet,
the distinct values one column takes over a filtered query on a resource, not an
entity collection; naming it after `customers` implied it listed the end-user
table when it actually reads spend logs, which is a different row set. Serving it
under the parent resource means its filters are the parent's filters, so the
dropdown offers exactly the values the logs table can show without two endpoints
having to keep agreeing on that

Contract changes: `size` becomes `page_size`, `search` becomes `q`, the window
moves from flat `start_date` / `end_date` to `filter[startTime][gte]` / `[lte]`,
and the body becomes `{data, meta, links}`. Unknown query params are now a 400
rather than being silently dropped, because an ignored filter over-returns data.
Errors are RFC 9457 problem documents on this prefix only; every other route
keeps the shape its callers already parse

`links` is what makes the rest deferrable. The dashboard hook follows the
server's `links.next` instead of computing `page + 1`, so moving this to cursor
pagination later changes the links and nothing the client does. That matters
because the inner scan is a sliding window, so offset paging can currently skip
or repeat an end user across pages; the fix is a follow-up, and the hypermedia
means it will not be a breaking one

Cursor mode, `sort`, `include`, ETag / `If-None-Match` and the generic `ListSpec`
framework are all deliberately out of scope here. They are additive or internal,
so none of them needs to beat the release
2026-07-25 23:57:25 -07:00
tin
708a3a19df fix(ui): use a single muted blue ramp for the tool charts
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-26 06:53:26 +00:00
Yuneng Jiang
7b655086e5
Merge branch 'litellm_internal_staging' into litellm_/model-table-dropdown-truncate-2b2a3f 2026-07-25 22:56:41 -07:00
Yuneng Jiang
55ff0e10eb
fix(ui): truncate long team names in the models table team dropdown
The Team dropdown popup is pinned to the trigger width via
w-(--anchor-width) and clips its overflow, while Base UI's ItemText
wrapper is flex-1 shrink-0 with min-width: auto, so it sizes itself to
the full nowrap label and simply overflows the popup. Teams without a
team_alias render their 36-char id, so those options were sliced
mid-character with no ellipsis.

Clears min-width: auto off the text wrapper and truncates the label at
the call site. The underlying gap is in the shared Select primitive,
which any long-labelled select in the dashboard will hit; that is left
for a separate change.
2026-07-25 22:56:37 -07:00
tin
5d77c39bbb fix(ui): color spend-by-tool charts with an ordered ramp
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-26 05:23:57 +00:00
tin
9dbf7c363b fix(ui): keep the spend-by-tool legend from overlapping the charts
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-26 04:58:37 +00:00
Yuneng Jiang
1912ea200c
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/mcp-tabs-styling-dd340c 2026-07-25 21:55:17 -07:00
Yuneng Jiang
984051f74d
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/model-table-divider-center-b75b6d 2026-07-25 21:53:39 -07:00
Tin Chi Lo
c8b0530c30 fix(proxy): roll up tool spend daily instead of scanning SpendLogs
GET /v1/tool/spend served the Cost Optimization card with two raw queries
over LiteLLM_SpendLogToolIndex x LiteLLM_SpendLogs on every dashboard load;
the totals query's driving scan was all of SpendLogs in the window. Both
per-request tables reach 1M+ rows at customer scale, so the card cost
O(traffic) per view and had to be capped at 30 days.

The index writer also mined proxy_server_request.tools, i.e. tools DECLARED
in the request body, attributing each request's full spend to tools that
never ran; and all non-MCP mining ran against payload fields that are '{}'
unless store_prompts_in_spend_logs is enabled, so non-MCP coverage silently
depended on a privacy setting.

Now the spend writer builds a ToolUsageTransaction at request time from
invoked tools only, resolved by the shared get_tool_calls_from_response
normalizer so every response surface (chat completions, Responses API,
Anthropic Messages) is covered; the tool registry's response arm delegates
to the same owner. Transactions queue beside the spend-log queue and the
flush job writes index rows plus a new LiteLLM_DailyToolSpend rollup
(date, tool_name PK) in one transaction, retrying connection errors with
backoff (a failed batch commits nothing, so the retry cannot double-count)
and dropping the batch with an error log on anything else.

The endpoint aggregates in SQL: by_tool is the top TOOL_SPEND_TOP_TOOLS
tools by spend via group_by and daily covers only those tools, so the
response is bounded by days x TOOL_SPEND_TOP_TOOLS regardless of range or
tool-name cardinality; the 30-day clamp is gone. total_spend is dropped
from the response; it was never rendered and its deduplicated semantics
are not computable from a rollup. Spend-log retention deliberately does
not touch the rollup, so tool spend history outlives per-request rows.
2026-07-25 21:52:58 -07:00
tin-berri
f7078e2e08
Merge pull request #34265 from BerriAI/litellm_lit4339_upstream_resource
feat(mcp): send RFC 8707 resource indicators on upstream OAuth legs
2026-07-25 18:53:45 -07:00
Yuneng Jiang
086cbb2d85
fix(ui): center vertical toolbar dividers
The shadcn separator primitive ships `data-vertical:self-stretch` so a bare
vertical divider fills its row, but every call site overrides the height with
`h-5`. A definite cross size makes `align-self: stretch` behave as
`flex-start`, so the dividers rendered flush with the top of their flex line
instead of centered: 0px above and 18px below in the dashboard header, 0px
above and 12px below in the models table toolbar

Routes the three vertical dividers through a ToolbarSeparator that pairs the
fixed height with a same-variant `data-vertical:self-center`. Matching the
variant is what matters; tailwind-merge then drops the conflicting class
outright, whereas a plain `self-center` ties on specificity (the variant is
defined with `:where()`) and loses on utility order. The CLI-managed primitive
is left untouched
2026-07-25 18:41:06 -07:00
Yuneng Jiang
a3f81eddcd
fix(ui): stop the custom-server action colliding with the dialog close button
DialogContent's close button is absolutely positioned 16px from the right
edge at 32px wide, so it overlays the rightmost 24px of the p-6 content
box. The justify-between header pins "+ Custom Server" to that same edge
and, being out of flow, the close button reserves nothing. Give the action
a right margin that clears it; keeping the margin on the button rather
than the row leaves the header rule full-bleed
2026-07-25 18:38:06 -07:00
Yuneng Jiang
2ce5900770
style(ui): match MCP Servers tabs to the dashboard's line tab pattern
The MCP Servers page was the only page-level tab bar using the segmented
(pill) TabsList stretched with w-full, which rendered a full-width grey
bar with a lone pill on the left. Every other page-level tab bar
(budgets, vector stores, access groups, organizations, routing groups,
API reference) uses the underlined line variant, so use that here too.
2026-07-25 17:43:53 -07:00
Yuneng Jiang
ecc491756a
fix(ui): restore the wide Add MCP Server dialog
The shadcn migration carried the antd modal's 1000px width over as an
unprefixed max-w-[1000px], which tailwind-merge keeps alongside the
DialogContent base class sm:max-w-md; the responsive variant wins from
640px up, so the dialog rendered at 448px. Prefix the override so the
merge drops the base clamp
2026-07-25 17:42:47 -07:00
Tin Chi Lo
1fa40bd168 feat(cost-optimization): anchor the savings line at a $0 range start
The "Savings over time" chart plotted a single floating dot for short
ranges: the daily rollup keys spend by YYYY-MM-DD, so a one-day range is
one point by construction. Rather than stand up an hourly SpendLogs data
source, read that same daily rollup and make the cumulative line legible.

- Cumulative | Per day toggle. Cumulative accumulates within the range;
  Per day shows the raw stacked bars.
- Cumulative prepends a synthetic $0 point at the range start
  (withStartAnchor) so the line rises from zero to the running total
  instead of floating. An empty series is left untouched so the chart's
  own "No data" state shows.
- Order the daily series oldest-first (the rollup arrives newest-first)
  so the axis reads left to right and the total accumulates forward.
- Header legend, dots on small series, and a "No data" guard on BarChart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 15:35:51 -07:00
tin-berri
7c1d9fa9ab
Merge pull request #34598 from BerriAI/litellm_cost_savings_tooltip
fix(cost-optimization): swap methodology Collapse for a shadcn HoverCard
2026-07-25 14:24:49 -07:00
devin-ai-integration[bot]
16550edd00
ci: drop docker-based SERVER_ROOT_PATH e2e in favor of a unit test (#34642)
Co-authored-by: ryan <ryan@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-25 18:49:56 +00:00
Tin Chi Lo
3c287576b2 fix(cost-optimization): replace savings methodology Collapse with per-card info popovers
Swap the antd Collapse "How savings are calculated" panel for click-triggered
shadcn Popovers on each SummaryCard, so the explanation sits next to the
metric it describes instead of in one combined block.
2026-07-25 10:49:03 -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
ryan-crabbe-berri
57894b5b5e
revert(ui): return Models + Endpoints tabs to in-memory, keep the ?model drill-in (#34629)
Per-tab path routing for Models made each tab a separate route parsed out
of the pathname, which is fragile under a static export mounted at a
runtime-variable server-root prefix. Revert the tabs to in-memory state:
a single /models-and-endpoints route renders an antd Tabs whose active
tab is React state, and each tab body moves from its own page.tsx into a
non-routed panel component under panels/. Role-gating (which tabs show),
the refresh control and the header are unchanged.

The ?model= / ?team= query drill-in stays: it is query-param based (read
via useSearchParams, written via history.pushState), so it is unaffected
by the server-root prefix and remains shareable. The shared tab-routing
helpers (createTabRoutes / useTabRouting) are untouched; the other four
pages still use them.

Removes the per-tab route dirs, layout.tsx and tabRoutes.ts (+ their
path-routing tests) and replaces the layout's coverage with a page test
for in-memory tab switching, the drill-in overlays and role-gating.
2026-07-25 09:53:13 -07:00
ryan-crabbe-berri
21de59b32e
feat(ui): deep-link virtual key detail view via ?key= query param (#34591)
* feat(ui): deep-link virtual key detail view via ?key= query param

Clicking a key on the Virtual Keys page now sets ?key=<token> with
history.pushState, mirroring the models page's ?model= routing, so the
detail view survives reloads and can be shared as a URL. The key is
resolved from the loaded page when present and fetched via /key/info
otherwise. Extracts the shared navigateWithParams helper out of the
models detailNavigation hook

* test(ui): use a realistic hashed token in the virtual keys fixture
2026-07-25 09:44:52 -07:00
yuneng-jiang
a66bac3adf
Merge pull request #34579 from BerriAI/litellm_/litellm-logs-ui-lag-0ca4b8
fix(logs): scope and bound the End User filter on the logs page
2026-07-25 09:07:23 -07:00
tin-berri
b9b27c2beb
Merge pull request #34582 from BerriAI/litellm_toolspend_30d_bound
fix(proxy): cap /v1/tool/spend window at 30 days and bound every SpendLogs read
2026-07-24 20:05:42 -07:00
Yuneng Jiang
b03004a1eb
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/litellm-logs-ui-lag-0ca4b8 2026-07-24 18:24:14 -07:00
Yuneng Jiang
48e77738ca
refactor(logs): make the end-user filter scan cap a fixed constant
The cap was an env-tunable knob in constants.py. Nothing needs to tune it:
it exists so DISTINCT cannot run over an unbounded row set, and picking a
value is a correctness decision, not deployment configuration. An env var
also makes the bound unverifiable, since the same code can behave very
differently between two proxies.

It is now a plain constant next to its only caller, mirroring how
SPEND_LOGS_PAGINATION_COUNT_CAP sits beside ui_view_spend_logs, and it takes
that constant's value: both reads of LiteLLM_SpendLogs now stop at the same
depth. constants.py goes back to matching staging exactly.

The existing test only asserted the parameter equalled the constant, which
is tautological; raising the constant to a billion kept it green while
removing the bound. A second test pins the value against the logs page's
cap, so an arbitrary change to either one fails.
2026-07-24 18:24:13 -07:00
yuneng-jiang
78348fd1c7
Merge pull request #34571 from BerriAI/litellm_/migrate-simple-table-status-74b530
refactor(ui): migrate routing groups table onto the shared DataTable
2026-07-24 18:06:58 -07:00
Tin Chi Lo
30b7fd16f0 fix(proxy): label the tool spend clamp accurately (start capped at 30 days before end)
The clamp floor is end_date minus 30 days, serving up to 31 calendar
dates inclusive: deliberately the same width as the endpoint's default
window, so the dashboard's own default range never triggers the clamp
note. The docstring, card note, and test name now state that invariant
instead of the misleading 'most recent 30 days'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 17:31:00 -07:00
Yuneng Jiang
2a50b3a087
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/litellm-logs-ui-lag-0ca4b8 2026-07-24 17:28:22 -07:00
Yuneng Jiang
44f571a8aa
fix(logs): keep the End User filter window in step with the logs table
Two issues Greptile raised on the filter window and the capped scan.

A preset date range ends at "now", which the logs query re-reads on every
fetch, so live tail keeps moving the table's end bound. The filter window
was memoized on the date controls alone, so it pinned whichever "now" it
was first built with: an end user that started sending traffic afterwards
showed up in the table but stayed missing from the dropdown until
something remounted it.

formatLogsWindow now takes the preset end bound as an argument, and
getLogsWindowEndBound derives it from the logs query's last fetch, rounded
up to the next minute. Rounding up rather than down means the filter window
never trails the table; bucketing means the query key holds steady between
ticks instead of churning once per render. The panel reads it from
logsQuery.dataUpdatedAt so it advances exactly when the table refreshes,
falling back to the stored end time before the first fetch. Deriving it
from Date.now() during render is what the purity rule forbids.

The capped inner scan ordered by startTime alone, so rows sharing a
timestamp could be cut differently between two requests and successive
OFFSET pages would disagree about the set they were paging through.
request_id now breaks the tie, which the (startTime, request_id) index
already covers.

Drift from rows genuinely arriving inside the window between page fetches
is left alone. Removing it means keyset pagination over the distinct set,
which cannot keep the inner row cap, and that cap is what stops this
query from degrading into a full scan of LiteLLM_SpendLogs.
2026-07-24 17:28:17 -07:00
Tin Chi Lo
26f6ff24d8 fix(proxy): cap tool spend window at 30 days and bound every SpendLogs read
GET /v1/tool/spend aggregated LiteLLM_SpendLogToolIndex joined to
LiteLLM_SpendLogs with a start_time-only predicate the composite
(tool_name, start_time) index cannot serve, and the dedup total query
left the outer SpendLogs scan unwindowed, so every dashboard load
walked both per-request tables end to end.

- clamp the window to the most recent 30 days ending at end_date; the
  response start_date reflects the effective window and the dashboard
  notes the clamp
- index SpendLogToolIndex on start_time (all schema copies + migration)
- window the SpendLogs side of both queries (1s margin: the two writers
  can disagree by ~1ms on the same request)
- expire SpendLogToolIndex rows on the spend-log retention cutoff via a
  parametrized batch-delete engine shared with the SpendLogs cleanup

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 17:24:24 -07:00
yuneng-jiang
3eaf7b1c0a
Merge pull request #34573 from BerriAI/litellm_/key-activity-missing-c5383e
Some checks are pending
CodSpeed Benchmarks / benchmarks (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
fix(ui): keep entity usage tabs aligned with their panels
2026-07-24 16:25:29 -07:00
Yuneng Jiang
12bd6b5e5b
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/litellm-logs-ui-lag-0ca4b8 2026-07-24 16:21:50 -07:00