feat(quota): per-account Gem/Cla quota for Google Antigravity (#1082) - #3213
Conversation
supportsPerAccountQuota now includes google-antigravity. Each stored account is probed with its own bearer (same refresh hygiene as Anthropic) and its own Cloud Code Assist project id, and the existing Gem/Cla classification is shared with the provider-level probe. The per-account probe always targets Google's Cloud Code Assist host over the pinned provider-outbound transport, so a configured baseUrl cannot redirect stored bearers and the provider+account cache identity stays exact across config changes; redirects, blocked destinations, and a missing project id yield unavailable, never 0%. No UI change: the account list already projects customWindows. Supersedes PR #2123 (design credit: account loop and token hygiene).
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
✅ Deterministic PR hygiene checks passed. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Team Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughGoogle Antigravity now supports per-account Gem and Cla quota probing. Each account uses its own access token and project ID through the pinned Google transport. Missing projects, redirects, and probe failures produce unavailable results. Documentation and focused tests cover the behavior. ChangesGoogle Antigravity per-account quota
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant AccountQuota
participant fetchAntigravityUsageQuota
participant providerOutboundPost
participant GoogleCloudCodeAssist
AccountQuota->>fetchAntigravityUsageQuota: accessToken and projectId
fetchAntigravityUsageQuota->>providerOutboundPost: POST fixed Google endpoint
providerOutboundPost->>GoogleCloudCodeAssist: pinned request with bearer and project
GoogleCloudCodeAssist-->>providerOutboundPost: quota response or redirect
providerOutboundPost-->>fetchAntigravityUsageQuota: response
fetchAntigravityUsageQuota-->>AccountQuota: Gem and Cla quota or unavailable
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd55b6f841
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (!response.ok) return null; | ||
| const customWindows = antigravityWindowsFromModels(asRecord(await readQuotaJson(response))); | ||
| if (customWindows.length === 0) return null; | ||
| return { customWindows, updatedAt: Date.now() }; |
There was a problem hiding this comment.
Rank Antigravity accounts by the requested family
After a dashboard or --quota probe populates this cache for a multi-account Antigravity provider, generic OAuth pre-dispatch ranking in src/oauth/account-quota-rank.ts computes headroom from the maximum of every customWindows percentage without knowing the requested model. Because Gem and Cla are mutually exclusive model-family limits rather than concurrent account-wide limits, an account with exhausted Gemini quota but ample Claude quota is incorrectly deprioritized for Claude requests, potentially selecting an account whose Claude allowance is exhausted and causing avoidable 429s; make the ranking select the window for the requested Antigravity model family, or keep these family-specific rows out of generic account-wide ranking.
Useful? React with 👍 / 👎.
| // Per-account Gem/Cla windows (#1082). The project id is part of the stored | ||
| // credential; without it the probe cannot be made, and that is "unavailable", | ||
| // never 0%. | ||
| const projectId = getAccountCredential(provider, accountId)?.projectId; |
There was a problem hiding this comment.
Keep the token and project ID in one credential snapshot
If the same Antigravity account is refreshed, reauthenticated, or re-imported after getTokenForAccountQuotaProbe resolves but before this second store read, the request can pair one credential generation's bearer with another generation's projectId. Google may reject the probe, or a token authorized for both projects may cache the wrong quota under this account for the TTL; return the bearer and project ID together from a full account-scoped snapshot while preserving the existing background-local-cli refresh guard. This token/credential pairing path is a repository-defined security boundary.
AGENTS.md reference: src/AGENTS.md:L20-L20
Useful? React with 👍 / 👎.
|
|
||
| Google Antigravity rows carry the same `Gem` / `Cla` windows as the provider-level quota, computed | ||
| from that account's own credential and Cloud Code Assist project id. The per-account probe always | ||
| talks to Google's Cloud Code Assist host through the pinned outbound transport, regardless of a |
There was a problem hiding this comment.
Qualify the transport pinning claim in proxy mode
When HTTP_PROXY/HTTPS_PROXY is configured and this public host does not match NO_PROXY, providerOutboundRequest deliberately sends the request through globalThis.fetch (src/lib/provider-outbound.ts:170-172) and warns that the final route and peer cannot be pinned locally. Therefore this unconditional user-facing statement is false in a supported environment; document that direct connections are resolved and pinned while proxy-mode connections preserve the configured proxy routing and its weaker peer guarantee.
AGENTS.md reference: docs-site/AGENTS.md:L7-L10
Useful? React with 👍 / 👎.
Summary
Gem/Claquota rows for Google Antigravity ([Feature]: add per-account Gem/Cla quota display for Google Antigravity #1082).supportsPerAccountQuotanow includesgoogle-antigravity; each stored account is probed with its own bearer (same refresh hygiene as the Anthropic probe: fresh stored access is used as-is, backgroundlocal-clislots never trigger a CLI-adopting refresh) and its own Cloud Code Assist project id. ThefetchAvailableModels→Gem/Claclassification is extracted into one function shared by the provider-level and per-account probes, so the semantics are identical.https://daily-cloudcode-pa.googleapis.com), not the configurablebaseUrl. A custom base URL is a routing choice for requests, not a second source of Google's accounting for a stored credential, so the existingprovider\0accountIdcache/in-flight identity and generation reconciliation stay exact across config changes.providerOutboundPost(resolved/pinned transport, manual redirect handling); a blocked or redirecting destination yieldsunavailableand no token is sent.unavailable(last-good preserved), never 0%. The provider-level probe is unchanged./api/oauth/accounts?quota=1andocx account list --quotaalready projectcustomWindowsper account. Docs updated inreference/cli/providers-accounts.md.Closes #1082
Verification
bun x tsc --noEmitclean;bun run privacy:scanpassed.bun test tests/provider-account-quota.test.ts tests/provider-quota.test.ts tests/oauth-store-multi.test.ts tests/core-lab-boundary.test.ts→ 166 pass / 0 fail. New: two accounts probed with distinct bearer + project id on the fixed host via the injected pinned transport (plainfetchthrows if touched), distinct Gem/Cla percentages and reset times per row; a rejected destination sends no bearer and yieldsunavailable; a redirecting upstream yieldsunavailableand an account without a project id makes no request.Checklist
Summary by CodeRabbit