Commit graph

11611 commits

Author SHA1 Message Date
devin-ai-integration[bot]
c1f005bbd4
fix(proxy): keep every repeated form field value in get_form_data
dict(form) collapses duplicate multipart keys to the last one, so a request with
timestamp_granularities[]=segment and timestamp_granularities[]=word reached the
provider as a single-element list. Iterate form.multi_items() instead.

Fixes #35937

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-05 12:13:11 +00:00
mateo-berri
83008a916d Merge remote-tracking branch 'origin/litellm_internal_staging' into fix-responses-batch-usage
# Conflicts:
#	litellm/batches/batch_utils.py
2026-08-05 02:38:02 -07:00
Mateo Wang
64f4bedde1
Merge pull request #34957 from BerriAI/litellm_gpt56_cache_token_pricing
fix(cost): bill gpt-5.6 prompt cache reads at the cache read rate
2026-08-05 02:30:41 -07:00
mateo-berri
a9902fcdb5 fix(streaming): carry Anthropic cache-creation TTL split through fallback usage reassembly 2026-08-05 02:06:52 -07:00
mateo-berri
e8a80b9883 docs(anthropic): state why usage-shape detection requires a cache key, pin Responses-shape rejection 2026-08-05 02:01:53 -07:00
mateo-berri
bd04520d98 Merge branch 'litellm_internal_staging' into litellm_gpt56_cache_token_pricing 2026-08-05 01:51:07 -07:00
mateo-berri
7288247682 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_openai_cache_token_details_loss
# Conflicts:
#	litellm/litellm_core_utils/llm_cost_calc/utils.py
#	litellm/litellm_core_utils/streaming_chunk_builder_utils.py
#	litellm/litellm_core_utils/streaming_handler.py
#	tests/test_litellm/litellm_core_utils/test_streaming_chunk_builder_utils.py
2026-08-05 01:23:54 -07:00
mateo-berri
c11ea9694a Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_self_heal_evicted_httpx_clients 2026-08-04 22:52:06 -07:00
mateo-berri
34f87a1a91 fix(async_client_cleanup): stop cleanup from resurrecting healed clients 2026-08-04 22:43:40 -07:00
tin-berri
4fcaf7d736
feat(spend): derive a default auto-router savings baseline from the hardest tier (#35907)
* feat(spend): derive a default auto-router savings baseline from the hardest tier

The savings driver shipped off by default: unless an operator names
litellm_settings.autorouter_savings_baseline_model, every auto-routed request
records $0.00 and the dashboard card never populates. Nobody discovers a knob
whose feature they have never seen work, so the default has to come from
somewhere the proxy already knows.

The router's own tier ladder is that place. Without a router a deployment runs
one model that can carry the hardest request it will see, so the derived
baseline is the priciest model in the hardest configured tier, REASONING when
present, otherwise the most severe tier the router actually defines. A cheap
tier is a choice the router made, not a ceiling it was bounded by.

An earlier draft of #35521 derived this per request and was deleted for it:
ranking candidates against the request that ran meant reading the request, and
every input shape it could take produced its own review finding. This
derivation is ranked against one fixed reference request instead, a cache-heavy
shape matching real auto-routed traffic, so it never reads the request at all.
Candidates still resolve through the router's deployments, so Azure base_model
and per-deployment pricing overrides rank correctly.

The deciding router records the result on its routing_decision, because one
model name can carry several tag-scoped routers with different tier ladders and
only the deciding instance knows which of them routed the request. The spend
writer's precedence is: configured baseline, then the recorded one, then off.
When the setting is present the router skips deriving entirely rather than
pricing candidates per decision only to be ignored.

Resolution never raises; an unresolvable baseline zeroes the driver instead of
failing a live request. Rows queued by a pod on the previous release carry no
recorded baseline and fall back to the configured setting, exactly as today.

The schema.d.ts regeneration also picks up the reminder_markers field that
UI-19232 (#35874) added without regenerating, so one hunk there is inherited
staleness rather than part of this change.

* fix(spend): cache the derived baseline, price it by deployment, keep it out of the routing preview

Three review findings on the derived baseline, addressed together because they
all sit on the same value's path from derivation to consumer.

Derivation walked and priced the hardest tier's whole pool inside a property
read on every routing decision, unbounded by pool size. The router now caches
the result per instance with a 30 second TTL, None results included, so the
hot path is a clock compare and a deployment edit still lands within a window
no operator watches closer than.

Ranking used each deployment's effective pricing but recorded only the model
name, so the spend writer priced the winning baseline at its public rate: a
hardest tier whose deployment carries a negotiated rate produced materially
wrong savings. The decision now also records savings_baseline_deployment_id
and the writer resolves it through Router.get_deployment_model_info, exactly
as the selected arm already does. The id is ignored whenever the configured
setting overrides the recorded baseline, since the setting names a model, not
a deployment.

/auto_router/test_routing returns the routing decision verbatim to team admins
while only authorizing the classifier and embedding models, so a derived
baseline would resolve another team's model-group alias into its backend
provider/model mapping and hand it to a caller never authorized for it. The
preview's throwaway router is built with derive_savings_baseline=False; its
decisions are never spend-tracked, so nothing is lost, and a source-pinning
test keeps the flag on the endpoint.

Also strips the explanatory comments this PR had added.

* refactor(spend): pin the derived baseline per router instance instead of a TTL

Creating or editing a router already rebuilds its ComplexityRouter instance,
through unregister and re-add on upsert and through the registry reset on a
full model_list load, so a value derived once per instance refreshes on
exactly the flows that can change it. That makes the TTL a solution to a
problem the rebuild lifecycle already solves, and it goes.

Derivation stays deferred to first use rather than running in __init__: during
a config load this router can be constructed before the deployments its tiers
name, and a baseline pinned at that moment would be empty for the process
lifetime.

The one behavior the TTL had that the pin does not: editing a tier deployment
without touching the router itself refreshed the baseline within a window.
That edit path rebuilds only the edited deployment's own strategies, so the
pin holds the old answer until the router is next saved or the config next
loads. A stale deployment id degrades to public-rate pricing rather than
failing, which is where every other unresolvable baseline already lands.
2026-08-04 22:36:45 -07:00
Mateo Wang
86b59fd1bb
Merge pull request #35903 from BerriAI/litellm_precommit_parallel_blocks
perf(pre-commit): run python, dashboard, and gen-api checks concurrently
2026-08-04 22:30:18 -07:00
mateo-berri
d7dbb28b32 fix(pre-commit): scope interrupt cleanup to the job process groups 2026-08-04 21:37:01 -07:00
mateo-berri
a1f497c7c0 fix(pre-commit): kill background jobs and remove their logs on interrupt 2026-08-04 21:28:46 -07:00
mateo-berri
e528e57e53 fix(bootstrap): fail fast when nvm cannot activate the pinned node 2026-08-04 21:18:58 -07:00
mateo-berri
2f36625e7f perf(pre-commit): run python, dashboard, and gen-api checks concurrently 2026-08-04 21:18:00 -07:00
mateo-berri
c418ea59ae fix(bootstrap): switch to the dashboard node floor via nvm or fnm
The dashboard pins engines node >=24.14.1 with engine-strict, so make
bootstrap dies with EBADENGINE on any shell whose default node is older.
Wrap the npm install in scripts/with_dashboard_node.sh: it execs the
command as-is when node already meets the floor, otherwise activates the
.nvmrc version via nvm or fnm, and fails fast with install instructions
when neither manager exists
2026-08-04 21:02:26 -07:00
Abhimanyu Kapur
31a86daa85
feat(auto-router): make reminder marker pair configurable (#35874)
* feat(auto-router): make reminder marker pair configurable

Some harnesses inject internal context using their own marker pair
instead of Claude Code's <system-reminder>/</system-reminder>
convention, and some send it as a separate follow-up user message
rather than inline with the ask. Both cases fall out of the same root
cause: the router's marker-matching is hardcoded, so foreign markers
never strip to empty and the reminder-only turn wins "newest human
ask" selection instead of being skipped.

Add an optional reminder_markers field to ComplexityRouterConfig so
operators can override the (open, close) pair via proxy config, with
the existing skip-when-empty selection logic handling both cases once
the markers match.

* test(auto-router): drop unsolicited comments from the reminder-markers regression test

Per Greptile review on #35874: no comments unless explicitly requested.
2026-08-05 03:08:49 +00:00
Yassin Kortam
1e265dc86c
fix(auth): name enable_jwt_auth when a JWT-shaped key is rejected (#35831)
A three-segment token presented while `general_settings.enable_jwt_auth` is
unset is never treated as JWT-shaped, so it falls through to the virtual-key
path and is rejected for not starting with 'sk-'. That reads as a missing
key in the verification table and sends the operator off to inspect virtual
keys, when the real cause is one missing config line. The rejection now
names `enable_jwt_auth`, appended to the existing text so the Prometheus
invalid-key filter and the admin UI keep matching what they match today.

The hint claims only that the key is JWT-shaped. Segment count cannot tell a
JWT from any other dotted credential, so asserting the key IS a JWT would
swap one confident misdiagnosis for a narrower one.

The enterprise gate on that same path raised a bare `ValueError`, which the
terminal handler turns into a 401. Every sibling enterprise gate answers
403, and a 401 tells the client to retry with a better credential, which no
credential can satisfy while the install is unlicensed. It now raises a 403
`ProxyException` like the SSO gate does.
2026-08-04 20:05:03 -07:00
Mateo Wang
faf3c51469
Merge pull request #35869 from BerriAI/litellm_gate_owns_basedpyright_heap
fix(lint): move the basedpyright heap flag into the type check gate
2026-08-04 19:26:24 -07:00
yuneng-jiang
abcffa1e23
Merge pull request #35875 from BerriAI/litellm_/inspiring-franklin-058a96
test(e2e): skip view-backed global spend probes pending LIT-5211
2026-08-04 19:14:48 -07:00
yuneng-jiang
1d39c5fa7d
Merge pull request #35881 from BerriAI/litellm_/revert-pr-34649-9f1755
revert: "test(e2e): vendor API strategy coverage across endpoints" (#34649)
2026-08-04 19:14:24 -07:00
mateo-berri
5bf9246667 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_gate_owns_basedpyright_heap 2026-08-04 19:04:52 -07:00
devin-ai-integration[bot]
4781b53e72
feat(ui): add Test Routing to the auto router create form (#35859)
* feat(ui): add Test Routing to the auto router create form

Route a test prompt through the complexity-router config on screen before the router
is saved, showing the model it lands on and the same decision trace the Logs page renders.
Adds POST /auto_router/test_routing, which classifies with the live pre-routing hook and
sends nothing to the routed model.

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

* fix(ui): reset the routing test modal on reopen and expose /auto_router on the UI backend

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

* fix(proxy): enforce caller model access and key budget on the routing test's classifier call

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

---------

Co-authored-by: tin <tin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-04 19:00:54 -07:00
Yuneng Jiang
472dd2716f
revert: "test(e2e): vendor API strategy coverage across endpoints (#34649)"
This reverts commit dcb4e5033c.

The suites landed without the proof-of-fix and QA runbook the PR body
itself flagged as outstanding, so the coverage they claim is unverified
against a live proxy
2026-08-04 19:00:34 -07:00
Mateo Wang
727812beef
Merge pull request #35868 from BerriAI/litellm_gate_merge_head_base
fix(lint): pick the merge-aware base so in-progress merges are not blamed for base drift
2026-08-04 18:56:04 -07:00
jwang-gif
bb58f019a0
fix(proxy): fix zguard httpcode when block input (#31948)
* fix(zscaler_ai_guard): return 400 on guardrail block

* fix(zscaler_ai_guard): don't log error on intentional BLOCK

A BLOCK is expected guardrail behavior, not a failure. Before this
fix, raising HTTPException inside the try block caused the generic
except to log it as "Failed to apply guardrail", producing spurious
error-level noise for every normal block event.

Added except HTTPException: raise before the generic handler (matching
the existing pattern in make_zscaler_ai_guard_api_call), and a
regression test that asserts logger.error is not called on a BLOCK.

---------

Co-authored-by: yucheng-berri <yucheng@berri.ai>
2026-08-05 01:46:05 +00:00
ryan-crabbe-berri
0a42114847
fix(claude-code): create-only skill registration with a PUT update route (LIT-4110) (#31752)
* fix(claude-code): make skill registration create-only with a PUT update route

POST /claude-code/plugins upserted by name, so re-registering an existing
name silently overwrote the stored skill's source and metadata. The "Add
New Skill" UI button posts here, so a name collision clobbered a different
skill with no signal to the user.

Make POST create-only: it returns 409 if the name already exists, with a
unique-violation guard mapping the find-then-create race to the same 409.
Add an explicit PUT /claude-code/plugins/{plugin_name} for updates (404 if
the name is missing). PUT is a full replace and documents that omitted
fields reset to their defaults, so UpdatePluginRequest defaults version to
None instead of fabricating the create-time 1.0.0.

The shared mutable fields move to a PluginSpec base; RegisterPluginRequest
keeps its name and its generated schema unchanged, UpdatePluginRequest
carries no name. Regenerated the dashboard types and the lazy openapi
snapshot for the new route.

Resolves LIT-4110

* fix(ui): surface the proxy error detail so the skill 409 conflict is legible

The add-skill form rendered the raw HTTPException envelope on failure
because deriveErrorMessage did not unwrap an object-shaped detail
({"detail": {"error": ...}}), so the new create-only 409 reached the user
as a JSON blob. Unwrap object-shaped detail at the client layer, which
covers every handler that returns detail={"error": ...}, and surface the
resulting message verbatim on the form instead of burying it under a
generic prefix.

* refactor(claude-code): replace blind excepts in plugin mutations with typed handling

Narrow register_plugin's create-conflict guard from a broad 'except Exception'
+ isinstance dance to a direct 'except UniqueViolationError', using an Exception
subclass sentinel (not None) as the prisma-absent fallback so the sentinel can be
caught directly. Drop update_plugin's outer 'except Exception -> 500' wrapper so
HTTPExceptions propagate on their own and unexpected DB errors surface as FastAPI's
default 500 rather than echoing str(e). Keeps the BLE001 strict-rule budget green.

* fix(claude-code): restore structured 500 handling on update_plugin via typed PrismaError catch

Flattening update_plugin to satisfy the no-blind-except rule dropped its error
wrapper entirely, so a data-layer failure (e.g. a dropped DB connection) would
skip the intentional verbose_proxy_logger.exception call and degrade the response
from the endpoint's structured {"error": ...} body to FastAPI's default
{"detail": "Internal Server Error"}, inconsistent with every sibling route.

Wrap update_plugin in 'except PrismaError' instead of the blind 'except Exception'
the other routes use: it logs and returns the structured 500 for real DB failures
while letting genuine code bugs surface rather than masking them as 'Update failed',
and stays off the BLE001 budget. Add a regression test that a PrismaError during
the update maps to a structured 500.

* fix(claude-code): import prisma error types at function level to satisfy LIT009

* refactor(claude-code): typed plugin mutation responses and lint gate fixes

Return RegisterPluginResponse models from POST and PUT instead of ad-hoc
dicts, declare them as response_model so the OpenAPI schema and dashboard
types carry the real response shape, build the stored manifest via
model_dump, and drop update_plugin's unused auth parameter (the route
dependency already enforces auth). Keeps the LIT002/B008/UP045 budgets at
their ratcheted ceilings after merging litellm_internal_staging
2026-08-05 01:44:56 +00:00
Yuneng Jiang
e56a6cadc6
test(e2e): skip view-backed global spend probes pending LIT-5211 2026-08-04 18:40:13 -07:00
mateo-berri
118a9396ba fix(http_handler): guard sync client healing with a double-checked lock 2026-08-04 18:22:55 -07:00
yuneng-jiang
24dbd2b2db
Merge pull request #35863 from BerriAI/litellm_/vigilant-bell-8e5b37
Some checks are pending
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy Legacy Tests / proxy-server-extras (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Proxy Legacy Tests / auth-and-jwt (push) Waiting to run
Unit Tests: Proxy Legacy Tests / key-generation (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-config (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-response-and-misc (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-server (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-token-counter (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-user-auth-and-spend (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-utils (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
test(e2e): self-seed the ui suite's password-login users in global setup
2026-08-04 18:17:10 -07:00
devin-ai-integration[bot]
a01cac2132
fix(s3_v2): sign S3 object URLs with S3SigV4Auth so encoded paths verify (#35726)
Generic SigV4 double-encodes the canonical URI while S3 canonicalizes the wire path with single encoding, so any object key containing a character that percent-encodes (a team alias, key alias or s3_path with a space) was signed over %2520 while the request carried %20; S3 recomputed a different signature and answered 403.

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: yucheng <yucheng@berri.ai>
2026-08-05 01:14:48 +00:00
Mateo Wang
cb27d998f6
Merge pull request #35826 from BerriAI/litellm_fix_toolcall_stream_linear_assembly
perf(streaming): assemble streamed tool-call arguments in linear time
2026-08-04 18:06:23 -07:00
Mateo Wang
4e5cd0b9f5
Merge pull request #35748 from BerriAI/litellm_budget_reset_uow
refactor(repositories): add prisma protocol seams and a spend-reset unit of work
2026-08-04 18:06:06 -07:00
mateo-berri
22a1c30603 fix(lint): move the basedpyright heap flag into the type check gate
The 12 GB NODE_OPTIONS setting lived only in the Makefile export and the
CI env line, so any hand-run gate pipeline forgot it and node OOMed at
the ~4 GB default after 80 seconds, with || true feeding the gate empty
output. The gate now spawns basedpyright itself for both the head and
base passes, appends the heap flag last so it wins node's last-flag-wins
resolution while preserving other caller flags, and fails loudly on
crash exit codes instead of reading them as zero errors.
2026-08-04 17:59:56 -07:00
mateo-berri
96c8c9cee1 fix(lint): pick the merge-aware base so in-progress merges are not blamed for base drift 2026-08-04 17:58:41 -07:00
mateo-berri
555156ab3b fix(http_handler): self-heal handler clients closed after cache eviction
Since #35492 the evicted-client closer really closes litellm-owned
httpx clients once their cache entry is evicted and the grace window
passes. Objects that fetch get_async_httpx_client once in __init__ and
hold the handler forever (40 guardrail classes, pagerduty and email
callbacks, and more) then fail every request with 'RuntimeError: Cannot
send a request, as the client has been closed.'

AsyncHTTPHandler.client and HTTPHandler.client are now properties that
rebuild the inner client from the constructor's stored config when the
handler owns it and finds it closed. Caller-supplied or assigned
clients are never rebuilt, and close paths use the backing field so
closing a handler does not resurrect it.
2026-08-04 17:47:20 -07:00
Yuneng Jiang
fb353423d8
test(e2e): self-seed the ui suite's password-login users in global setup 2026-08-04 17:38:38 -07:00
Mateo Wang
d64e79bf05
Merge pull request #35856 from BerriAI/litellm_revert_evicted_client_closer
revert: "fix(caching): close evicted LLM clients so their connections are reclaimed (#35492)"
2026-08-04 17:35:19 -07:00
mateo-berri
8c7792a5cc Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_toolcall_stream_linear_assembly 2026-08-04 17:16:24 -07:00
mateo-berri
adb9a53ba1 revert: "fix(caching): close evicted LLM clients so their connections are reclaimed (#35492)"
This reverts commit 66bc70365f and the
follow-up 2-line type fix a6d4654261 (#35706), which only retyped a
signature #35492 introduced.

Closing evicted litellm-owned clients breaks every object that fetches
get_async_httpx_client once in __init__ and holds the handler for the
life of the process: 40 guardrail classes plus the pagerduty and email
callbacks. Once the cache entry is evicted (TTL 3600s or the 200-entry
size cap) and the 900s grace passes, the held client is closed and every
subsequent request through it fails with RuntimeError: Cannot send a
request, as the client has been closed. On a production deployment with
a default-on guardrail this surfaced as every request 500ing roughly 75
minutes after boot.

The connection-reclaim goal of #35492 can re-land once handlers survive
their inner client being closed.
2026-08-04 17:05:06 -07:00
yuneng-jiang
794338af67
Merge pull request #35725 from BerriAI/litellm_/spend-reports-implementation-25a080
feat(spend): add caller-scoped key/user/team/organization spend report endpoints
2026-08-04 17:03:31 -07:00
Mateo Wang
e926097fec
Merge pull request #35481 from mubashir1osmani/litellm_azure_gpt56_price_cut
fix(pricing): apply OpenAI's gpt-5.6 terra/luna cut to Azure cost map
2026-08-04 17:02:12 -07:00
Yuneng Jiang
6e0627ed04
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/spend-reports-implementation-25a080
# Conflicts:
#	litellm/proxy/spend_tracking/spend_management_endpoints.py
2026-08-04 16:50:34 -07:00
yucheng-berri
bcce83a17e
fix(guardrails): scan model output on the /openai/v1/responses alias (#35818)
The proxy serves POST /openai/v1/responses alongside /responses and
/v1/responses, but only the latter two were in API_ROUTE_TO_CALL_TYPES.
UnifiedLLMGuardrails.async_post_call_success_hook resolves the call type
from request_route, so on the alias it resolved to None and returned the
response unscanned; model output reached the client with post-call
guardrails never running. The key and team tool allowlist was unenforced
on the same alias for the same reason.

Register the alias family in API_ROUTE_TO_CALL_TYPES and in
LiteLLMRoutes.openai_routes, mirroring how the /openai/v1/realtime
aliases are registered, and log a warning at the two points where the
unified guardrail skips post-call scanning so a future unmapped route is
visible instead of silent.

The Responses block of API_ROUTE_TO_CALL_TYPES moves from list to tuple
literals because the LIT002 budget rejects net-new mutable-collection
construction; the map is read-only, so it is now typed as a Mapping of
Sequence and the budgets ratchet down accordingly.
2026-08-04 16:46:45 -07:00
yuneng-jiang
0e593645d1
Merge pull request #35845 from BerriAI/litellm_/cci-failing-tests-f73740
test: repair three failing suites on litellm_internal_staging
2026-08-04 16:42:58 -07:00
mateo-berri
1dad33749c perf(streaming): group tool-call fragments once instead of rescanning per index 2026-08-04 16:38:37 -07:00
Mateo Wang
1798d9d2a9
Merge pull request #35834 from BerriAI/litellm_fix_cursor_variant_budget_bypass
fix(proxy): enforce per-model budgets against resolved cursor model variants
2026-08-04 16:14:06 -07:00
ryan-crabbe-berri
f4538679c0
fix(proxy): apply key_alias/key_hash filters to all /key/list visibility branches (#35840)
* fix(proxy): apply key_alias/key_hash filters to all /key/list visibility branches

The filters previously lived only in the own-keys OR branch, so a team admin's admin-team branch matched every team key and the Key Alias filter in the Virtual Keys UI appeared broken. Both filters are now global AND conditions alongside team_id/project_id/access_group_id/agent_id, narrowing every visibility branch while leaving unfiltered visibility unchanged.

* chore: drop new explanatory comments flagged by review

* chore: restore schema.d.ts to base enum order
2026-08-04 23:07:57 +00:00
Yuneng Jiang
a28f7be27e
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/cci-failing-tests-f73740 2026-08-04 16:07:22 -07:00
Yuneng Jiang
b6557d2b14
test: repair three failing suites on litellm_internal_staging
The management route-coverage guard fires because /team/metadata_schema landed
in #33353 without a behavior-suite scenario, so this adds one covering the nine
seeded actors plus the unauthenticated 401

The prometheus budget-metric assertions read the log call's first positional
arg, which #35703 turned into an unrendered "%s" format string when it moved
logging to lazy args. They now render the message from the call args, which
also pins the arg order and the exception text that the old substring check
never reached

GitHub Models was fully retired on 2026-07-30, so test_completion_github_api
can no longer pass: the endpoint the github provider targets returns 404 and
models.github.ai answers 410 "github_models_retirement_brownout". The dead live
test is removed rather than skipped
2026-08-04 16:07:02 -07:00