Commit graph

243 commits

Author SHA1 Message Date
Mateo Wang
4eb13a0b2a
Merge pull request #41843 from BerriAI/litellm_lit8064_unpin_derived_pricing
fix(proxy): unpin cost-map pricing copied into model_info and report pricing overrides
2026-09-18 22:58:04 -07:00
Mateo Wang
cda022ca68
Merge pull request #40243 from zoroyihan7/fix-responses-stream-error-events
fix(responses): emit typed streaming failure events
2026-09-18 17:29:57 -07:00
Mateo Wang
9b342cdd40
Merge pull request #41868 from BerriAI/litellm_config_update_rejects_config_owned_keys
fix(proxy): refuse config-owned keys on POST /config/update
2026-09-18 17:23:23 -07:00
mateo-berri
f143a46cdf chore: merge main into litellm_lit8064_unpin_derived_pricing 2026-09-18 16:11:37 -07:00
Yassin Kortam
87694c26ef
Merge pull request #41324 from BerriAI/litellm_daily_global_spend_table
feat(proxy): add LiteLLM_DailyGlobalSpend key-free rollup for the usage dashboard
2026-09-18 14:53:08 -07:00
mateo-berri
e0a74dabd1 Merge remote-tracking branch 'origin/main' into litellm_config_update_rejects_config_owned_keys 2026-09-18 14:51:11 -07:00
ryan-crabbe-berri
a43a4924a6
Merge pull request #40878 from BerriAI/litellm_null_cost_unpriced_deployments
fix(router): report null cost for unpriced deployments instead of 0
2026-09-18 14:20:52 -07:00
mateo-berri
eb96d885ce fix(proxy): end failed responses streams with [DONE]
Emit data: [DONE] after event: response.failed, and after a late failure
when a terminal event already went out, so OpenAI SDK clients see the
same stream end as a completed response. Restore the lazy OpenAPI
snapshot to its Python 3.12 rendering, which is what CI regenerates.
2026-09-18 14:16:47 -07:00
mateo-berri
6449632c7b fix(proxy): persist only the router settings keys the request set 2026-09-18 14:01:05 -07:00
mateo-berri
df1b3c849b fix(responses): keep upstream error details in response.failed
RateLimitError and InternalServerError now carry the provider body, so
the OpenAI exception mapper keeps upstream codes like cyber_policy and
the upstream message instead of a generic mapped one

The proxy's response.failed event prefers the upstream body's code,
message, and type over the mapped exception's, and numeric error codes
in an error event map to their own HTTP status
2026-09-18 13:58:53 -07:00
mateo-berri
f4aff06a3e chore: merge main into fix-responses-stream-error-events 2026-09-18 13:49:37 -07:00
mateo-berri
acfe9a899a merge main and drop config_data from its two routing group tests 2026-09-18 13:22:54 -07:00
yassin
6a6ae2d064 Merge remote-tracking branch 'origin/main' into litellm_daily_global_spend_table 2026-09-18 20:20:17 +00:00
yucheng-berri
88e150bb59
Merge pull request #40982 from BerriAI/litellm_lit5285_login_rate_limit_v2
* feat(proxy): limit repeated failed Admin UI sign-in attempts

The Admin UI sign-in endpoints accept an unbounded number of password attempts.
All three call authenticate_user, and none of them keeps any record of how many
times a given caller has already been refused, so a misbehaving or misconfigured
client can retry indefinitely at full speed.

A LoginThrottle is now a required argument to authenticate_user, so the accounting
lives at the one function all three endpoints share and a fourth endpoint cannot be
added without deciding what to pass. Failures are counted per username and source
address over a fixed window and further attempts are refused with 429 and a
Retry-After header. The check runs before the database lookup and before the
password comparison, so a refused caller does no further work.

Only genuine credential rejections count. Configuration errors do not, a refused
attempt does not extend the window, and a successful sign-in clears the bucket.
The username is case folded because the user lookup is case insensitive, so casing
cannot multiply the allowance. Both credential rejections now return one identical
message. SSO is unaffected; it never calls this function.

max_failed_login_attempts (10) and failed_login_window_seconds (900) are read from
config.yaml, with LITELLM_DISABLE_LOGIN_RATE_LIMIT to turn the accounting off. They
are deliberately not database backed, so editing YAML always wins and an operator
refused by a bad value can recover.

