Repository navigation
[Feature]: Generic OAuth account-pool failover with session affinity and quota-aware selection #695
Description
Activity
github-actions commented
on Jul 29, 2026 on Jul 29, 2026 – with GitHub ActionsContributorMore actionsAutomated translation bookkeeping — detected language: English.
- addedaccount-poolOAuth, credentials, Codex pool, quota, failover, plansOAuth, credentials, Codex pool, quota, failover, plans
on Aug 1, 2026 Multiple Antigravity accounts can already be stored and selected manually, but "automatically" is not specific enough to define safe routing behavior.
Please clarify the trigger and invariants: quota percentage, upstream 429/402, authentication failure, or round-robin; whether an existing conversation must stay on its account; how unknown quota is handled; and whether the requested policy is Antigravity-only or should use the generic OAuth account pool. Automatic background use is out of scope unless explicitly designed. Keeping this open for those details rather than guessing at a policy.
Triage status: useful capability, but we need the policy defined before implementation. Could you spell out: (1) the exact trigger conditions for an automatic switch (which signals, which thresholds), (2) affinity rules while requests are in flight, (3) behavior when an account's quota state is unknown, and (4) whether this should be Antigravity-specific or a generic pool mechanism? Answers to those four determine the design.
- addedneeds-infoWaiting on reporter for a concrete spec or reproductionWaiting on reporter for a concrete spec or reproduction
on Aug 3, 2026 Proposed Failover & Routing Policy
1. Trigger Signals & Thresholds
-
Primary: Switch immediately on upstream errors
429(Rate Limit) or401/403(Auth invalid). -
Secondary (Optional): Pre-emptive switch when detected quota reaches
$\ge 95%$ .
2. Session Affinity
- Standard conversations should stick to the assigned account during an active session unless a hard error (
429/401) occurs, at which point fallback to a healthy account in the pool happens automatically.
3. Unknown Quota Handling
- Treat unknown quota accounts as "Healthy but unverified", ranking them lower than accounts with known healthy quota, but above depleted/errored accounts.
4. Scope
- Implement via the generic OAuth account pool mechanism so other providers can benefit from identical failover logic in the future.
-
Primary: Switch immediately on upstream errors
Thanks — this answers all four questions, and it is the specification this needed.
Recording the policy as accepted design input:
- Trigger: hard switch on upstream
429and401/403; optional pre-emptive switch at ≥95% detected quota. - Affinity: a conversation stays on its assigned account for the session, and fails over only on a hard error.
- Unknown quota: "healthy but unverified" — ranked below known-healthy, above depleted or errored.
- Scope: the generic OAuth account pool, not an Antigravity-only path.
The scoping answer is the important one. Building this on the generic pool means the same failover logic serves other OAuth providers instead of creating a second, divergent mechanism next to the existing Codex pool — that is the right call and it is what makes this implementable.
Two things still need deciding before code, and they follow from your own rules rather than contradicting them:
- Re-entry after failover. A
429account is not permanently dead. The pool needs a cooldown and a re-probe path, otherwise a busy pool degrades to one survivor by the end of the day. Reset-window handling is being discussed in [Research] Provider-specific post-reset activation to anchor quota windows #823 and [Feature]: opt-in crash-safe reset-credit auto-redemption before expiry #822; this issue should consume whatever those settle on rather than inventing a third policy. - The pre-emptive 95% threshold depends on quota being observable. Where quota is unknown or stale, that rule silently does nothing — which is acceptable, but it means the
429path is the real guarantee and the threshold is an optimization. Worth stating that way so the feature is not oversold.
Keeping this open as the failover-policy issue. #1062 tracks the pooling and quota-statistics surface for Antigravity, and #821 tracks user-defined priority ordering on top of automatic selection — all three want the same underlying pool, so the runtime slice should land once and be shared.
No implementation timeline promised. This is now unblocked on design, which it was not before.
Reacted by agentHitsReacted by agentHits- Trigger: hard switch on upstream
@Wibias @lidge-jun The most important task is to implement a feature for importing accounts from any subscription—specifically, subscriptions sourced from the Cockpit Tools application. This application stores subscription data, which we can export in the following format: [
{
"email": "jimguerrero@gmail.com",
"refresh_token": "1//0cEqtAXq6tRLmCgYIARAAGAwSNwF-D8IrR5oO9j05ZXkGS0FRW9FMEjOwLyae9aIj5nGwfo4-HcTP1LLim_3e2djmCAw_Rm3VzCU"
}
] — and this import capability needs to be integrated into OpenCodeX via the import function. This will allow us to easily manage accounts by simply adding them to the OpenCodeX system, making the process convenient for everyone.- removedneeds-infoWaiting on reporter for a concrete spec or reproductionWaiting on reporter for a concrete spec or reproduction
on Aug 7, 2026 - changed the title
[-][Feature]: Support switching antigravity accounts automatically[/-][+][Feature]: Generic OAuth account-pool failover with session affinity and quota-aware selection[/+]on Aug 7, 2026 Goal
Implement a generic OAuth account-pool failover policy that can be shared by Antigravity and other OAuth-backed providers.
This issue tracks the runtime account-selection and failover policy.
Provider-specific account-management UI, quota presentation, and import formats belong in their respective provider issues.
Accepted routing policy
Hard failover
Switch away from the active account when the upstream returns an error indicating the account is currently unusable:
429— rate limit or quota exhaustion;401— authentication is no longer usable;403— authentication/account access is rejected in a way that makes the account unusable for the request.
The implementation should classify errors carefully rather than treating every provider-side failure as an account-health failure.
Optional proactive selection
When reliable quota information is available, an account at or above 95% detected quota usage may be deprioritized before a hard failure occurs.
This is an optimization, not the correctness guarantee.
If quota information is missing, stale, or not available for a provider, hard-error failover remains the authoritative path.
Session affinity
A conversation should remain on its assigned account while that account remains healthy.
OpenCodex should not rotate accounts between ordinary requests simply for load balancing.
Affinity should be broken only when the assigned account becomes unusable according to the failover policy.
Unknown quota
An account whose quota state is unknown should be treated as:
healthy but unverifiedSuggested ranking:
known healthy > healthy but unverified > depleted / cooling down / erroredUnknown quota must not automatically mean either exhausted or fully healthy.
Cooldown and re-entry
An account that hits a temporary quota/rate limit must not be permanently removed from the pool.
The pool needs a cooldown and re-probe/re-entry path.
Reset-window and proactive reactivation behavior should reuse the lifecycle defined by #822 and #823 rather than introducing a separate third policy.
Scope
This should be implemented in the generic OAuth account-pool layer so provider integrations can reuse a single selection and failover engine.
This issue owns:
- account health classification used for routing;
- session affinity;
- hard failover;
- optional quota-aware selection;
- deterministic ranking when quota information is unknown;
- cooldown/re-entry integration with the shared account lifecycle.
This issue does not own:
- Antigravity-specific quota UI;
- Cockpit Tools import;
- provider-specific account-management screens;
- user-defined account priority ordering beyond consuming that priority as a routing input.
Related issues
- [Feature] Google Antigravity multi-account management, pool health and quota UX #1062 — Google Antigravity account-pool and quota-management UX.
- [Feature]: add per-account Gem/Cla quota display for Google Antigravity #1082 — Antigravity Gemini/Claude quota and reset-time display.
- [Feature] Let users define the priority order for automatic account failover in the Codex pool #821 — user-defined account priority ordering.
- [Feature]: opt-in crash-safe reset-credit auto-redemption before expiry #822 / [Research] Provider-specific post-reset activation to anchor quota windows #823 — quota reset, cooldown, proactive re-probe, and account re-entry lifecycle.
- [Feature]: safely import Cockpit Tools Google Antigravity accounts #1076 — Cockpit Tools account import; separate from failover policy.
Acceptance criteria
- Hard failover works when the active account becomes unusable because of rate limit/quota or authentication failure.
- Ordinary healthy requests preserve session/account affinity.
- Unknown-quota accounts are ranked deterministically and do not incorrectly outrank known-healthy accounts.
- Temporarily limited accounts can re-enter the pool after cooldown/reset.
- Optional quota-aware preemption does not become a dependency for correctness.
- Provider integrations reuse the generic engine rather than implementing divergent failover logic.
- Routing decisions are observable enough to explain why an account was selected, skipped, cooled down, or re-entered.
- Regression coverage includes at least:
- healthy account affinity;
- 429 failover;
- authentication-failure failover;
- unknown-quota ranking;
- cooldown and re-entry;
- no healthy alternative available.
리뷰 · 우선순위 69 / 80
현재
dev에는 Anthropic 옵트인 계정 풀(src/oauth/anthropic-routing.ts)처럼 프로바이더별 스티키 어피니티와 429 페일오버가 있습니다. 이 이슈가 소유한 일반 OAuth 풀 런타임은 그 파일이 아닙니다. 이슈 본문도 기존 구현을 복사해 일반 계약으로 삼지 말라고 합니다. #821 사용자 우선순위는 끝났고, Antigravity UX는 #1062/#1082로 분리됐습니다.이슈가 원하는 것은 재사용 엔진입니다. 세션 어피니티, 라우팅용 건강 분류, 할당 계정이 못 쓰일 때의 페일오버, 신뢰할 수 있는 쿼터 증거로 순위, unknown 쿼터의 결정적 처리, 쿨다운 재진입, 유계 설명입니다. 수락된 하드 페일오버는 429와 사용 불가 401, 그리고 프로바이더가 사용 불가로 분류한 403입니다. 일반 403으로 계정을 독극물 처리하면 안 됩니다.
네이티브 신뢰성과 프로바이더 호환이 점수입니다. 건강한 대화는 계정에 붙고, 로드밸런싱으로 돌면 안 됩니다. unknown 쿼터는 건강하지만 미검증이며 0%나 죽은 계정이 아닙니다. 사전 95% 전환은 선택이며 하드 에러 경로와 같으면 안 됩니다. Windows/서비스에서 인플라이트 요청의 어피니티를 바꾸면 도구 턴이 계정을 갈아탑니다.
위생적으로 Cockpit import(#1076)와 이 런타임을 섞지 마십시오. 가져오기는 자격 증명을 넣고, 이 이슈는 고릅니다. 프로바이더 UI가 선택 이유를 보여 주려면 엔진이 먼저 관측 가능한 결정을 내야 합니다.
해결방안은 Anthropic 풀에서 정책을 일반화하되, 프로바이더 분류 훅만 남기고 계정 선택 코어를 한곳으로 모으는 것입니다. 하드 에러가 어피니티를 깨고, 쿼터 unknown은 후순위입니다. 패치는 추측하지 않으며, 현재 트리를 일반 OAuth 페일오버 완료로 보지 않습니다.
이 댓글은 grok-bot이 작성했습니다
Adding concrete 2.35.0 evidence from a real 4-account Antigravity pool (Windows 10, npm @bitkyc08/opencodex 2.35.0) in support of implementing the accepted policy from this issue.
State today — the pool exists, but every proactive control is Codex/Anthropic-only:
ocx account list google-antigravity --quota— 4 OAuth accounts stored, but no quota probe and no priority data:PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS QUOTA google-antigravity oauth 37ea404f n***r@gmail.com - - google-antigravity oauth de4a3658... m***a@gmail.com - - google-antigravity oauth 207353b7... r***c@gmail.com - active - google-antigravity oauth a367fe95... s***9@gmail.com - -> ocx account auto-switch google-antigravity status Error: auto-switch only applies to the openai Codex account pool > ocx account strategy google-antigravity Error: pool settings apply to the openai Codex pool and the anthropic pool, not "google-antigravity"Reactive 429 failover (
oauthAccountFailover, #2568) does work and is genuinely useful, but it is strictly reactive: the daily-driver account keeps getting hammered until a hard 429, in-flight conversations are disrupted, and only then does rotation kick in. With 4 accounts the pool never spreads load proactively — there is no threshold, no strategy (quota/round-robin/fill-first), no priority tiers, no sticky limit for generic OAuth providers.Also note the pre-emptive leg of the policy accepted in this thread ("optional pre-emptive switch at ≥95% detected quota") is currently unreachable for Antigravity because there is no quota probe at all —
QUOTAis-for every account (tracked separately in #1082). Until that lands, even the accepted policy can only operate on 429/401/403 signals.Happy to test the generic runtime against this 4-account pool once an implementation lands — good natural testbed (different plan types across the accounts).
Reacted by agentHitsConfirmed against current dev 8df7051: your four-account evidence matches the implementation boundary.
- Generic OAuth failover is present in src/oauth/generic-account-failover.ts and rotates eligible accounts reactively after upstream failures.
- supportsPerAccountQuota currently admits only anthropic and kiro, so Google Antigravity has provider-level quota probing but no per-account quota evidence for proactive ranking.
- The CLI auto-switch command is still Codex-only, and the shared strategy/sticky transport supports only Codex plus Anthropic. Google Antigravity is rejected before the management request.
So this is not a configuration mistake and the issue should remain open. The safest implementation order is: first land the per-account Antigravity quota path tracked in #1082; then generalize the pool-settings API and CLI through a provider capability contract; finally let the generic OAuth selector consume that evidence for quota, round-robin, and fill-first behavior. That avoids creating a second Antigravity-only router and keeps unknown quota as unknown rather than treating it as zero capacity.
Your four-account pool is a useful acceptance environment. The eventual regression should prove that proactive selection spreads new sessions without breaking existing affinity, while 401/403/429 recovery still walks the eligible roster and never exposes account identity or quota data across rows.
Slice 1 landed on
devvia #3214 (squash356e495f5), following the order agreed above: per-account Antigravity quota went in with #3213, and this adds the pool-settings capability contract. Any generic OAuth provider (Antigravity, xAI, Cursor, Kimi, Copilot, Nous, …) now acceptsstrategyandautoSwitchThresholdthroughGET/PUT /api/oauth/accounts/pooland theocx account strategy/ocx account auto-switchverbs, persisted onproviders.<name>.oauthAccountFailover. Codex and Anthropic contracts are unchanged.What is deliberately still open here, for the next slice: the generic selector consuming those settings (quota / round-robin / fill-first, threshold-driven proactive switch), session affinity for generic pools, classified 401/403 hard failover, cooldown re-probe, and bounded selection reasons. Until that lands the stored settings are declared but inert, and the API says so (
"inert": true). Keeping the issue open for that runtime slice.Reacted by agentHitsClosing in favor of #3375, which carries the remaining scope forward.
Thank you @luwei1990 — this report on generic OAuth account-pool failover with session affinity and quota-aware selection was accurate, and part of it shipped.
What landed. The first tranche landed:
src/oauth/generic-account-failover.tsimplements 429 cooldown, rotation, and quota-ranked initial selection (816f3a1).What is still missing. reusable session affinity, 401 / provider-classified 403 failover, the full health lifecycle, and decision observability.
Rather than leave four issues open each describing one facet of the same unfinished lifecycle, the surviving scope is consolidated in #3375, which names this issue and credits you for the original analysis. Please follow and comment there; if you think the consolidation dropped something you asked for, say so on #3375 and it will be added.
- added a commit that references this issue
on Sep 14, 2026 - added a commit that references this issue
on Sep 17, 2026
Area
Authentication / OAuth account pools / routing
Goal
Implement one generic OAuth account-pool selection and failover engine that provider integrations can reuse.
This issue owns the runtime policy for:
Provider-specific account-management UI, import formats, and quota probes belong in their respective provider issues.
Current status
The routing policy has been defined and accepted.
The remaining work is implementation of the generic OAuth-pool runtime. Existing provider-specific pool implementations must not become the de facto generic contract by copy/paste.
Antigravity-specific work is now separated cleanly from this generic runtime:
This issue remains open because the generic OAuth failover/affinity engine itself is not complete.
Accepted routing policy
Hard failover
Break affinity when the currently assigned account is positively known to be unusable for the request.
Relevant signals include:
Provider errors must be classified deliberately. An unrelated upstream failure must not incorrectly mark an account unhealthy.
Hard-error failover is the correctness path.
Session affinity
Healthy conversations stay on their assigned account.
Ordinary requests must not rotate across accounts merely for load balancing.
Conceptually:
In-flight requests and concurrent sessions must not corrupt or accidentally overwrite affinity state.
Quota-aware selection
When fresh, account-scoped quota evidence is available, it may improve account selection.
The accepted policy permits deprioritizing an account at or above approximately 95% detected quota usage.
This is an optimization, not a correctness dependency.
A provider with no usable quota probe must still support hard-error failover.
Stale quota must not be treated as current quota.
Unknown quota
Unknown quota remains a first-class state.
Suggested ordering:
Unknown must not mean:
and must not mean:
Account A's quota or failure state must never be projected onto account B.
Cooldown and re-entry
A temporary
429or quota exhaustion must not permanently remove an account from the pool.The generic runtime needs an explicit lifecycle such as:
Re-entry must be bounded and deterministic.
#822 and #823 remain separate reset-lifecycle features. Their background redemption/activation behavior must not be required for generic failover correctness.
No healthy alternative
If the assigned account becomes unusable and no eligible alternative exists:
Priority relationship
#821 implemented user-defined priority ordering for the existing automatic account transition surface.
The generic OAuth-pool engine should be able to consume an explicit priority signal where applicable without making priority configuration mandatory.
Priority is an input to candidate selection, not a replacement for:
Provider integration contract
Provider integrations should supply normalized evidence such as:
The generic pool should own the selection policy.
Do not implement separate Antigravity, Anthropic, Kimi, or other provider-specific copies of the same routing state machine.
Observability and privacy
Operators should be able to determine why an account was:
without exposing:
Use safe opaque account references where attribution is required.
Related issues
Acceptance criteria
429/ recognized quota exhaustion can trigger bounded same-request failover.403responses are not blindly classified as account exhaustion.dev.