-
Notifications
You must be signed in to change notification settings - Fork 974
feat(anthropic): add quota-window account pool routing (carry of #2560) #2982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a575eb1
f9323b0
35e16d7
4f870c8
dd15b54
57cbe6b
8628c07
a584438
77cb03b
16ee295
36a970c
d283a7d
43430e1
853ac54
fa4a8cc
ba4433d
5c1e220
dc461bd
d8bf706
af58ceb
43e60a6
5ec56ef
6f7b1fd
6b8b3a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,9 +13,10 @@ You can log in multiple Claude accounts via the Providers dashboard (`ocx login | |||||||||||
| add-account). By default every request uses the **active** account only. | ||||||||||||
|
|
||||||||||||
| An **experimental, opt-in** Claude account pool (`anthropicAccountPool.enabled`) adds sticky | ||||||||||||
| session affinity and 429 cooldown failover across those OAuth accounts. For **new** sessions | ||||||||||||
| only, `anthropicAccountPool.strategy` selects among eligible accounts: `quota` (default) picks | ||||||||||||
| lowest known 5-hour usage when above `autoSwitchThreshold`; `round-robin` spreads evenly | ||||||||||||
| session affinity and 429 cooldown failover across those OAuth accounts. For **new** sessions, | ||||||||||||
| `anthropicAccountPool.strategy` selects among eligible accounts: `quota` (default) picks the | ||||||||||||
| lowest known usage in the window set by `quotaWindow` (`five-hour` by default, or `weekly` / | ||||||||||||
| `max-utilization`) when above `autoSwitchThreshold`; `round-robin` spreads evenly | ||||||||||||
|
Comment on lines
+17
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Document The new text explains
As per path instructions, user-facing documentation must stay synchronized with actual CLI/API behavior. The supplied routing contract states that 📍 Affects 3 files
🤖 Prompt for AI AgentsSource: Path instructions
Comment on lines
+18
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Clarify the scope of The State that new-session As per path instructions, Proposed wording-`quota` (default) picks the lowest known usage in the window set by `quotaWindow` (`five-hour` by default, or `weekly` /
-`max-utilization`) when above `autoSwitchThreshold`;
+`quota` (default) picks the lowest known usage in the window set by `quotaWindow` (`five-hour` by default, or `weekly` /
+`max-utilization`) for new-session selection; `autoSwitchThreshold` controls proactive switching only.📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Path instructions |
||||||||||||
| (`stickyLimit`, default `1`); `fill-first` drains the active account until cooldown, | ||||||||||||
| reauthentication, or threshold, then advances. It is **off by default**, shows a GUI warning, | ||||||||||||
| and is not battle-tested — Anthropic may restrict accounts that look like automated rotation; | ||||||||||||
|
|
@@ -31,6 +32,11 @@ Operational contract when enabled: | |||||||||||
| selection until re-authenticated. | ||||||||||||
| - If every eligible account is cooling, the proxy returns **429** (not 401) with `Retry-After` | ||||||||||||
| when known. | ||||||||||||
| - Recovery, including 429 failover, uses `quotaWindow` to rank eligible replacements without | ||||||||||||
| changing the existing cooldown or failover limits; `round-robin` ignores `quotaWindow`. | ||||||||||||
| - `autoSwitchThreshold: 0` turns off **proactive** usage-based switching only. New-session | ||||||||||||
| selection and 429 recovery still consult `quotaWindow`, so the window is inert only under | ||||||||||||
| `round-robin`. `fill-first` evaluates its drain threshold in the selected window. | ||||||||||||
|
|
||||||||||||
| See [Configuration](/reference/configuration/#anthropicaccountpool-experimental). | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -283,8 +283,9 @@ rotation may trigger provider restrictions. | |
| | Key | Type | Default | Description | | ||
| | --- | --- | --- | --- | | ||
| | `anthropicAccountPool.enabled?` | `boolean` | `false` | Enable sticky affinity and 429 cooldown failover. | | ||
| | `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | For new sessions, choose the lowest known cached 5-hour usage at or above this threshold. `0` disables quota picking. | | ||
| | `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session strategy; quota uses 5-hour bars only. | | ||
| | `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | For new sessions, when the active account reaches this threshold, choose the lowest known cached usage in the configured window; the account chosen does not itself have to be at or above the threshold. `0` disables **proactive** usage-based switching only — new-session selection and routing recovery after an eligible 429 still consult `quotaWindow`. | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- repository convention and learning files ---'
find /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732 \
-maxdepth 2 -type f -name '*.md' -print
printf '%s\n' '--- declaration and targeted test excerpts ---'
rg -n -C 8 'autoSwitchThreshold|quotaWindow|quota|eligible|429' \
src/oauth/anthropic-routing.ts tests/anthropic-account-pool.test.ts
printf '%s\n' '--- documentation and locale references ---'
rg -n -C 3 'autoSwitchThreshold|quotaWindow|quota selection|account pool' \
docs-site/src/content/docs/reference/configuration/providers.md \
docs-site/src/content/docs --glob '*providers.md' --glob '*configuration*' || trueRepository: lidge-jun/opencodex Length of output: 50376 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- routing control flow ---'
sed -n '450,540p' src/oauth/anthropic-routing.ts
printf '%s\n' '--- threshold-zero and quota-window tests ---'
rg -n -C 10 'threshold.?0|threshold.?=.?0|autoSwitchThreshold: 0|quota.*429|429.*quota|quota.*selection' \
tests/anthropic-account-pool.test.ts
printf '%s\n' '--- documentation convention and scoped learnings ---'
cat /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732/conventions/docs-site.md
cat /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732/learnings/docs-site-src-content-docs.md
cat /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732/learnings/docs-site-src-content-docs-ru.md
printf '%s\n' '--- all provider configuration locale copies ---'
git ls-files 'docs-site/src/content/docs/**' | rg 'configuration/providers\.md$|providers\.md$'Repository: lidge-jun/opencodex Length of output: 12339 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- exact scoring and failover implementations ---'
sed -n '245,345p' src/oauth/anthropic-routing.ts
sed -n '565,603p' src/oauth/anthropic-routing.ts
printf '%s\n' '--- exact threshold-zero tests and surrounding assertions ---'
sed -n '545,595p' tests/anthropic-account-pool.test.ts
printf '%s\n' '--- English and localized provider configuration entries ---'
for f in \
docs-site/src/content/docs/reference/configuration/providers.md \
docs-site/src/content/docs/ja/reference/configuration/providers.md \
docs-site/src/content/docs/ko/reference/configuration/providers.md \
docs-site/src/content/docs/ru/reference/configuration/providers.md \
docs-site/src/content/docs/zh-cn/reference/configuration/providers.md
do
printf '\n### %s\n' "$f"
rg -n -C 2 'autoSwitchThreshold|quotaWindow|anthropicAccountPool' "$f" || true
doneRepository: lidge-jun/opencodex Length of output: 38712 Align With 🤖 Prompt for AI AgentsSource: Path instructions |
||
| | `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session strategy; `quota` ranks accounts by the window set by `quotaWindow`, and `fill-first` evaluates its drain threshold in that same window. | | ||
| | `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | The cached provider-reported utilization bar used for usage-aware account selection. `five-hour` keeps the original behavior. `weekly` scores the weekly bar and skips accounts whose 5-hour bar is exhausted while another eligible account remains, but falls back to exhausted candidates when none do. `max-utilization` scores the highest known bar, so it can use 5-hour usage before weekly usage is available; if neither is known, the account follows unknown-usage ordering. Known usage ranks before unknown usage under the opt-in `weekly` and `max-utilization` windows only; an omitted or explicit `five-hour` preserves the legacy ordering. If every eligible account is unknown, selection still returns one in eligible order. After the documented lower-5-hour tie-break, exact ties preserve eligible order. A healthy affinity-bound session is not proactively rebalanced. For new-session assignment and routing recovery after an eligible 429 replacement, `quota` ranks eligible candidates directly with this window; `fill-first` advances in stable order using this window's threshold and exhaustion rules; `round-robin` ignores it. Cooldown, failover limits, and reauthentication eligibility remain separate local state. Per-account weekly bars are only known once the dashboard Providers page has polled them. | | ||
| | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Successful new-session binds retained on one round-robin selection. Range 1–100. | | ||
|
|
||
| When enabled, 429 records bounded cooldown from `Retry-After` or a default backoff and may rotate | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Limit known-before-unknown ordering to opt-in quota windows.
The translated reference rows describe the opt-in ordering rule as if it also applies to the default
five-hoursetting. State thatweeklyandmax-utilizationuse known-before-unknown ordering, while omitted or explicitfive-hourpreserves legacy ordering.docs-site/src/content/docs/fr/reference/configuration/providers.md#L198-L198: Scope the known-before-unknown sentence to opt-in windows.docs-site/src/content/docs/ja/reference/configuration/providers.md#L164-L164: Scope the known-before-unknown sentence to opt-in windows.docs-site/src/content/docs/zh-tw/reference/configuration/providers.md#L131-L131: Scope the known-before-unknown sentence to opt-in windows.As per path instructions, translated documentation must stay synchronized with actual CLI/API behavior. The supplied PR objective states that known-before-unknown ordering is restricted to opt-in windows and that explicit
five-hourpreserves legacy ordering.🧰 Tools
🪛 LanguageTool
[typographical] ~198-~198: Caractère d’apostrophe incorrect.
Context: ... pour la sélection selon l'utilisation.
five-hourconserve le comportement actu...(APOS_INCORRECT)
[typographical] ~198-~198: Caractère d’apostrophe incorrect.
Context: ...-hour
conserve le comportement actuel.weekly` utilise la barre hebdomadaire et...(APOS_INCORRECT)
[style] ~198-~198: Les chiffres s’écrivent généralement en lettres.
Context: ...et ignore les comptes dont la barre sur 5 heures est épuisée tant qu'un autre com...
(NOMBRES_EN_LETTRES_2)
[typographical] ~198-~198: Caractère d’apostrophe incorrect.
Context: ...mais y revient si aucun autre ne reste.
max-utilizationutilise la valeur connu...(APOS_INCORRECT)
[style] ~198-~198: Un autre mot peut être plus précis.
Context: ... ne reste.
max-utilizationutilise la valeur connue la plus élevée et peut donc employer la...(CELEBRE)
[style] ~198-~198: Les chiffres s’écrivent généralement en lettres.
Context: ...evée et peut donc employer la barre sur 5 heures avant que la barre hebdomadaire ...
(NOMBRES_EN_LETTRES_2)
[style] ~198-~198: Un autre mot peut être plus précis.
Context: ...l'ordre des utilisations inconnues. Les utilisations connues précèdent les inconnues, mais si tous l...
(CELEBRE)
[style] ~198-~198: Les chiffres s’écrivent généralement en lettres.
Context: ...enté par la plus faible utilisation sur 5 heures, une égalité exacte conserve cet...
(NOMBRES_EN_LETTRES_2)
[style] ~198-~198: Un verbe peut dynamiser votre phrase.
Context: ...rééquilibrée de manière proactive. Pour l'affectation des nouvelles sessions et la reprise du rou...
(PROP_NOMINALES_EN_VERBALES)
📍 Affects 3 files
docs-site/src/content/docs/fr/reference/configuration/providers.md#L198-L198(this comment)docs-site/src/content/docs/ja/reference/configuration/providers.md#L164-L164docs-site/src/content/docs/zh-tw/reference/configuration/providers.md#L131-L131🤖 Prompt for AI Agents
Source: Path instructions