* test(proxy): clear failed-login TTLs when resetting the throttle between tests

* feat(proxy): harden Admin UI login throttling

* docs(proxy): clarify login throttle configuration

* fix(proxy): keep the login throttle inside the type budget and fail safe on secret errors

* fix(proxy): warn about per-worker sign-in counters without a module global

* fix: honor environment login throttle settings

* fix: satisfy login setting type checks

* refactor(proxy): keep authenticate_user within the C901 budget after merge

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

* fix(proxy): write failed-login counters and their expiry in one Redis call

Use RedisCache.async_increment_with_floor (a single Lua INCRBY + EXPIRE) for the
shared login counters instead of the two-step INCRBYFLOAT then EXPIRE, so a
counter can never be committed to Redis without its expiry. The repair in
_remaining_window now only covers expiries stripped out of band (PERSIST, a
restore) and uses the same atomic call

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

* fix(proxy): resolve the login rate limit kill switch once per process

Reading LITELLM_DISABLE_LOGIN_RATE_LIMIT through get_secret_bool on every
unauthenticated sign-in attempt meant a hosted secret manager in read mode
was queried once per password guess, before any counter was checked

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

* fix(proxy): count failed sign-ins in Redis alone while it answers

Every worker spends one shared budget and a successful sign-in clears it for all
of them. This worker's own counter is only consulted while Redis raises, so an
outage degrades to per-worker accounting instead of switching the control off

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

* fix(proxy): keep counting the failed sign-ins Redis missed once it answers again

A guess is recorded in exactly one place, Redis or this worker's own store when Redis
refused it, so the count is the sum of the two. Redis is read through
async_batch_get_counts, which raises on failure, instead of async_get_cache, which
swallows it into None and read as an empty counter

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

* refactor(proxy): read the shared sign-in counter through a tuple of keys

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

* refactor(caching): spell out the key collections batch_get_counts accepts

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

* fix(proxy): warn about per-worker login counters even without general_settings

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

* chore(ui): regenerate schema.d.ts after merging main

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

* refactor(proxy): inject settings and Redis cache into LoginThrottle.from_request

Removes the runtime import of proxy_server from login_throttle so the
throttle module no longer participates in the import cycle CodeQL
flagged (py/cyclic-import). Callers pass general_settings and
redis_usage_cache explicitly; behavior is unchanged.

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

* test(proxy): drop the section banner comment from the login tests

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

* refactor(proxy): assert separate login counter stores in the spray regression test instead of a comment

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

* feat(proxy): throttle failed Admin UI sign-ins per source and source/username

Replace the username-global lockout with counters keyed by source address and by
source/username pair. Each has a fixed counting window (60s) and a separate
block TTL (300s). Blocks are soft: a correct password still signs in, wrong
passwords from a blocked key take one of 5 held slots per worker and are held
30s before a 429. Once a pair is blocked its failures stop counting against the
source. The source scope runs only when trusted_proxy_ranges is set, IPv6 is
grouped by /64, and per-source limits accept IP and CIDR overrides with
longest-prefix matching. Redis is authoritative through one Lua script per
failure, with bounded per-worker fallback when Redis raises.

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

* test(proxy): explain the internal patches in the login throttle tests

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

* fix(proxy): key held sign-in attempts on the source while the source is blocked

An active source block now takes precedence over a pair block, so every blocked username behind one blocked source shares the source's five held slots instead of getting five each

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

* fix(proxy): apply source overrides to IPv4-mapped IPv6 sign-in sources

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

* fix(proxy): catch only Redis failures when falling back to local login counters

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

* fix(proxy): type the login throttle's local store and pass frozen Redis script arguments

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

* fix(proxy): keep the sign-in hold pool from refusing a correct password

The held-attempt cap ran before the password check, so five parked wrong
guesses from a blocked source turned the soft block into a lockout for the
real user. The slot is now taken only after a wrong password, and the
pool-full refusal carries the block's remaining time as Retry-After

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

* test(proxy): stub DATABASE_URL in the hold-pool regression test so it passes off the dev box

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

* chore(proxy): drop a comment that restated the NUM_WORKERS assignment

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

