Virtual Keys, Teams, Request Logs and Tags now hand DataTable a bounded
flex chain and use fillHeight, so the app shell main stays the only page
scroller, the rows scroll under a pinned header and the pagination footer
sits at the bottom of the page. DataTable keeps the sticky header inside
its own scroller in maxBodyHeight mode too, which is what let the header
scroll away with the rows on Keys, Teams and Models. Model Hub, Vector
Stores and the team detail keys tab drop their 75vh boxes and flow with
the page scroller.
Adds an e2e spec that fails on the merge base for every one of those
pages and passes at this tip.
Refs LIT-4738
Claude-Session: https://claude.ai/code/session_018yW93iDaEMhoQUXcYjus7D
All Models now pushes the model group, access group and wildcard filters into
/v2/model/info (new optional access_group and wildcard_only params) so the
server total_count matches the rendered rows. Request Logs defaults to 25,
uses the shared page size options and counts rendered rows in the footer.
Deleted Teams gets the shared DataTable server pagination footer instead of a
hard-coded page size of 100. Per-user usage and the remaining unbounded list
tables get paginationMode so the size selector renders.
Resolves LIT-4738
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
PR #39604 renamed the Internal Users search box placeholder to "Search by email or ID…" but left searchUsers.spec.ts looking for the old "Search by email…" copy, so e2e_ui_testing has been red on litellm_internal_staging since it merged. Point the locator at the shipped placeholder
Derive the GCS batch object path from the deployment's configured model
when present, so a user-crafted JSONL body.model cannot redirect an
authorized deployment's credentials to a different endpoint; the JSONL
value remains the fallback for direct SDK calls with no deployment
config.
Route the fine-tuned endpoint resolution GET through _check_custom_proxy
so custom api_base deployments do not contact Google directly.
Prefer the publisher model path over an endpoints/ segment when parsing
GCS uris, and use the last endpoints/ occurrence, so a bucket prefix
containing endpoints/<digits> cannot shadow the real model path.
Move the custom_endpoint rejection from the batches dispatcher into the
Vertex batch handler so the provider policy lives in the provider
module.
Okta sends profile updates as full PUTs with no groups or groups: [], since SCIM User.groups is readOnly and membership is synced through /Groups. The PUT handler diffed that empty list against the stored teams, removed the user from every team (which also deletes their team keys) and recomputed the role from an empty group list. Treat an empty groups list on PUT as unspecified: keep the stored teams and leave the role alone. Explicit non-empty groups still replace memberships as before
Claude-Session: https://claude.ai/code/session_01CqwUV4Ywnu5aUjXx1UhJrM
Managed batches mangled any Vertex model that is not a plain publisher
model: a fine-tuned Gemini endpoint id was filed under
publishers/google/models/gemini/<id> at upload, then the batch create
parse dropped the id and targeted the nonexistent publisher model
'publishers/google/models/gemini', which Vertex rejects.
Fine-tuned endpoints are now stored under endpoints/<id> in the GCS
object path, and batch create resolves the endpoint to its deployed
tuned model resource (projects/../models/<id>) via GET endpoints/<id>,
which is the only form the v1 batch API accepts for tuned models. The
cost poller's bare-model parse round-trips the endpoint id so unmanaged
batch spend still maps to the configured deployment.
custom_endpoint deployments have no Vertex batch surface, so batch file
uploads and batch creation against them now return a clear 400 instead
of creating a doomed job.
Resolves LIT-6899
Calling the endpoint without going through FastAPI leaves the new search param set to its Query default object, which is not None, so the grouped-session and request_id lookup tests started taking the search branch
Claude-Session: https://claude.ai/code/session_01Q5sbiogJzPcCRmYSbaHxZf
A sent null for tpm_limit, rpm_limit, max_budget and the other budget fields
was dropped by a 'v is not None' filter, so update_budget was never called and
the request returned 200 without changing the budget row. Presence is now read
from model_fields_set (merge-patch semantics, matching /v2/organization) and
the nested litellm_budget_table payload no longer drops nulls either
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The search= param on /key/list, /audit, and /spend/logs/ui, plus key_hash= on /key/list, now compare the pasted value verbatim. Only a copied key ID (the hash) matches, so a raw virtual key never needs to travel in a GET query string
Claude-Session: https://claude.ai/code/session_01Q5sbiogJzPcCRmYSbaHxZf
Keeps staging's response-id keying next to the pass-through failure-path helpers
and types the read-only raw_bytes parameters as Sequence[bytes] so the merged tree
stays inside the lint budgets
The Bedrock branch of get_model_from_request reassigned the already resolved
model binding. Move the route parsing into a helper that returns the URL model
or None so the caller picks between it and the body model without rebinding.
With every kept get_configured_mode test using mode "chat", a Router that
answered "chat" for any non-blank configured mode passed all four of them
(the deleted #39630 pair's audio_speech case was the only test catching it).
Read the mode back as audio_speech on an unmapped model so the configured
value itself is what the test checks. Six hand-applied mutations of
Router.get_configured_mode, including that hardcoded-chat one, are now all
killed by the four surviving tests.
Routes without /projects/<project>/locations/<location>/ built the upstream host from the URL's
still-empty location and 500ed even with default_vertex_config set. Build the base URL once after
the configured project and location are applied, drop the hook that re-derived it afterwards, and
answer 400 with a fix-it message when no location is available at all.
Resolves LIT-6905