Commit graph

4874 commits

Author SHA1 Message Date
Yuneng Jiang
b40a469836
Merge remote-tracking branch 'origin/litellm_internal_staging' into HEAD
# Conflicts:
#	ui/litellm-dashboard/src/components/templates/key_edit_view.tsx
#	ui/litellm-dashboard/src/utils/capabilities.ts
2026-08-10 13:43:09 -07:00
yuneng-jiang
3e680a4ffc
Merge pull request #36333 from BerriAI/litellm_/elated-bhaskara-739752
fix(ui): hide admin-only Logs tabs from roles that cannot call their endpoints
2026-08-10 13:39:51 -07:00
Yassin Kortam
ade805ef0c
feat(rate limiting): configurable estimated output tokens per key, team and model (#36143) 2026-08-10 12:51:14 -07:00
yucheng-berri
e014b341c8
feat(ptu): gate PTU flat-cost attribution behind an opt-in env var (#36138)
LITELLM_ENABLE_PTU_COST_ATTRIBUTION, read through get_secret_bool and defaulting to
false, makes the whole PTU flat-cost feature inert unless an operator opts in. The
daily rollup cron is not registered at all, so no sentinel row is ever written;
/model/new and /model/{id}/update reject a request that carries any PTU model_info
field with a 400 naming the fields and the env var rather than dropping them; the
daily activity read path reports zero flat cost; and the model add and edit forms
hide the four PTU inputs.

The read gate lives where flat cost enters SpendMetrics rather than in the aggregated
SQL select. /team/daily/activity, the endpoint the Usage page reads, is served by the
paginated find_many path and never runs that query, so forcing the select to a
constant zero would have left the reporting surface that matters still showing flat
cost.

Sentinel row filtering is deliberately not gated. An operator can enable the flag,
accrue rows under the __ptu_flat_cost__ api_key, then disable it, and those rows stay
in LiteLLM_DailyTeamSpend; gating the filter too would surface the sentinel as a bogus
api_key and mint a provider bucket for its empty provider. Response fields keep their
shape and report 0.0, so typed clients are unaffected, and the migration and the
ModelInfo field declarations are untouched.

The write gate reads the incoming request rather than the merged deployment, so a
model configured during an earlier opt-in stays editable, and the edit form drops the
PTU keys from the payload instead of sending nulls that would clear stored config.

The dashboard reads the flag from a read-only enable_ptu_cost_attribution key on
/get/ui_settings, computed from the environment on every read. It is deliberately not
an allowlisted persisted setting, and PATCH /update/ui_settings rejects it with a 400,
so an admin cannot flip an env-gated feature from the UI.

Two review findings on the gate itself. The PTU clear loop now runs only when the
feature is enabled: the write gate rejects a value but lets an explicit null through,
and a client round-tripping a model_info blob sends the PTU keys as nulls, so a
disabled proxy would have quietly erased a billing configuration set up during an
earlier opt-in. Disabling pauses PTU rather than discarding its setup. And the
dashboard flag is re-read every thirty seconds instead of the hour the other UI settings
use, since those are persisted records while this one tracks the proxy process; a
restart that flips the variable would otherwise leave the model form offering inputs
the backend now rejects. The flag is polled rather than only marked stale, since a form
that stays mounted and focused never refetches on its own.

The read gate checks the row before the flag. It runs once per metric accumulation and a
record fans out across roughly a dozen breakdowns, while the flag reads through the secret
manager uncached, so consulting it for every accumulation put thousands of lookups on a
shared endpoint that made none before. Only a row actually carrying flat cost reaches it.
2026-08-10 12:23:20 -07:00
yucheng-berri
ed242098ba
feat(ptu): PTU inputs on the model form and flat cost on the Usage page (#35393)
Add PTU count, cost per PTU per hour, and effective-from/to date-time pickers to
the model add and edit forms; the create submit and the edit save map the picker
values to model_info as ISO strings

On the Team Usage Cost tab the money tile becomes Total Cost once a team has
accrued flat cost, and expands to a Request Cost and Flat Cost breakdown, so the
summary row stays at five tiles and the cards keep their width. Each of the three
carries a tooltip, including that flat cost is reported rather than charged
against budgets. The Daily Spend chart stacks Flat cost on Request cost, with a
tooltip that splits the two and shows the total

A team that has accrued no flat cost renders exactly as it did before, and other
entity views are unchanged. CSV export gains Flat Cost and Total Cost columns
when a team accrued non-zero flat cost; the existing Spend header is left alone
so downstream parsers keep working

Both forms validate the PTU pair through one shared module. The count rule rejects
a fractional, zero or negative value, and a rate rule rejects a negative one, each
mirroring a contract the backend enforces. Keeping the rate rule shared rather than
on a single form is deliberate: the edit form previously validated only the count,
so a negative rate typed past the input's min reached the backend and failed the
save with a 400 the operator had no way to anticipate

Both forms require PTU Effective From once PTU Count is set, matching the backend, which
rejects PTU config without a start because flat cost accrues from that instant and an
inferred one would bill days a deployment did not exist. The rule lives beside the count
and rate rules in the shared module, so the add and edit paths cannot drift.
2026-08-10 11:05:06 -07:00
yucheng-berri
457be8f00a
feat(ptu): surface PTU flat cost on the daily activity read path (#35391)
Aggregate the ptu_flat_cost written by the rollup into SpendMetrics.flat_cost and
DailySpendMetadata.total_flat_cost, so /team/daily/activity returns flat cost
alongside per-request spend. The aggregated SQL path selects ptu_flat_cost only
for LiteLLM_DailyTeamSpend and a constant zero for the other daily tables, keeping
the response shape uniform.

Rows written under the PTU sentinel api_key add their flat cost to every parent
bucket (per-model, per-day, per-team totals) but never appear as an api_key row in
any breakdown, and are excluded from the per-request provider breakdown; the
sentinel string is not a real key alias. Both flat_cost and total_flat_cost default
to zero, so a read of any entity without PTU config is unchanged.

The sentinel row now keys on the deployment id, so the per-model breakdown keys it on
model_group instead. That breakdown key is rendered directly as a label by the Usage page
and the daily_with_models export, and a deployment id there would read as a UUID. Two
deployments sharing a public name merge under it, which is the collapse the write path
used to do by summing them into one row. Request rows are untouched and still key on
model, since their model_group is a routing concept rather than a display name.
2026-08-10 10:55:55 -07:00
yucheng-berri
e5386c10a7
feat(ptu): configure provisioned-throughput flat cost on a model deployment (#35341)
Add ptu_count, cost_per_ptu_per_hour, ptu_effective_from and ptu_effective_to to
ModelInfo so a model deployment can carry the inputs for provisioned-throughput
flat-cost attribution. ModelInfo validates per-field bounds (positive count,
non-negative rate, effective_to after effective_from); model/new and
model/{id}/update enforce the cross-field invariant (count and rate set together,
team_id required) on the effective model_info so partial updates validate the
merged result, and v1/model/info returns the fields.

LiteLLM_DailyTeamSpend gains ptu_flat_cost and ptu_source_model_id columns plus a
sentinel api_key constant; the daily rollup that writes them lands in a follow-up
PR. Adding the optional model_info fields is backward compatible; models without
them are unaffected.

ptu_effective_from is required alongside the count and rate rather than optional. Flat
cost accrues from that instant, so an absent start has to be inferred, and inferring it
let a deployment configured today be billed for days it did not exist. Both PTU validators
also run over the merged view before any write on the update path, beside the premium check the create path
already runs there: the team ACL update below autocommits, so a validator raising further
down left the team mutated and the deployment row never written.

The update path validates the model_info a patch would store rather than the patch
alone. An invariant holds over the deployment as it will exist, not over whichever
subset of fields a caller sent, and validating the patch rejected raising the rate on
an already configured model because that patch carries no start of its own.
2026-08-10 09:51:16 -07:00
Yuneng Jiang
d554450f62
test(ui): drop test commentary and assert the normalized org-admin denial 2026-08-08 21:20:32 -07:00
Yuneng Jiang
e3d3177ff1
style(ui): drop narration comments from the usage gating tests
Both restated what the test name and the surrounding setup already say, so
they were maintenance cost without explanatory value. The reasoning they
carried lives in the commit that added the gates.
2026-08-08 21:12:27 -07:00
Yuneng Jiang
2502ee4a2a
fix(ui): gate policy and prompt lookups on an admin capability
/policies/list and /prompts/list are default-deny for internal_user, but the
Virtual Keys create/edit flow, the Teams forms and the Playground called them
on mount, so every internal user landing on the dashboard fired two requests
that 401. Add viewPolicies and viewPrompts to the capability map and use them
to gate the nav entry, the form field and the fetch together, following the
pattern from the Tool Policies migration. Non-admins now see no policy or
prompt selector at all rather than an empty dropdown.
2026-08-08 20:34:56 -07:00
Yuneng Jiang
6a540a1bf8
fix(ui): gate organization and agent usage views behind capabilities
The Usage page admits internal users because their own usage view works,
but the entity breakdown selector inside it also offered Organization
Usage, so picking it fired /organization/daily/activity and collected a
401. Neither that route nor /agent/daily/activity appears in any non-admin
route list, so both are default-deny. The team breakdown leaked the second
one too: it fetches agent activity unconditionally to fill its Top Agents
card, which 401s for the same roles.

Adds viewOrganizationUsage and viewAgentUsage to the existing capability
map and points the selector option, the page section, and the fetch's
enabled flag at the same capability, so a role that cannot call the
endpoint never sees the breakdown and never issues the request. The team
and tag breakdowns, which internal users can read, are untouched, and the
default Usage view was already one of those.
2026-08-08 20:17:12 -07:00
Yuneng Jiang
30c4898de9
fix(ui): hide admin-only Logs tabs from roles that cannot call their endpoints
The Logs nav entry is open to internal users so they can read their own
request logs, but the page rendered all four tabs unconditionally. Audit
Logs calls GET /audit and Deleted Teams calls GET /v2/team/list?status=deleted,
neither of which an internal user is permitted to call, so the page fired
requests that came back 401.

Gate both tabs on new viewAuditLogs / viewDeletedTeams capabilities, using
the same CAPABILITY_ROLES map and useCan hook introduced for Tool Policies.
Hiding a tab drops its panel from the tree entirely, so the request is never
issued rather than issued and rejected.

Selecting a tab also mapped index 0 to "request logs" and every other index
to "audit logs", which activated the audit panel whenever a user opened
Deleted Keys or Deleted Teams. Derive the active tab from the visible tab
list instead, so the mapping survives tabs being filtered out.
2026-08-08 20:16:22 -07:00
yuneng-jiang
97a59c8c90
Merge pull request #36293 from BerriAI/litellm_fix_circleci_88641_outdated_tests
test: repair stale CircleCI contracts
2026-08-08 13:08:22 -07:00
tin-berri
e35ee4e5fa
feat(router): independent, default-on deployment affinity for the auto-router (#36146) 2026-08-08 13:02:29 -07:00
Yuneng Jiang
1a40a67394
fix: stabilize generated user role ordering 2026-08-08 12:54:23 -07:00
mubashir1osmani
3725233736 Merge remote-tracking branch 'berri/litellm_internal_staging' into litellm_playground_shadcn
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
# Conflicts:
#	ui/litellm-dashboard/src/components/llm_calls/fetch_models.tsx
2026-08-08 12:33:13 -07:00
devin-ai-integration[bot]
cfd64d45a8
fix(ui): show team BYOK models in team fallback settings (#36241)
* fix(ui): show team BYOK models in team fallback settings

Team router settings loaded fallback options from /model_group/info, which resolves models without a team, so a team's own BYOK deployments were never selectable in its own fallback config. Load the team-scoped listing when a team id is present.

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

* fix(ui): ignore stale team model responses in router settings

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

* refactor(ui): use react-query for fallback model listing in router settings accordion

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ryan-crabbe-berri <ryan@berri.ai>
2026-08-08 19:28:57 +00:00
mubashir1osmani
f2e3b6a568 fix(ui): drop null guardrail names from MultiSelect options 2026-08-08 12:25:41 -07:00
Yuneng Jiang
0d7f7c689a
test: repair stale CircleCI contracts 2026-08-08 12:19:29 -07:00
mubashir1osmani
757d5a4dcd fix(ui): apply coy theme after code props on ReasoningContent 2026-08-08 12:19:17 -07:00
mubashir1osmani
4aff515a8e fix(ui): cast syntax highlighter theme through unknown 2026-08-08 12:15:09 -07:00
mubashir1osmani
38e1fe8ffd fix(ui): extract chat handlers and type MCP tool pool 2026-08-08 12:11:33 -07:00
mubashir1osmani
01d55b9d0f fix(ui): guard null voice selection from shadcn Select 2026-08-08 12:07:36 -07:00
mubashir1osmani
d78a016bc5 fix(ui): green playground shadcn CI after staging merge
Normalize MCP description nullability for MultiSelect, preserve model
selection via functional setState, and update endpoint/vector-store
selector tests for the shadcn combobox API
2026-08-08 12:01:44 -07:00
mubashir1osmani
0302283eba chore: merge litellm_internal_staging into playground shadcn stack 2026-08-08 11:56:47 -07:00
mateo
f668c10609 chore(ui): regenerate dashboard api types for ModelInfo pricing fields
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-08 03:25:09 +00:00
mateo
96a8b7f488 chore(ui): regenerate dashboard api types for tier_turns
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-08 02:09:53 +00:00
ryan-crabbe-berri
2a9aac7004
fix(ui): let access groups be a team's only model source, with hover provenance (#36234)
* feat(proxy): return per-group model provenance on /team/info

/team/info now carries access_group_details, one entry per resolved access
group with its id, name, and model list, so the UI can attribute each
inherited model to the group granting it. The batch resolver returns the
access group rows keyed by id instead of a stringly dict of lists, and the
team member budget helper returns a copy instead of mutating its parameter.
Type discipline and basedpyright budgets ratchet down accordingly.

* feat(ui): allow group-only teams and show model provenance on hover

Team create and edit no longer require a model selection: an empty
selection is saved as the no-default-models sentinel, never as a bare
empty list, since an empty team model list means unrestricted access.
The team info Models card now renders every badge with a hover tooltip
naming how the team got that model: directly, via named access groups,
or both, and group-granted badges stay visible when the direct list is
empty or a sentinel.

* refactor(proxy): dedupe access group ids and return copies instead of mutating

Duplicate access_group_ids no longer amplify the /team/info response: ids
collapse order-preserving before provenance is built, pinned by a regression
test. The resolver returns a model_copy rather than mutating its parameter,
and the team create call sends a new object instead of reassigning
formValues.models. Budgets ratchet down further with the mutation removal.
2026-08-07 17:45:50 -07:00
ryan-crabbe-berri
8db2fbaad0
feat(ui): show user email or alias in usage data export (#36232)
* feat(ui): resolve user email/alias in usage export instead of raw user id

* test(ui): cover email/alias resolution in usage export data builders

* chore(ui): drop explanatory comment per repo comment policy
2026-08-07 22:53:59 +00:00
mateo
2f70f4edba build(deps): bump nanoid to 3.3.17 in the dashboard lockfile
GHSA-2v37-7h3g-55p8 (CVE-2026-67213) rates 8.2 against nanoid 3.3.16 and reds osv-scan on every PR into staging. Custom generators can loop indefinitely when size is zero, so a caller that passes through a zero size hangs the process.

nanoid is transitive through the dashboard's toolchain and 3.3.17 is a patch release that published 08-03, so it already clears the .npmrc min-release-age=3 guard. The lock diff is the version, resolved url, and integrity hash for that one package.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-07 21:30:09 +00:00
mateo
493eb9054e chore(ui): regenerate schema.d.ts for the /key/info docstring update
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-07 19:13:12 +00:00
ryan-crabbe-berri
527dc0a8bb
feat(proxy): add apply_user_budget_to_team_keys opt-in (#36102)
* feat(proxy): add apply_user_budget_to_team_keys opt-in

PR #32005 made a user's personal max_budget apply to their team-scoped keys
too, and PR #35271 reverted the whole thing (behavior plus the
skip_user_budget_on_team_key opt-out) because that flipped the default for
everyone. This brings the behavior back the other way round: default is
unchanged, and general_settings.apply_user_budget_to_team_keys opts a
deployment into charging the key owner's personal budget on team keys.

The flag reaches all three personal-budget gates so an opted-in deployment
enforces consistently: the read-time check in common_checks, the optimistic
reservation counter in _get_budget_counters, and the _PROXY_MaxBudgetLimiter
pre-call hook. It is also in the /config/list allowed args and, unlike the
reverted flag, in the _update_general_settings propagation allowlist, so the
Admin UI General Settings toggle actually takes effect at runtime; an explicit
YAML value still wins over the DB value on reload.

get_config_list's allowed_args moves to a module-level frozen mapping of
field name to type string, dropping 18 LIT002 violations and rebuilding one
less dict per request.

* style(proxy): drop explanatory comments from the budget flag paths
2026-08-07 15:40:13 +00:00
LHMQ878
55b52970ea fix(proxy): preserve OpenAI WS query params and provider auth
Forward realtime model query string, keep OPENAI_API_KEY (forward_headers=False),
satisfy ruff strict gates, sync dashboard OpenAPI types, and cover the behavior in tests.
2026-08-07 11:09:27 +08:00
yuneng-jiang
4e5495e1bd
Merge pull request #36147 from BerriAI/litellm_bump_js_yaml_4_3_1
build(deps): bump h2 to 4.4.1 and js-yaml to 4.3.1
2026-08-06 19:10:07 -07:00
ryan-crabbe-berri
429a5dc430
fix(ui): allow clearing a key's budget reset from the Edit Key form (#36140) 2026-08-06 18:46:28 -07:00
bhuvan2134686
1e24f93d39 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_scx_ai_provider 2026-08-07 11:26:05 +10:00
bhuvan2134686
8aa9d3dfe5 feat(models): swap SCX.ai catalog to GLM-5.2 and Qwen3.8 Max
Replaces the five launch models with the two that SCX.ai now leads on.
Both are live on api.scx.ai and both were verified against it for tool
calling, json_object and json_schema output, reasoning, prompt caching,
and, for Qwen3.8 Max, image input

Pricing follows SCX's published USD rates. GLM-5.2 lands at $0.55/M input
and $1.9255/M output, tracking the recent GLM-5.2 market repricing;
Qwen3.8 Max at $1.815/M and $5.4461/M sits under the only other seller of
that model, and is the first Qwen3.8 Max entry in the catalog

Also corrects a metadata bug the removed entries carried: they set
max_tokens equal to max_input_tokens, conflating the context window with
the output cap. Both new entries declare a max_output_tokens of 131072,
which is what the endpoint's own validator enforces

The Add Model placeholder moves to scx-ai/GLM-5.2 now that MiniMax-M2.7
is no longer in the catalog
2026-08-07 11:22:01 +10:00
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
tin-berri
7da891a42a
fix(ui): match auto-router preset models against wildcard-expanded model groups (#36111) 2026-08-06 17:47:05 -07:00
mubashir1osmani
5102b9c0d8 fix(ui): ignore stale playground model loads on key switch
Cancel in-flight model fetches when the key or source changes so an older
response cannot overwrite modelInfo. Drop the inverted endpoint-filter
assertion; filtering coverage lands in the next stack PR
2026-08-06 15:33:30 -07:00
mubashir1osmani
bb5d9a199a feat(ui): migrate ChatUI off Ant Design and Tremor
Replace ChatUI cards, inputs, dialogs, popovers, MCP selects, uploads,
tooltips, and icons with shadcn/Base UI and Lucide. Update ChatUI tests
to drive searchable combobox controls instead of Ant Design selectors
2026-08-06 14:33:39 -07:00
mubashir1osmani
ea654d11a5 feat(ui): migrate playground tabs and message icons to shadcn
Replace Tremor playground page tabs with Base UI tabs and swap remaining
message bubble and attachment renderer icons to Lucide
2026-08-06 14:26:15 -07:00
mubashir1osmani
f5d98c0b8c feat(ui): migrate playground chat controls toward shadcn
Continue the Playground Chat Ant Design/Tremor migration: shared MultiSelect,
upload validation with semantic file inputs, collapsible message widgets, and
AdditionalModelSettings on Base UI controls
2026-08-06 14:25:11 -07:00
Mateo Wang
0acca3e86a
Merge pull request #24548 from mpcusack-altos/fix/bedrock-batch-credential-fields
fix(router): include Bedrock batch/S3 fields and model in deployment credentials
2026-08-05 22:39:39 -07:00
tin-berri
34fc8d2ee7
fix: expired-miss share over all measured turns + cost-optimization tab labels (#36037)
* fix(ui): make the expired-miss stat row a focusable tooltip trigger

* fix: auto-router expired-miss percentage and cost-optimization tab labels

- change expired-miss percentage denominator from return-to-tier misses to
  all measured turns (same_model + first_visit + return_to_tier). when
  auto-routers flip tiers rapidly within TTL, return-to-tier turns become
  hits and disappear from the miss count; the old metric reported only the
  rare failure population. the new metric contextualizes that population as
  a share of overall coverage
- rename usage tab from 'Usage' to 'Overall'
- rename auto-router-usage tab from 'Auto-Router Usage' to 'Auto-Router'
- update component and unit tests to match new semantics
2026-08-05 22:34:55 -07:00
tin-berri
86890654c5
fix(proxy): include today's UTC bucket when a daily activity range ends at the caller's current day (#36051)
* fix(proxy): include today's UTC bucket when a daily activity range ends at the caller's current day

* fix(proxy): gate the current-UTC-day extension behind an opt-in param sent by the cost optimization dashboard

* fix(ui): label cost optimization savings dates as UTC days
2026-08-05 22:33:54 -07:00
Michael Cusack
3d275d97fe fix(router): return model and Bedrock batch fields in deployment credentials
get_deployment_credentials_with_provider dropped s3_region_name,
s3_encryption_key_id, and aws_batch_role_arn because
CredentialLiteLLMParams never declared them, and it never returned the
deployment's model, so proxy batch creation against Bedrock failed with
"LiteLLM doesn't support custom_llm_provider=bedrock for 'create_batch'"
or "AWS IAM role ARN is required" (#25104)

Provider-only file and batch calls keep their no-model contract:
get_team_provider_credentials strips the model key so a provider-scoped
request is not pinned to an arbitrary matching deployment
2026-08-05 21:49:31 -07:00
Mateo Wang
ba91768146
Merge pull request #35925 from BerriAI/litellm_tier_aware_reasoning_token_cost
fix(cost): bill reasoning tokens at the service tier output rate
2026-08-05 21:09:55 -07:00
tin-berri
7c621b3141
fix(auto-router): accept every reminder marker pair a harness emits (#36029)
* fix(auto-router): accept every reminder marker pair a harness emits

reminder_markers held one (open, close) pair, so a harness that wraps
injected context differently per agent type only got the slice of traffic
using the configured envelope stripped. Every other agent type kept hitting
the original bug: its reminder-only turn never stripped to empty, won
"newest human ask", and the harness blob got classified in place of the
real question, choosing the tier and therefore the spend.

The field now takes a list of ReminderMarkerPair, following the
KeywordTierRule pattern already in this file so each pair validates itself
and errors point at reminder_markers.N.close rather than a bare index.

Blocks from different pairs can nest, which the gap construction could not
handle: resuming the kept text at an inner block's end walks back inside
the enclosing block and leaks its remainder. Running the block ends through
a maximum collapses nested and overlapping spans without a separate merge
pass, and stays linear in block count, which a fold over a growing tuple
of merged spans would not.

A single pair's ends already increase, so the maximum is the identity and
the default path is byte-identical: verified against the shipped function
over 200k generated inputs, and every existing reminder test passes
unchanged. The prior single-pair config shape is rejected loudly at
startup and at /model/new rather than silently stripping nothing.

* docs(auto-router): document reminder_markers in the complexity router README

* chore(ui): regenerate dashboard API types for the reminder_markers shape

---------

Co-authored-by: Abhimanyu Kapur <38531241+akapur99@users.noreply.github.com>
2026-08-05 21:03:36 -07:00
mateo-berri
1b30b1bc20 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_tier_aware_reasoning_token_cost
# Conflicts:
#	litellm/types/utils.py
2026-08-05 20:45:34 -07:00