* fix(proxy): match IPv4-mapped IPv6 peers against IPv4 trusted proxy ranges

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

* fix(proxy): keep mapped-notation trusted proxy ranges matching mapped peers

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

* feat(proxy): hard-block throttled Admin UI sign-ins with no credential bypass

A blocked source, or source and username pair, is now refused with 429 before the database lookup and password check, in place of the soft block that held wrong guesses for 30 seconds and let a correct password through. The env admin credentials and the master key typed into the login form are refused like any other credential while blocked; recovery is the master key as an API bearer token, which never goes through the sign-in path

trusted_proxy_ranges: [] now means clients connect directly, so the peer address is the source and the per-source limit stays on. Only an unset or malformed value leaves the topology unknown, warns at startup and turns the per-source limit off

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

* refactor(proxy): move login throttle sentinels into constants

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

* feat(proxy): derive the per-username sign-in allowance from the address limit

The per-address-and-username allowance is now half the effective address allowance, rounded up, instead of a separate max_failed_login_attempts_per_user setting. A per-address override therefore raises or effectively removes both limits for that address, and no second override table is needed

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

* refactor(proxy): raise the sign-in block explicitly and type the empty settings mapping

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

* feat(proxy): round the per-username sign-in allowance down and exempt an address with an override of 0

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

* test(proxy): import LoginThrottle under TYPE_CHECKING for the throttle helper annotation

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

* fix(proxy): break ties between equivalent login limit overrides deterministically

Two spellings of one network share a prefix length, so the exemption wins the tie, then the higher limit, regardless of mapping order

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

* fix(proxy): treat a malformed trusted_proxy_ranges entry as an undeclared topology

A list with an entry that is not an address or CIDR range no longer switches
the per-source Admin UI sign-in limit on against the direct peer address, so a
typo cannot make a shared ingress address the bucket for every user behind it

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

* fix(proxy): reject blank trusted_proxy_ranges entries before they are dropped

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

---------

Co-authored-by: Yucheng Zhu <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 13:18:50 -07:00
mateo-berri
1581c45615 fix(proxy): check and persist only the settings the request sent
POST /config/update compared litellm_settings after lowercasing the
callback list, so a config file spelling a callback in mixed case refused
the same list sent back, and it stored every general_settings model default
next to the keys the request set. Both now use the request as sent; only
the stored callback list is lowercased.

Also drops config_data from the router settings reload callers the previous
commit left behind and teaches the legacy MockProxyConfig the ownership
check.
2026-09-18 13:14:22 -07:00
ryan-crabbe-berri
d37320f8cf fix(proxy): report null cost for unpriced deployments on the /model/info id lookup
GET /model/info?litellm_model_id= went through _get_proxy_model_info, a copy of _enrich_model_info_with_litellm_data that missed the unpriced check, so the same deployment read as null in the list and as 0 on the id lookup. The id lookup now delegates to the shared helper, so the two paths cannot drift again
2026-09-18 13:08:55 -07:00
yassin
b92820dcfe Merge branch 'litellm_usage_key_free_aggregate_split' into litellm_daily_global_spend_table 2026-09-18 20:06:47 +00:00
jesus
32e6a86319 fix(router): report null cost for unpriced deployments instead of 0
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 12:52:57 -07:00
mateo-berri
7cfec730d5 fix(proxy): refuse config-owned keys on POST /config/update
POST /config/update stored keys the config file owns and answered 200
while the file silently kept winning. Run the config-owned check for
general_settings, litellm_settings, and router_settings before the first
database read, the way /config/field/update already does, so a refused
request stores nothing.

The config reload re-loaded the merged settings as yaml settings, which
turned every saved router setting read-only after one tick. Read the
saved router settings row instead so database-owned values stay writable.

The integration harness seeds num_retries through /config/update instead
of the config file, which is what the effective-settings and observed
routing tests need to keep exercising a database-owned value.
2026-09-18 12:42:08 -07:00
mateo-berri
42541a9233 fix(proxy): drop echoed cost-map pricing on a row's next save and build /model/info pricing stamps without mutation 2026-09-18 11:42:07 -07:00
yassin
fa70e49b81 chore: merge main into litellm_transcribe_passthrough
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 17:54:59 +00:00
mateo-berri
b03957ba9c fix(proxy): unpin cost-map pricing copied into model_info and report pricing overrides
A model_info blob that carries key next to pricing fields is a copy of a /model/info response (only litellm.get_model_info emits key), so those pricing fields are dropped when the row is loaded from the DB and on every Reload Price Data, and the deployment follows the current cost map again. Prices typed into litellm_params, or into model_info without key, stay as they are.

