Commit graph

55217 commits

Author SHA1 Message Date
devin-ai-integration[bot]
b5befe2dd0
test(routing): a team's wildcard serves its keys before a proxy-wide wildcard of the same pattern (#48501)
Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:54:32 -07:00
devin-ai-integration[bot]
100529391a
fix(ui): show the budget period date range instead of "cycle" on team member spend (#48488)
* fix(ui): show the budget period date range instead of "cycle" on team member spend

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

* fix(ui): derive the budget period start in UTC before showing it in local time

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

* fix(ui): keep clock times on sub-day budget periods and restore the total spend lower bound wording

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

---------

Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:24:44 -07:00
devin-ai-integration[bot]
549e6d4f46
fix(router): keep DB-only deployments priced across price data reloads (#48486)
* fix(router): track every router for price data reloads so DB-only deployments keep custom pricing

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

* fix(router): register the router for reload replay only once model_list exists, and type the regression test

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

---------

Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:17:52 -07:00
tin-berri
833d82bb4e
fix(mcp): reject revoked browser sessions during gateway authorization (#48494) 2026-10-26 17:14:57 -07:00
devin-ai-integration[bot]
9873128b42
fix(team): keep the team reset schedule when a temp budget increase is set on a member inheriting the team default (#48495)
* fix(team): keep the team reset schedule when a temp budget increase is set on a member inheriting the team default

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

* test(integration): expect the temp-only member row to carry the team default cap

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

---------

Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:13:56 -07:00
devin-ai-integration[bot]
76d001a7c0
fix(router): serve a team's wildcard deployment before a proxy-wide wildcard (#48490)
* fix(router): serve a team's wildcard deployment before a proxy-wide wildcard

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

* fix(router): keep the wildcard precedence helpers free of partially typed locals

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

* fix(router): call each pattern router once in the wildcard precedence helpers

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

* test(ptu): a team's wildcard reservation serves beside a proxy-wide catch-all

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

---------

Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:06:09 -07:00
devin-ai-integration[bot]
1263f70ab6
feat(ui): budget period tooltip on key, team, user and org spend tiles (#48487)
* feat(ui): budget period tooltip on key, team, user and org spend tiles

Adds a shared BudgetPeriodTooltip to the four detail-view spend tiles showing the current budget period, max budget, reset interval and spend so far, and makes organization create schedule budget_reset_at and organization info return it

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

* fix(ui): give the budget period tooltip trigger its own aria label

The default SimpleTooltip trigger shares the question-circle label with InheritedBudgetHint, which broke the key budget display tests that count that icon

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

* fix(ui): match the proxy's budget window rules in the period tooltip

30d and Nmo now span calendar months like get_budget_window_start, the arithmetic runs in UTC so a viewer's DST change cannot shift the start, the hourly/daily/weekly/monthly aliases the proxy accepts are normalized before parsing, and spend without a duration reads as lifetime spend

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

---------

Co-authored-by: joshua <joshua@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:37 -07:00
yujonglee
b9825e1f87
docs: document incremental database access migration (#48476)
* docs(rust): document incremental database access migration

* docs(rust): organize database guidance by task

* docs: move database access skill to repository root

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:08 -07:00
yujonglee
a783f8e78b
feat(db): add typed daily end-user spend upsert (#48237)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:08 -07:00
yujonglee
a2545134f3
feat(db): add typed daily team spend upsert (#48236)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:07 -07:00
yujonglee
1b874ceb85
feat(db): add typed daily user spend upsert (#48235)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:07 -07:00
yujonglee
b446d58909
feat(db): add typed spend-log insert query (#48234)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:06 -07:00
yujonglee
46410c8da9
feat(db): add typed team-member spend upsert (#48233)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:06 -07:00
yujonglee
c531692976
feat(db): add transaction-scoped team lock query (#48232)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:06 -07:00
yujonglee
8f456eb7d5
feat(db): add typed end-user spend query (#48231)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:05 -07:00
yujonglee
3b72c08c4f
feat(db): add typed team spend query (#48230)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:05 -07:00
yujonglee
8e61c22fe0
feat(db): add typed user spend query (#48229)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:04 -07:00
yujonglee
35cd5fc05f
feat(db): add typed key spend query (#48217)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:04 -07:00
yujonglee
554b011787
feat(rust): add typed database query foundation (#48214)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:05:04 -07:00
Kerry Lu
db1c871c12
refactor(cost-map): drop the legacy max_tokens field in favor of max_input_tokens and max_output_tokens (#48471)
* refactor(cost-map): drop the legacy max_tokens field in favor of max_input_tokens and max_output_tokens

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

* test: drop assertions that pinned the retired cost-map max_tokens field

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 17:03:05 -07:00
moe-berri
7fd8740ad5
fix(router): isolate forwarded Anthropic subscription cooldowns (#48485)
* fix: isolate forwarded Anthropic subscription cooldowns

* test: fix the clock for Anthropic cooldown regression
2026-10-26 16:54:38 -07:00
ryan-crabbe-berri
df06b2d4fb
chore(lint): add google-convention docstring rules to strict ruff gate (#48245)
* chore(lint): add google-convention docstring rules (D202, D403, D417) to strict ruff gate

* fix(lint): mark docstring rules external in base ruff config so RUF100 keeps their noqa
2026-10-26 16:52:43 -07:00
yucheng-berri
a4ee952444
fix(proxy)!: gate key budget_duration and budget_id updates like max_budget (#47681)
* fix(proxy): gate key budget_duration and budget_id updates like max_budget

A key owner or team member could shorten budget_duration or swap budget_id on
/key/update without the budget authorization max_budget gets, so the reset job
cleared spend on a capped key or a bigger tier lifted its cap

Fixes #46916

* test(proxy): cover tier keys and self-serve budget policies for key budget updates

---------

Co-authored-by: yucheng-berri <293926326+yucheng-berri@users.noreply.github.com>
2026-10-26 16:45:35 -07:00
tin-berri
bc0f598db5
fix(proxy): validate JSON object bodies before request handling (#48438) 2026-10-26 16:11:38 -07:00
ryan-crabbe-berri
db9eda19b4
fix(http_handler): name the timeout phase and limit that fired instead of "after None seconds" (#48250)
* fix(http_handler): name the timeout phase and the limit that fired instead of 'after None seconds'

Every HTTP verb on both handlers raised litellm.Timeout with the per-call
timeout argument interpolated into the message, which is None whenever the
caller relied on the client default, and always said "Connection" even for a
read timeout. One helper now reads the limit httpx actually enforced from the
failed request and names the phase that fired

Fixes #14635

* fix(rust_bridge): name the timeout phase in the vault timeout message to match the httpx handler

* fix(http_handler): drop the unreachable timeout fallbacks httpx already rules out

* refactor(rust_bridge): drop a doc comment that restated the timeout helper
2026-10-26 16:04:33 -07:00
tin-berri
593c640971
fix(models): declare Azure audio snapshot capabilities (#48475) 2026-10-26 16:00:38 -07:00
Zap777
ffb79b10ee
fix(mcp): send tool-call stream headers once the call is authorized (#47897)
OAuthScopeResponse holds a tools/call response's http.response.start so a managed OAuth scope challenge can replace it with a 403. Once the call was allowed, the held start still waited for the next body message, which for a slow tool is the 15s SSE keep-alive ping. Send it as soon as the call is allowed instead.

Fixes #46659
2026-10-26 16:00:02 -07:00
devin-ai-integration[bot]
2e27a02a9f
feat(chatgpt): forward client subscriptions through the gateway (#41522)
* feat(chatgpt): forward each Codex user's ChatGPT OAuth login through the proxy

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

* test(router): cover _model_group_llm_provider metadata resolution

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

* fix(chatgpt): keep the gateway ChatGPT login bound to the authenticator api_base

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

* refactor(chatgpt): move client credential header selection into the chatgpt provider

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

* test(chatgpt): cover credential recognition and stored account id fallbacks

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

* feat(chatgpt): support per-model chatgpt_auth_file for multiple ChatGPT accounts

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

* fix(chatgpt): resolve bare chatgpt_auth_file paths and drop redundant test docstring

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

* fix(chatgpt): pass per-model auth file to early provider detection

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

* fix(chatgpt): normalize chatgpt_auth_file before caching the authenticator

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

* fix(chatgpt): type account selection parameters

* fix(chatgpt): preserve account selection through saved prompts

* fix(chatgpt): allow administrator account configuration through the proxy

* test(chatgpt): construct immutable request parameters

* fix(router): preserve typed deployment credential resolution

* fix(chatgpt): allow admins to probe unsaved account configurations

* fix(chatgpt): retain SDK login headers during provider resolution

* fix(chatgpt): allow admins to probe unsaved account configurations

* fix(chatgpt): normalize subscription health probe input

* fix(chatgpt): normalize health probe input and cover credential destinations

* test(chatgpt): keep destination rejection assertions focused

* feat(proxy): forward client ChatGPT subscriptions on native Codex routes

* docs: lead ChatGPT forwarding with standard model setup

* fix(chatgpt): preserve selected credentials in health provider lookup

* fix(chatgpt): preserve gateway credentials and workspace selection

* refactor(chatgpt): avoid rebinding streaming metadata inputs

* fix(chatgpt): keep account lookup token argument immutable

* fix(chatgpt): scope forwarded credential routing to ChatGPT

* refactor: keep forwarded credential isolation opt-in by provider

---------

Co-authored-by: Moe Khalil <moe@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Urbanonymous <ugutitej@gmail.com>
Co-authored-by: mateo <mateo@berri.ai>
2026-10-26 15:44:05 -07:00
moe-berri
4da24fa01e
fix(ui): show search tool errors instead of empty results (#48478)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 15:42:17 -07:00
yucheng-berri
7045139c3a
fix(router): stop concurrent deployment deletes from crashing deployment lookups (#47680)
* fix(router): stop concurrent deployment deletes from crashing deployment lookups

delete_deployment and upsert_deployment shrink model_list before they repair
the index maps, so a lookup on another thread in that window read a stale
index: IndexError, or the neighbouring deployment and its credentials. An add
racing a delete could corrupt the index for good.

One RLock now covers model_list and the three index maps. Delete, upsert, add
and the set_model_list reset change them under it, and every lookup that turns
an index into a deployment reads under it.

Fixes #45242

* test(router): release the held delete when the read reaches the index lock

The race tests released the held write after a fixed 0.2 s, so a reader the runner
stalled past it read the repaired list and passed on unfixed code. The read now runs
on its own thread and the write stays held until the read returns or reaches the
router's index lock; the 10 s bound only fails a broken synchronization.

The integration test gains the audit cells: chat, streaming, Responses and
Anthropic messages calls (sync and async, by model name and team public name)
during a held delete, the same for upsert, add and set_model_list, a request for
the deployment being deleted, a provider error, a double delete, and thread and
async bursts during upsert churn.

* test(router): cover the early return of a delete and the team filter of get_model_ids

delete_deployment now returns None from inside the index lock, and get_model_ids by
name reads its deployments through _deployments_named; pin both: deleting an unknown
id returns None and leaves the list alone, and exclude_team_models drops only the
team deployment.

* fix(router): read deployments by name under the index lock outside the Router

The response polling provider check, the complexity router's adaptive pool and the
savings baseline turned the name index into list positions themselves, so a concurrent
delete could still hand them a stale slot. They now read through Router.deployments_named,
which takes the deployment index lock.

* fix(router): type the locked deployment lookups as DeploymentTypedDict

deployments_named and _team_deployments_named returned tuple[Any, ...]. They now return
DeploymentTypedDict rows, which is what model_list holds. The adaptive pool setup in the
Router and the complexity router drop their branches for pydantic Deployment rows, which
these lookups never return, and should_include_deployment accepts the typed row.

---------

Co-authored-by: yucheng-berri <293926326+yucheng-berri@users.noreply.github.com>
2026-10-26 15:40:19 -07:00
moe-berri
9a35ed93f9
feat(ui): simplify auto router setup with deployed model defaults (#48451)
* feat(ui): simplify auto router setup with deployed model defaults

* fix(ui): recognize catalog Opus deployment formats

* fix(ui): address auto router setup review gaps

* fix(ui): preserve Gemini auto router suggestions

* fix(ui): prefer current aliases and wait for team selection

* fix(ui): default auto routers to classify each user turn

* fix(ui): parse Grok snapshot dates separately from releases

* refactor(ui): use non-mutating auto router sorting

* feat(ui): allow custom models in simple auto router setup
2026-10-26 15:40:03 -07:00
ryan-crabbe-berri
48a893aefc
build(deps): drop expired exclude-newer pins for certifi, mlflow and pypdf (#48461)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 15:38:17 -07:00
tin-berri
8b1910c95a
fix(mcp): advertise valid OAuth resources for toolset URLs (#48474) 2026-10-26 15:30:05 -07:00
devin-ai-integration[bot]
57ac107311
ci: remove the Together AI and weekly cost map sync workflows (#48473)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 15:28:53 -07:00
tin-berri
9a38ff4cb5
fix(gemini): preserve tool media for older models (#48428) 2026-10-26 15:27:13 -07:00
moe-berri
a6fdc7c5a3
fix(proxy): scope dashboard search grants to user (#48464)
Co-authored-by: Jodok Batlogg <jodok@batlogg.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 15:01:40 -07:00
moe-berri
dbd55d3202
fix(ui): keep Aria accessible in the dashboard header (#48454)
* fix(ui): keep Aria accessible in the dashboard header

* test(ui): wait for every pagination fixture log

* test(ui): update assistant setup for Aria branding
2026-10-26 14:55:08 -07:00
tin-berri
ccd783d907
fix(proxy): reject negative RPM and TPM request limits (#48444) 2026-10-26 21:16:15 +00:00
tin-berri
6d93445350
fix(proxy): preserve limiter state across SSE keepalive tasks (#48452) 2026-10-26 14:09:19 -07:00
tin-berri
b7a2226f43
test(proxy): make tokenizer offload check deterministic (#48458) 2026-10-26 20:58:51 +00:00
devin-ai-integration[bot]
c843cee062
feat(pricing): add github_copilot/gpt-6.1-terra (#48450)
* feat(pricing): add github_copilot/gpt-6.1-terra

* fix(pricing): raise github_copilot gpt-6 max_input_tokens to 922000

---------

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 20:55:51 +00:00
moe-berri
3beee3cfe9
fix(elevenlabs): map wav and pcm TTS formats to 24kHz output formats (#48455)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 13:42:01 -07:00
devin-ai-integration[bot]
768960610b
feat(cost-map): add baseten elephant-1 and mammoth-1 decision models (#48453)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 20:41:58 +00:00
shrey-berri
9cb102b721
chore(deps): remove expired boto3 botocore and grpcio overrides (#48447) 2026-10-26 13:41:15 -07:00
tin-berri
f96200bcea
fix(vertex_ai): bound shared credential cache retention (#48442) 2026-10-26 12:56:13 -07:00
devin-ai-integration[bot]
52c11bf383
feat(bedrock): add global. and us. openai.gpt-6.1-terra rows (#48441)
* feat(bedrock): add global. and us. openai.gpt-6.1-terra rows

* chore: rerun ci after flaky event loop timing test

---------

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 19:39:48 +00:00
devin-ai-integration[bot]
c69e82f538
chore(cost-map): add openai batch and ultrafast 12-hour cache write rates from the pricing page (#48433)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 12:18:19 -07:00
devin-ai-integration[bot]
dab39d7402
fix(azure): set azure_ai/Microsoft-Decision-1 max_input_tokens to 32768 (#48434)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-26 12:09:14 -07:00
mrinal-berri
07a82a287b
fix(guardrails): exclude litellm_metadata from pass-through guardrail scan text (#48276)
* fix(guardrails): exclude litellm_metadata from pass-through guardrail scan text

The pass-through guardrail translation json-dumps the request body as the
scan text when no request_fields are configured. The unified guardrail hook
injects litellm_metadata into that body first, so the dump carried the
caller's key metadata. Exclude it alongside metadata and litellm_logging_obj;
vendors still receive it through request_data.

* test(guardrails): type the pass-through scan-text tests per AGENTS.md
2026-10-26 12:07:58 -07:00
tin-berri
85871f791c
fix(ui): render string inputs in general settings (#48431) 2026-10-26 11:50:31 -07:00