Commit graph

46529 commits

Author SHA1 Message Date
mubashir1osmani
5182dfa66b
test(e2e): remove the Presidio guardrail suite (#35129)
Drops tests/e2e/guardrails/test_presidio_guardrail_e2e.py and the
PresidioParamsBody it was the only caller of.

Both cases were red on most stage runs between 07-25 and 07-29: pre_call
failed 6 of 11 runs, post_call 6 of 11, with post_call reporting the raw
address reaching the caller while apply_to_output was set.

The cause was propagation, not masking. GuardrailsClient.register() posts
/guardrails and returns immediately with no readiness wait, unlike
ProxyClient._await_model_servable or GuardrailsClient._await_team, and the
data plane only picks a new guardrail up on its next periodic DB sync. Calls
issued before that sync pass the raw value through. #34833 has since made
both cases poll to the deadline, and on the current build each masks on the
first attempt, so the suite is expected to be green now; it is being removed
because it spends real provider money on every retry and because a pod
replaced mid-poll still reproduces the old failure.

The three guardrail.presidio.* rows stay in coverage_registry/guardrail.yaml
and go uncovered on purpose, so Presidio reads as a tier-P0 gap in Grafana
rather than dropping out of the denominator.
2026-07-29 14:20:39 -07:00
Devin AI
b93030f84e fix(vertex_ai): surface real error/status on vertex batch create instead of IndexError 500 2026-07-29 21:20:25 +00:00
Devin AI
f02e095ddb fix(cost): stop token-pricing the placeholder input on file content calls 2026-07-29 21:11:53 +00:00
Devin AI
4429742e83 fix(proxy): fetch background responses through the router in CheckResponsesCost
Closes #35131
2026-07-29 21:11:44 +00:00
milan
bf723fa9c1 fix(vertex_ai): percent-encode the custom_id in fanned-out vertex batch keys
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 20:50:27 +00:00
Yassin Kortam
440b1bcf65
fix(otel): make OTLP export work against Grafana Cloud (#35060)
Three defects kept LiteLLM's OTel metrics from reaching an OTLP backend.

OTEL_EXPORTER_OTLP_HEADERS is W3C Baggage encoded per the OTLP spec, so its
values are percent-encoded. litellm split the string on "," and "=" and passed
the raw value straight to the exporter, so a vendor that documents
"Authorization=Basic%20<token>" got a literal "%20" on the wire and the backend
rejected the credential. Grafana Cloud documents exactly that shape, which made
its OTLP gateway unreachable. Header parsing now delegates to the OTel SDK's own
W3C Baggage parser in liberal mode, so percent-encoded values decode and values
that were never encoded keep working. It moves from model/utils.py to
plumbing/providers.py because model/ is deliberately free of opentelemetry
imports; providers.parse_headers was already the entry point every caller used.

The OTLP metric exporters then overrode histogram temporality to delta.
Prometheus and Mimir, which back Grafana Cloud's OTLP gateway, reject delta
histograms outright: the gateway answers 400 "invalid temporality and type
combination" and drops the entire batch, so every GenAI metric was silently lost
while traces kept flowing. Backends that prefer delta still accept cumulative, so
the SDK default is the compatible choice in both directions, and the enterprise
billing exporter already relies on it.

Three GenAI instruments also carried names no convention or backend defines, so
nothing downstream could chart them. Time to first token and time per output
token take their semconv names, gen_ai.server.time_to_first_token and
gen_ai.server.time_per_output_token; the gen_ai.client.response.* spellings
litellm used are not conventions at all. Cost has no semconv instrument, so it
takes gen_ai.usage.cost, the name backends already query for spend. All three are
listed verbatim in Grafana Cloud's AI Observability integration reference, so its
prebuilt panels find them. Both engines now read the names from the shared Metric
constants rather than repeating string literals, so v1 and v2 cannot drift.

The renames are breaking for anyone charting the former names; the docs and the
release changelog carry the migration note.
2026-07-29 13:43:33 -07:00
devin-ai-integration[bot]
ea783cc35c
refactor(rust): make litellm-core the callable messages() SDK; drop the ai-gateway handler (#35044)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
2026-07-29 13:41:31 -07:00
ryan-crabbe-berri
bf5334bc59
fix(router): drop duplicate Mapping import that fails ruff F811 (#35122)
router.py imports Mapping from collections.abc and again from typing,
which ruff flags as a redefinition and fails the lint CI job on every
open PR. Keep the collections.abc import
2026-07-29 12:32:55 -07:00
Mateo Wang
8b03315ac6
Merge pull request #35028 from BerriAI/litellm_batch_provider_credentials
fix(proxy): resolve named credentials on provider-only batch and files calls
2026-07-29 11:59:09 -07:00
ryan-crabbe-berri
ba7d8ae17f
feat(ui): deep link organization detail page via ?org= query param (#35117)
* feat(ui): deep link organization detail page via ?org= query param

The organizations page kept the selected organization in React state, so
an org detail page had no URL: it could not be shared, bookmarked, or
opened from another page, and the browser back button dropped you out of
the page instead of closing the detail view

Adds useOrgDetailRouting reading ?org= (same pattern as the api-keys,
models, logs, and teams deep links) and derives the open organization in
OrganizationsPanel from the URL

* fix(ui): reset org edit mode on plain row selection and type test mocks

Greptile P1: with the selected org now URL-derived, browser Back leaves
the detail view without running onClose, so a stale editOrg=true made
the next plain row click open on the Settings tab. Reset the flag on
row selection, matching the teams page

Greptile P2: type the panel test's captured table and detail-view props
from the real components instead of any
2026-07-29 11:56:37 -07:00
ryan-crabbe-berri
bb769702b1
feat(ui): deep link team detail page via ?team= query param (#35112)
The teams page kept the selected team in React state, so a team detail
page had no URL: it could not be shared, bookmarked, or opened from
another page, and the browser back button dropped you out of the page
instead of closing the detail view

Adds useTeamDetailRouting reading ?team= (same pattern as the api-keys,
models, and logs deep links) and derives the open team in Teams.tsx from
the URL. TeamInfo now also derives team-admin rights from the fetched
team data, so team admins arriving via a deep link are not stuck with a
read-only view
2026-07-29 11:35:06 -07:00
Mateo Wang
c56e657097
Merge pull request #34266 from BerriAI/litellm_team-model-allowlist-stale-qqg50q
fix(proxy): stop serving stale team model allowlist after /team/update
2026-07-29 11:00:38 -07:00
yuneng-jiang
74244ddd45
Merge pull request #35041 from BerriAI/litellm_/ui-perf-regression-d7888c
fix(ui): point the navbar and sidebar logos at the dashboard home route
2026-07-29 10:59:53 -07:00
Mateo Wang
2348ccc977
Merge pull request #35107 from BerriAI/litellm_usage_public_model_names
fix(ui): show public model names in usage breakdowns
2026-07-29 10:42:13 -07:00
ryan-crabbe-berri
fdea50daa2
feat(ui): shareable log links via log_id query param on the logs page (#34879)
* feat(ui): shareable log links via log_id query param on the logs page

Clicking a log row now writes ?log_id=<request_id> to the URL, closing the
drawer removes it, and loading the logs page with ?log_id= opens the drawer
for that log. When the log is not in the loaded page, it is fetched by
request_id (the backend already drops the date window for id lookups), so
links keep working for logs of any age. Drawer open state derives from the
URL, mirroring the models page ?model= pattern.

* fix(ui): close the log drawer on browser back after opening via session id

Session opens now write ?session_id= to the URL instead of holding local
state, so back removes both params and the drawer closes (Greptile P1).
Session views become shareable links as a side effect. In-drawer log
switching now replaces the history entry instead of pushing, so back
always closes the drawer in one step rather than replaying every viewed
log.

* fix(proxy): scope /spend/logs/session/ui to the requesting user's visible logs

Non-admin callers now only receive session rows they could already see on
/spend/logs/ui: their own logs plus logs of teams where they hold the
spend-logs permission. Previously any authenticated user could read any
session's log metadata by id, which shareable ?session_id= links made
trivial to trigger. Admin views are unchanged. Also, clicking a log row
now clears a lingering ?session_id= from the URL so the drawer shows the
clicked log instead of a stale session (Greptile P1).
2026-07-29 17:01:09 +00:00
mateo-berri
d17387e2e1 fix(proxy): fall back on empty-string model_group in aggregated usage SQL 2026-07-29 09:59:34 -07:00
ryan-crabbe-berri
9b7a6b9b90
feat(ui): split failed requests into their own series on the cache dashboard (#34862)
* feat(ui): chart failed requests as their own series on the cache dashboard

Spend logs for failed requests are stored with an empty call_type, so the
Cache Hits vs API Requests chart lumped them into an Unknown bar that read
as normal LLM API traffic. The activity query now also returns a per-group
failed_rows count (status = 'failure') and the dashboard charts it as a
third stacked series, so failures are visibly separate from successful
requests and cache hits. The chart data transform moves into a pure
summarizeCacheActivity helper with unit tests; header stats keep their
existing semantics (cache hit ratio still counts failures in the
denominator).

* refactor(ui): move cache dashboard aggregation server-side with a typed response

The /global/activity/cache_hits endpoint previously returned raw per
(key, call_type, model) spend-log aggregates typed as LiteLLM_SpendLogs
(wrong), and the dashboard reduced them in the browser: grouping by
call_type, relabeling empty call_type as Unknown, and computing the stat
card totals. All of that now happens server-side. The SQL groups per
call_type and splits cache hits vs successful vs failed requests, a new
cache_activity module validates rows into Pydantic models and computes
totals plus the key-alias/model filter options, and the endpoint declares
a real response_model so schema.d.ts types it correctly. The dashboard
consumes it through a typed $api react-query hook (filters ride the
query key and are applied in SQL instead of the browser), the hand-rolled
summarizeCacheActivity transform and the adminGlobalCacheActivity fetch
helper are deleted, and the refresh button now actually refetches.

The endpoint is UI-internal (hidden from the public swagger), so the
response reshape is not a public API break.
2026-07-29 09:48:17 -07:00
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
Mateo Wang
e299d2b970
Merge pull request #35074 from BerriAI/litellm_daily_any_cleanup_07_29_2026
chore(typing): clear basedpyright Any errors in proxy management endpoints
2026-07-29 09:42:19 -07:00
ryan-crabbe-berri
25ebe5600a
fix(scim): stop provisioning nested group ids as internal users (#34997)
* fix(scim): stop provisioning nested group ids as internal users

POST/PUT/PATCH /scim/v2/Groups treated every member.value as a user id, so
with the default scim_upsert_user=true an unknown id was auto-created as an
internal user. Entra sends nested groups as members carrying "type": "Group",
which meant every nested group produced a phantom internal user whose id and
email were the group GUID, and those users counted toward licensed seats.

Group members are now classified before they are used: members typed "Group"
are skipped without a database hit, an id that names an existing team is
skipped too (Okta sends untyped ids through filtered paths, so the type alone
is not enough), and only ids that resolve to a user, or that resolve to
nothing at all, keep today's behavior. The user lookup runs before the team
lookup so a user whose id collides with a team id keeps syncing.

The type was previously dropped at parse time on POST/PUT because SCIMMember
had no such field, and on PATCH because the raw member dicts were reduced to
bare ids; both paths now share one resolver and one parser that preserves it.

Member removals no longer upsert: a remove of an id we do not know is an
idempotent no-op rather than a reason to create a user and immediately drop
it, and strict mode (scim_upsert_user=false) no longer rejects it. Removal of
an id that is on the roster but has no user row still cleans up membership.

Responses now state members are of type "User" instead of emitting a null,
and the advertised Group schema documents the members.type sub-attribute.

* fix(scim): harden group member classification after adversarial review

Removals now bypass classification and drop exactly the ids they name,
restoring cleanup of roster entries the old bug left behind. The
team-id fallback only applies to untyped members, so an explicit User
type always provisions even when the id collides with a team. Member
types are normalized before matching; a type other than User or Group
only skips when the id is not an existing user. Non-string type values
are tolerated as absent on every verb instead of failing validation.
Admitted member ids are deduped order-preserving, which also closes a
pre-existing duplicate-row hazard on group creation.

* fix(scim): only treat scim-managed teams as nested groups

A PR reviewer flagged that an untyped SCIM member whose id collides
with an admin-created team was silently skipped, suppressing that
user's provisioning. SCIM group writes (POST, PUT, and every PATCH)
now stamp the team with scim_managed metadata, and the typeless
team-id skip only applies to teams carrying that marker or the
scim_data blob older PUTs already wrote. Admin-created teams stay
unmarked, so a colliding untyped member provisions the user in
permissive mode and returns the standard unknown-user 400 in strict
mode. Teams SCIM touched before this change adopt the marker on their
next group write.
2026-07-29 09:38:17 -07:00
yuneng-jiang
cad32fd9bc
Merge pull request #35049 from BerriAI/litellm_hotfix_35047_mcp_e2e_poll
Some checks are pending
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Helm unit test / unit-test (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
test(e2e): poll MCP tools across multi-worker lag (#35047)
2026-07-29 09:06:21 -07:00
milan
3c979f0b47 test(vertex_ai): cover batch lines without a url staying on the chat path
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 15:23:14 +00:00
milan
627d2755da fix(vertex_ai): fan array embeddings input out into one vertex row per element
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 15:06:58 +00:00
milan
e96614a39f fix(vertex_ai): put embed config inside the request and read live usage
A live Vertex batch run showed the documented "embed_content_config" sibling of "request" is rejected by the API ("unsupported type"), failing the whole job rather than the row; the same fields inside the EmbedContentRequest succeed and honor output_dimensionality. Real output rows also report usage under response.usageMetadata.promptTokenCount, not the documented response.tokenCount, so every row came back with zero tokens.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 14:44:25 +00:00
milan
6cfcb6cd83 fix(vertex_ai): translate /v1/embeddings batch rows to Gemini embedding shape
Vertex batch files sent every jsonl line through the generateContent transform, so embeddings rows went out as {"request": {"contents": [...]}} and Vertex rejected each one with "no such field: 'contents'"; the OpenAI "input" was dropped along the way too. Route lines by their own url: embeddings lines now emit the EmbedContentRequest shape (singular content, embed_content_config sibling, custom_id round-tripping through the top-level key), and matching output rows come back as OpenAI embeddings responses.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 14:08:18 +00:00
mateo-berri
095364fd04
test: cover the model_validate conversion sites flagged by codecov
Add regression tests for the db-fetch paths whose converted construction
lines were uncovered: the auth_checks getters (default end user budget, end
user, team membership, access group, team by alias, org by alias, object
permission, managed vector stores, project), get_all_team_memberships and
list_available_teams in team_endpoints, and the proxy admin user info
helper. Each test feeds a mocked prisma row through the real function and
asserts the validated model's fields, so a bad model_validate conversion on
any of these paths now fails a test instead of only dropping coverage.
2026-07-29 10:04:58 +00:00
mateo-berri
44e091aedb
chore(typing): clear basedpyright Any errors in proxy management endpoints
Convert pydantic table-model construction from Cls(**row.model_dump())
kwargs-unpacking to Cls.model_validate(...) across the management endpoint
hotspot files (team, key, internal user, scim, model management, spend
tracking, auth checks, proxy_server). Unpacking an untyped dict reports one
Any-typed argument per matched model field, so each converted site clears
10-35 diagnostics while running the exact same pydantic validation.
Conversions were limited to models verified to use pydantic's default
__init__; UserAPIKeyAuth and LiteLLM_VerificationTokenView keep their custom
kwargs-rewriting __init__ and are untouched. Two locally-verified helper
params move from Any to object.

Whole-tree basedpyright, measured against the branch point in the same
environment: reportAny 24,431 -> 22,741 (-1,690), reportArgumentType
2,189 -> 2,136 (-53), reportUnknownArgumentType 34,370 -> 34,067 (-303),
reportExplicitAny 7,285 -> 7,283 (-2); total 154,882 -> 152,834 (-2,048)
with no rule increasing anywhere and no per-file increases. No casts, no
suppressions, no behavior changes. Budgets ratcheted: basedpyright -2,048
across 4 rules, ruff ANN401 -2.
2026-07-29 09:16:18 +00:00
mubashir1osmani
82fa66908b
test(e2e): poll MCP tools across multi-worker lag (#35047)
* fix(mcp): resolve call_tool by registry without requiring tool map

Multi-worker reloads put MCP servers in the registry from the DB but do
not re-run tools/list on every process. Gating call_tool on
tool_name_to_mcp_server_name_mapping made cold workers 500 with Tool not
found after another worker had already listed the tool. Treat a registry
match on server id/name/alias as enough; upstream rejects unknown tools

* test(e2e): poll MCP register, tools/list, and tools/call across multi-worker lag

Stage multi-worker gateways only load MCP servers and tool maps on the
process that handled the request. Poll until the server is listed, the
tool appears on tools/list, and tools/call is not a cold-worker 500 so
key-access and Datadog MCP e2e stop racing the LB

* Revert "fix(mcp): resolve call_tool by registry without requiring tool map"

This reverts commit 8b56e51e39.

* test(e2e): tighten MCP multi-worker lag classifier

Only retry tools/call on gateway shapes Tool <name> not found and
server_not_found, not any 500 that mentions tool/server not found, so
upstream failures are not retried until the poll deadline

* test(e2e): drop unit file for MCP lag classifier

The live await_call_tool polls already cover multi-worker lag; a separate
string-match unit module is not worth keeping

(cherry picked from commit c274cf321c)
2026-07-28 22:24:21 -07:00
mubashir1osmani
c274cf321c
test(e2e): poll MCP tools across multi-worker lag (#35047)
* fix(mcp): resolve call_tool by registry without requiring tool map

Multi-worker reloads put MCP servers in the registry from the DB but do
not re-run tools/list on every process. Gating call_tool on
tool_name_to_mcp_server_name_mapping made cold workers 500 with Tool not
found after another worker had already listed the tool. Treat a registry
match on server id/name/alias as enough; upstream rejects unknown tools

* test(e2e): poll MCP register, tools/list, and tools/call across multi-worker lag

Stage multi-worker gateways only load MCP servers and tool maps on the
process that handled the request. Poll until the server is listed, the
tool appears on tools/list, and tools/call is not a cold-worker 500 so
key-access and Datadog MCP e2e stop racing the LB

* Revert "fix(mcp): resolve call_tool by registry without requiring tool map"

This reverts commit 8b56e51e39.

* test(e2e): tighten MCP multi-worker lag classifier

Only retry tools/call on gateway shapes Tool <name> not found and
server_not_found, not any 500 that mentions tool/server not found, so
upstream failures are not retried until the poll deadline

* test(e2e): drop unit file for MCP lag classifier

The live await_call_tool polls already cover multi-worker lag; a separate
string-match unit module is not worth keeping
2026-07-28 22:15:21 -07:00
Napuh
2f7574d7c1
fix(anthropic-adapter): open the first content block with the real upstream type so reasoning-first streams start with thinking (#34433)
* fix(anthropic-adapter): open first content block with the real upstream type

* fix(anthropic): defer blank leading stream deltas
2026-07-28 21:51:59 -07:00
tin-berri
7ac5172686
Merge pull request #33290 from mihidumh/fix/latency-routing-timedelta
fix(router_strategy): serialize latency for non-chat responses in lowest-latency routing
2026-07-28 21:50:50 -07:00
mateo-berri
6e8655762c test(router): directly cover team-ownership credential filter helpers 2026-07-28 21:12:57 -07:00
mateo-berri
47a9fabb5a fix(proxy): honor key-level model allowlist in provider-only credential resolution 2026-07-28 21:11:50 -07:00
mgeorgaklis
987a8fcf48 fix(gemini): do not send duplicate thoughtSignature copies to Gemini
Gemini returns each thoughtSignature on exactly one part. LiteLLM
stores a function-call signature both message-level (thought_signatures)
and on the tool call itself, then re-attached it to BOTH the text part
and the function-call part when serializing history. gemini-3 and newer
models bill every replayed copy as the previous turn's full reasoning
token count, so long agentic sessions doubled their context growth and
hit the 1,048,576-token limit

Only attach a message-level signature to the text part when the same
signature is not already carried by a tool-call part:

- compare signature values instead of boolean presence so a distinct
  text-part signature is never dropped
- ignore the gemini-3 dummy-signature fallback during detection so
  replaying gemini-2.5 history to a newer model keeps the real text
  signature
- count signatures carried by server-side tool invocations so they are
  not re-attached to the text part

gemini-2.5 responses (signature on the text part, function call
unsigned) are unaffected: the text signature is preserved as before
2026-07-29 04:08:19 +00:00
tin-berri
9b48bf6084
Merge pull request #34151 from BerriAI/litellm_lit4663_autorouter_prefix
fix(proxy): reject model writes that corrupt an auto-router pseudo-model
2026-07-28 21:01:42 -07:00
mateo-berri
6d607ca3c2 fix(router): never resolve another team's deployment credentials for shared model names 2026-07-28 20:47:40 -07:00
Tin Chi Lo
1e04aee089 fix(proxy): reject model writes that corrupt an auto-router pseudo-model
An auto-router deployment's litellm_params.model (auto_router/...) is the
discriminator the router loads it by, but the model management endpoints
accepted any client-supplied value verbatim; a doubled or stripped prefix
made router init fail on the next load and ignore_invalid_deployments
silently dropped the deployment. Validate writes that supply
litellm_params.model at all three endpoints against the merged params and
reject incoherent values with an actionable 400. Classification is
extracted to router_utils/auto_router_model_naming.py so the Router
predicates and the validation share one source
2026-07-28 20:25:07 -07:00
tin-berri
1a6642ee2e
Merge pull request #34861 from BerriAI/litellm_lit4872_surface_reload_drop
fix(proxy): report when a model write does not survive the post-write reload
2026-07-28 20:18:02 -07:00
Mateo Wang
2bb297efa0
Merge pull request #34993 from BerriAI/claude/auto-til-blocked-cwalrj
fix(proxy): skip team model aliases that point at deleted deployments
2026-07-28 20:09:20 -07:00
Mateo Wang
c542e74b68
Merge pull request #34222 from BerriAI/litellm_jwt_v1_messages_team_route_1784693761
fix(jwt_auth): allow /v1/messages for JWT teams by default
2026-07-28 19:59:26 -07:00
mateo-berri
b592a37b8d test(proxy): cover stale-alias warning dedup and key-cache eviction 2026-07-28 19:39:30 -07:00
mateo-berri
17ce2c4e92 fix(proxy): resolve named credentials on provider-only batch and files calls 2026-07-28 18:57:15 -07:00
Tin Chi Lo
9f4e3c6009 fix(proxy): report when a model write does not survive the post-write reload
Every model-write endpoint returned 200 off the DB write alone; a model the
reload dropped (ignore_invalid_deployments, or a wholesale reload failure)
stayed invisible on every channel at once, which is how the registry-leak
defect went undiagnosed for three weeks. ProxyConfig.add_deployment and
clear_cache now return whether the reload pass completed, and each write
endpoint verifies the rows it wrote are live in this pod's router afterwards,
distinguishing a deliberately environment-inactive model via the same
predicate the Router's own gate uses. The access-group writers return the
mutated id set instead of discarding it
2026-07-28 18:52:06 -07:00
Mateo Wang
711be72512
Merge pull request #34816 from BerriAI/litellm_model_prices_json_schema
ci: publish a generated JSON schema for model_prices_and_context_window.json
2026-07-28 18:03:59 -07:00
yuneng-jiang
2cd62cfb83
Merge pull request #35020 from BerriAI/litellm_hotfix_e2e_model_servable_timeout
test(e2e): bound the post-/model/new servable wait at 40s
2026-07-28 17:58:14 -07:00
mubashir1osmani
87be33f935
fix(e2e): reject first listing that returns after the 40s deadline
A poll may start with remaining budget and still return after started+timeout
if the transport overruns its clamp. Recheck the first-listing deadline after
the response so a late listing does not open the continuous DB-sync phase

(cherry picked from commit 7ff2bcbf14)
2026-07-28 17:47:19 -07:00
mubashir1osmani
38d03fd341
fix(e2e): never skip the final deadline-clamped model-servable poll
When less than one full poll interval remained in the first-listing budget,
the pre-sleep check returned NotServable without another /v1/models call.
Sleep only min(interval, time left) so a model that becomes listable in the
last seconds of the timeout still gets a clamped final poll

(cherry picked from commit 8439195922)
2026-07-28 17:47:19 -07:00
mubashir1osmani
5953a66eab
test(e2e): drop proxy_client model-servable unit tests
Keep the create_model DB-sync wait in the harness; the pure-function unit
file is not needed for this PR

(cherry picked from commit 89204651d1)
2026-07-28 17:47:19 -07:00