/model/info, /v1/model/info and /v2/model/info now report model_info.pricing_overrides, the pricing fields the deployment sets itself, and the Admin UI model page says whether a price follows the cost map or overrides it.
2026-09-18 10:49:36 -07:00
yassin
f631301cfa Merge branch 'litellm_usage_key_free_aggregate_split' into litellm_daily_global_spend_table 2026-09-18 09:29:47 +00:00
yucheng
fade26b969 feat(proxy): derive the per-username sign-in allowance from the address limit
The per-address-and-username allowance is now half the effective address allowance, rounded up, instead of a separate max_failed_login_attempts_per_user setting. A per-address override therefore raises or effectively removes both limits for that address, and no second override table is needed

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 09:25:34 +00:00
Yuneng Jiang
2f3e4fa724
test(proxy): pass the new pass-through argument to the side-effect dispatcher
_apply_general_settings_side_effects grew a fourth argument when the reload
started comparing the resolved pass-through list, and this dispatch test calls
it positionally, so it failed with a TypeError.
2026-09-18 02:17:52 -07:00
Yuneng Jiang
8e67a33fc3
fix(proxy): refuse config-owned writes at one choke point and refresh the store
Both write paths now go through the same refusal, so /config/field/update and
/config/update answer identically instead of each phrasing its own rule.

A successful write now applies to the SettingsStore, so the next read sees it.
Without this, /config/field/info reported a key the dashboard had just stored
as "not set" until the process reloaded from the database.

resolve() no longer takes a KeyRule it never reads; the store picks the row.
The matrix tests resolve through SettingsStore instead of calling resolve
directly, so the section and key in each case actually route a lookup.

ConfigFieldInfo and ConfigList type `source` as the FieldSource literal, and
the dashboard API types are regenerated for the two new fields.
2026-09-18 01:49:30 -07:00
Yuneng Jiang
afa4a6fe78
refactor(proxy): make the config file win over the database
The precedence used to vary per key: some keys let a stored row win, some
let the file win, some merged the two. That meant an operator could not
answer "which value is live?" without knowing the key.

Now file presence decides ownership. A key the config file declares is
config-owned, whatever the database holds, and a key the file omits falls
back to the stored row. KeyRule no longer carries a RuleKind, only which
row the stored value lives in.

Writes to a config-owned key are refused at the two surfaces that reach
the database instead of being stored and silently ignored: save_config
and /config/field/update both 400 naming the key and the config file path.

Both read endpoints now report source and editable off the same
SettingsStore, so /config/field/info and /config/list can no longer
disagree inside one process.

Replaces the 786-case checked-in JSON fixture with cases generated from
the rule table, so the matrix tests no longer assert that resolve() agrees
with a snapshot of resolve().

BREAKING CHANGE: a dashboard or /config/field/update write to a setting
the config file declares now returns 400 instead of being stored. Remove
the key from the config file to let the database own it.
2026-09-18 01:28:21 -07:00
Yuneng Jiang
0524745510
fix(proxy): preserve config pass-through and retention reloads 2026-09-18 00:23:24 -07:00
Yuneng Jiang
d1cd869012
refactor(proxy): resolve config and DB settings precedence in one SettingsStore 2026-09-17 23:36:27 -07:00
Yuneng Jiang
77a5e2cb64
test(proxy): isolate environment variable encryption 2026-09-17 21:07:02 -07:00
Yuneng Jiang
463ece762a
fix(proxy): preserve opted-in environment variable saves 2026-09-17 20:53:21 -07:00
Yuneng Jiang
af17691389
fix(proxy): persist only the keys a caller changed in save_config 2026-09-17 20:32:04 -07:00
yassin
393d084db7 feat(proxy): restrict Transcribe media and output buckets per operator allowlist
Non-admin keys may only start transcription jobs whose media and transcript output live in the S3 buckets listed in general_settings.transcribe_media_buckets, and may not supply DataAccessRoleArn or JobExecutionSettings. The setting is editable from the Admin UI general settings table (new List editor) and DB values load into the running proxy when config.yaml does not set it

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 01:18:07 +00:00
yassin
3b2b9bf7b6 Merge branch 'litellm_usage_key_free_aggregate_split' into litellm_daily_global_spend_table
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled
2026-09-17 17:55:47 +00:00
yucheng
b227a8c4c9 refactor(proxy): move login throttle sentinels into constants
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 16:42:04 +00:00
yucheng
9a365d2021 feat(proxy): hard-block throttled Admin UI sign-ins with no credential bypass
A blocked source, or source and username pair, is now refused with 429 before the database lookup and password check, in place of the soft block that held wrong guesses for 30 seconds and let a correct password through. The env admin credentials and the master key typed into the login form are refused like any other credential while blocked; recovery is the master key as an API bearer token, which never goes through the sign-in path

trusted_proxy_ranges: [] now means clients connect directly, so the peer address is the source and the per-source limit stays on. Only an unset or malformed value leaves the topology unknown, warns at startup and turns the per-source limit off

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 16:10:23 +00:00
Moe Khalil
bab273ea0f fix(router): preserve discovered limits and model info fallbacks
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 00:23:50 +00:00
Moe Khalil
39286245b5 chore: merge main into model info discovery branch
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 00:10:00 +00:00
ryan-crabbe-berri
43713f7508
Merge pull request #39996 from BerriAI/litellm_team_admin_editable_fields
feat(proxy): let proxy admins choose which team fields team admins may edit
2026-09-16 17:07:13 -07:00
Moe Khalil
b7c6befb37 feat(router): discover token limits for hosted OpenAI-compatible models
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 23:19:54 +00:00
mateo-berri
3712d8de92 Merge remote-tracking branch 'origin/main' into litellm_model_group_info_proxy_admin_all_models
Some checks failed
LiteLLM Rust / rust-wheel (push) Has been cancelled
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
2026-09-16 16:18:45 -07:00
mateo-berri
2a9fa48730 fix: expand wildcard deployments for proxy admins on /model_group/info 2026-09-16 16:18:44 -07:00
yucheng
db97616149 chore: merge main into litellm_lit5285_login_rate_limit_v2
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 23:02:23 +00:00
ryan
287bbaa6c1 fix(proxy): remove duplicate user budget hook that 429'd zero-cost models
_PROXY_MaxBudgetLimiter re-checked spend:user:{id} against user_max_budget in
async_pre_call_hook without the zero-cost model exemption that
_user_max_budget_check applies in auth, so free models were rejected with
"Max budget limit reached." once a user was over budget. Auth already owns
this check, so the hook is deleted rather than taught the exemption again

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 15:42:15 -07:00
ryan-crabbe-berri
ac47c95db9 fix(proxy): re-read UI settings on every config reload
The persisted UI settings were read once at startup, so a proxy admin
flipping a runtime flag through PATCH /update/ui_settings only changed the
pod that served the request. Every other pod kept serving the old value
until it restarted.

add_deployment, the reload the scheduler runs every 30s, now re-reads the
row and applies the runtime flags before it takes the model reconcile lock,
so a change made through one pod reaches the rest within one reload
interval. The startup hook and the two settings endpoints share that helper
instead of each repeating the flag copy.

Claude-Session: https://claude.ai/code/session_018PUCupsaarVLJy4iDFx256
2026-09-16 15:38:06 -07:00
mateo-berri
ea5887d4bb test: cover proxy_admin_viewer sessions in the model_group/info admin regression test 2026-09-16 15:10:48 -07:00
mateo-berri
da844e3dd2 Merge remote-tracking branch 'origin/main' into litellm_model_group_info_proxy_admin_all_models 2026-09-16 14:40:10 -07:00
yassin
834313af4b test(proxy): assert the global rollup split and scheduler through behavior, not SQL text or add_job arguments
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 12:13:57 +00:00
yassin
225fc53f08 Merge branch 'litellm_usage_key_free_aggregate_split' into litellm_daily_global_spend_table 2026-09-16 01:48:46 +00:00
yucheng
7c2c59da90 test(proxy): explain the internal patches in the login throttle tests
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 00:13:51 +00:00