Repository navigation
fix(usage): read Antigravity quota from Agy, not the Gemini mirror - #16710
brennanb2025 wants to merge 10 commits into
Conversation
The Antigravity rate-limit entry was `{ ...gemini, provider: 'antigravity' }`,
so the segment reported Gemini Code Assist per-model quota under an Antigravity
label, and its refresh inherited Gemini CLI's credential plumbing — leaving
Antigravity-only users with a permanently failing segment.
Antigravity now answers for itself. Every `agy` run records its own pid and both
loopback ports in the first lines of its CLI log, so Orca discovers the newest
live language server from `~/.gemini/antigravity-cli/log`, asks it for
`RetrieveUserQuotaSummary`, and publishes the four native buckets (Gemini and
Claude/GPT, five-hour and weekly) with their independent resets.
- Newest run first: a long-lived `agy` keeps the account it started with across
a sign-out, so an older process answers with a stale account's quota.
- Plaintext loopback port first, so the common path needs no TLS exception.
- "No `agy` running", "signed out", and "unreadable" are now distinct outcomes;
only the actionable ones render a segment.
- Antigravity visibility no longer requires the Gemini CLI OAuth opt-in.
Fixes #9122
A signed-out answer from the newest `agy` used to fall through to an older process, which still holds the account it started with — so Orca could render a stale account's quota with nothing to indicate it. The newest live run now settles the question; older servers are only consulted when the newest could not be reached at all, which teaches nothing about the account.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughAdds native Antigravity quota discovery from local language-server logs. Adds quota parsing and HTTP or HTTPS fetching with timeout, response-size, abort, authentication, server, network, and parse handling. Runs Antigravity fetching independently in 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The changes satisfy issue Full details: Out of Scope Changes checkExplanation The changes remain aligned with the linked issue. Discovery, transport, WSL cancellation, visibility updates, native bucket rendering, mocks, and mirror removal support the independent Antigravity usage flow and its required runtime behavior. Full details: Description checkExplanation The description is complete and closely follows the repository template. It explains the change and rationale, links issue
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a48557cf-5318-4961-b841-3183324a90fe
📒 Files selected for processing (20)
src/main/rate-limits/antigravity-language-server-log.test.tssrc/main/rate-limits/antigravity-language-server-log.tssrc/main/rate-limits/antigravity-quota-summary.test.tssrc/main/rate-limits/antigravity-quota-summary.tssrc/main/rate-limits/antigravity-usage-fetcher.test.tssrc/main/rate-limits/antigravity-usage-fetcher.tssrc/main/rate-limits/antigravity-usage-mirror.test.tssrc/main/rate-limits/antigravity-usage-mirror.tssrc/main/rate-limits/rate-limit-service-test-harness.tssrc/main/rate-limits/service-account-target-selection.test.tssrc/main/rate-limits/service-antigravity-usage.test.tssrc/main/rate-limits/service-inactive-account-previews.test.tssrc/main/rate-limits/service-live-claude-usage.test.tssrc/main/rate-limits/service-minimax-usage.test.tssrc/main/rate-limits/service-refresh-orchestration.test.tssrc/main/rate-limits/service-window-activation.test.tssrc/main/rate-limits/service.tssrc/renderer/src/components/status-bar/StatusBar.tsxsrc/renderer/src/components/status-bar/status-bar-provider-visibility.test.tssrc/renderer/src/components/status-bar/status-bar-provider-visibility.ts
💤 Files with no reviewable changes (3)
- src/main/rate-limits/antigravity-usage-mirror.test.ts
- src/renderer/src/components/status-bar/StatusBar.tsx
- src/main/rate-limits/antigravity-usage-mirror.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 76d14c2f-dbde-4f47-98d9-673d5e0263f8
📒 Files selected for processing (2)
src/main/rate-limits/antigravity-usage-fetcher.test.tssrc/main/rate-limits/antigravity-usage-fetcher.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.
A newer Agy server response now settles quota lookup instead of falling through to an older account, and loopback abort listeners are released after settlement. The usage roster no longer duplicates the derived weekly summary or routes Antigravity sign-in to Gemini settings.
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f3554945-d85e-4675-866f-1860ccd2f62e
📒 Files selected for processing (8)
src/main/rate-limits/antigravity-usage-fetcher.test.tssrc/main/rate-limits/antigravity-usage-fetcher.tssrc/renderer/src/components/status-bar/UsageRosterPanel.tsxsrc/renderer/src/components/status-bar/tooltip.test.tssrc/renderer/src/components/status-bar/tooltip.tsxsrc/renderer/src/components/status-bar/usage-provider-settings-target.test.tssrc/renderer/src/components/status-bar/usage-provider-settings-target.tssrc/shared/rate-limit-types.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.
|
Final exact-head review — Resolved the three current review findings with focused production fixes and regression coverage:
All eight PR review threads are resolved. A fresh independent Verification passed:
CI run 33065989210 tested merge ref Verdict: the focused review fixes are clean, but the PR is |
|
QA/evidence for exact head No renderer/UI surface changed in the six-file review fix, so visual proof of those lifecycle and process-identity changes is not applicable. Regression coverage proves runtime-policy refresh and snapshot clearing, stale/ABA fetch rejection, and WSL PID identity/start-time validation; the full 491-test rate-limit suite, typecheck, lint, format, and diff checks pass. Live signed-in Antigravity/provider QA is blocked. Antigravity CLI Contributor provenance was rechecked: contributor commit Exact-head CI run 33065989210 remains red only on deterministic base/merge-ref runtime export parity failures in Node 24 and Node 26 shard 10/16 plus aggregate |
|
I tested this against a live Minimal follow-up commit, based exactly on this PR's current head It adds Verification:
Cherry-pick:
|
|
Thanks @taehyunkim3 — confirmed this is based on exact head |
|
Verdict for head |
Final review verification —
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/main/rate-limits/antigravity-usage-fetcher.test.ts (1)
74-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the
as nevercast. The object already matchesAntigravityUsageFetchOptions(targetpluslogSource), and the sibling test at Line 103 calls the same function without a cast. The cast hides future changes to thetargetshape from type checking.♻️ Proposed change
const limits = await fetchAntigravityRateLimits({ target: { runtime: 'wsl', wslDistro: 'Ubuntu' }, logSource: runningServers({}) - } as never) + })
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a0373b29-7264-4c1d-b8ac-c2bfd6f5d86c
📒 Files selected for processing (17)
src/main/git/wsl-process-group-termination.test.tssrc/main/git/wsl-process-group-termination.tssrc/main/index.tssrc/main/rate-limits/account-runtime-target-sync.test.tssrc/main/rate-limits/account-runtime-target-sync.tssrc/main/rate-limits/antigravity-quota-summary.test.tssrc/main/rate-limits/antigravity-quota-summary.tssrc/main/rate-limits/antigravity-usage-fetcher.test.tssrc/main/rate-limits/antigravity-usage-fetcher.tssrc/main/rate-limits/antigravity-wsl-usage-probe.test.tssrc/main/rate-limits/antigravity-wsl-usage-probe.tssrc/main/rate-limits/service-antigravity-usage.test.tssrc/main/rate-limits/service.tssrc/main/wsl/wsl-guest-environment.test.tssrc/main/wsl/wsl-guest-environment.tssrc/main/wsl/wsl-runner.test.tssrc/main/wsl/wsl-runner.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 2 remain after this review.
Exact-head review verificationReviewed live PR head Local verification passed: 54 focused files / 629 tests, Merge verdict: do not merge yet; refresh the branch from current |
QA / evidenceValidated exact head Authenticated four-bucket happy-path QA is truthfully blocked on this host: |
QA / evidence — exact head
|
|
I found one small UI gap while checking exact head I prepared a focused follow-up commit based directly on that head:
Cherry-pick: |
|
Windows evidence for the language-server route, since none of the Agy-quota PRs has been exercised there yet. Environment: Windows 11, Orca 1.4.198,
Happy to run any of these again against a branch if useful. |
|
@brennanb2025, following up on @Tauri-EPO's Windows evidence: #19209 implements the credential-backed Cloud Code path that avoids depending on the Language Server's authentication state. It was validated end to end with a refreshed Antigravity token on an Ampere KR host, including the caller-identity requirement and all four native quota windows. It also discovers the credential through Orca's existing filesystem routing on connected SSH hosts, which complements this PR's local/WSL Language Server path. I do not think #19209 should replace the Language Server happy path. Its narrow credential discovery and API request code could serve as a fallback when the server reports signed out for a working Agy session, or when Agy runs on an SSH execution host. Follow-up validation found two points to tighten before reuse: do not attach |
|
Independent review (2026-09-20): The current installed agy 1.2.7 does answer a harmless Verdict: do not merge this PR as-is; superseded by #21654 → #21678. No code changes made here. |


ELI5
Orca already treats Gemini and Antigravity as different usage meters, but before this PR it filled both meters from Gemini. Agy is the Antigravity CLI; after this PR, the Antigravity meter asks Agy for Antigravity’s own quota while the Gemini meter keeps asking Gemini for Gemini quota.
This is like fixing which utility meter Orca reads. It is not adding another account form to Settings.
Settings and account ownership
Is Agy now a separate provider account in Settings? No. This PR does not add an Agy or Antigravity entry under Settings → AI Provider Accounts. The Settings account surface is unchanged.
The
~/.gemini/antigravity-cli/logpath is Agy’s own language-server log location; that directory name does not mean Orca is using the Gemini provider account.User-facing before / after
agy; Orca distinguishes “Agy not running,” “Agy signed out,” and “quota unreadable,” without routing to Gemini Settings.What Changed
fetchAntigravityRateLimitsreads quota from the host-local Agy LanguageServer instead of copying the Gemini snapshot.~/.gemini/antigravity-cli/log/cli-*.log. Everyagyrun writes its own pid and both loopback ports in the first lines of that log, so nolsof,ps, process table, or command-line inspection is needed on any platform.agykeeps the account it started with in memory across a sign-out, so an older process will confidently answer with a stale account's quota. Log names sort chronologically; dead pids are filtered withprocess.kill(pid, 0). When the newest live server answers at all — with quota or with "signed out" — that is the answer; older servers are consulted only when the newest could not be reached, which teaches nothing about the account.agylistens on two adjacent ports — one HTTPS (self-signed), one plain HTTP — and both serve the RPC. Trying HTTP first means the common path needs no TLS exception at all; the self-signed fallback is pinned to127.0.0.1.agyrunning", "signed out", and "unreadable response" are now three distinct outcomes instead of one Gemini-flavouredToken refresh failed.geminiCliOAuthEnabled. It is gated on the checked status item (which itself requiresagyon PATH), and hides when discovery reports no running language server —agyis a per-session CLI, not a daemon, so "installed but idle" must not pin a dead warning bar.antigravity-usage-mirror.tsand its tests are deleted.Gemini CLI usage is left completely intact. Removing it is a separable migration across persisted settings, telemetry, localization, and mobile/web projections, and Gemini CLI remains documented for Workspace/Enterprise, API-key, and Vertex users.
Why
In
service.tsthe Antigravity entry was literally{ ...gemini, provider: 'antigravity' }. That produced two independent failures:fetchGeminiRateLimitscallscloudcode-pa.googleapis.com/v1internal:retrieveUserQuotawithideType: "GEMINI_CLI", so the segment rendered Gemini Code Assist per-model buckets under an Antigravity label. A user checking whether they were near their Antigravity weekly limit got a number unrelated to it.@google/gemini-clipackage. Antigravity users have no reason to have one, so the segment showed a refresh failure indefinitely.Fixing only (2) makes things worse, not better: a visible warning becomes confident numbers from the wrong product. The data source itself had to change.
The LanguageServer is the right authority: it is the process that holds the live account, it needs no credentials from Orca, and it answers with exactly the bucket identities the issue describes.
Linked Issue
Fixes #9122
Supersedes the Agy-quota direction explored in #11536, #14571, #15948, #16653 and #12095. Differences from those, briefly:
agy's own startup log lines; nolsof/ps/process table, no CSRF token, no command-line inspectionagy -p /usage(the shell-out route taken by #15948 and #16653) was evaluated and not used: on the currentagy1.1.21 the literal output labels those PRs parse (Five Hour Limit Remaining,Weekly Limit Remaining,Gemini Models,Claude and GPT models) do not appear anywhere in the binary, print mode explicitly refuses some slash commands (/%s is not available in print mode), and a full CLI turn costs seconds per poll. The LanguageServer RPC is present in the binary 110 times and answered live here.Visual Proof
N/Afor a before/after of populated bars — this machine has no signed-in Antigravity account, so the happy-path segment cannot be rendered locally. No layout or interaction component changed: the existing named-bucket renderer intooltip.tsx/UsageRosterPanel.tsxalready rendersbucketsgenerically, and this change only populatesProviderRateLimitsdifferently.Testing
Verified live against a real
agy1.1.21 on macOS arm64:agyrunning, the log walk returned exactly{pid: 14672, HTTPS: 55703, HTTP: 55704}— the spawned pid, both ports — andlsof -nP -p <pid> -iTCP -sTCP:LISTENindependently confirmed the same two ports.POST /exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummarywithconnect-protocol-version: 1and body{}to the discovered plaintext port returned the real signed-out payload, which the fetcher maps tounavailable/missing-credentials. The same request over the TLS port returns the same payload.QuotaSummaryGroup/QuotaSummaryBucketproto descriptors embedded in theagy1.1.21 binary (bucket_id,display_name,window,remaining_fraction,disabled,reset_time), not from guesswork. The signed-in 200 payload is the one leg that could not be exercised live here, for lack of an Antigravity account.Automated:
pnpm test src/main/rate-limits/ src/renderer/src/components/status-bar/— 91 files, 767 tests passed.pnpm test src/main/rate-limits/ src/renderer/src/components/settings/ src/renderer/src/hooks/useIpcEvents-rate-limit-hydration.test.ts src/shared/— 772 files, 7,572 tests passed, 66 skipped by existing conditions.pnpm tc— clean.oxlint --type-awareon every changed file — clean. Pre-commitoxlint, React Doctor, andoxfmtgates passed.New coverage: log-banner parsing against a verbatim real log head (including that
for HTTPS (gRPC)must not be read as the HTTP port), newest-first ordering, dead-pid filtering, log rotation, all four buckets with independent resets, disabled-bucket handling, most-constrained summarisation, plaintext-before-TLS ordering, TLS fallback, the three distinct failure outcomes, and that a signed-out newest server is never overridden by an older one's stale quota.Rewrote
service-antigravity-usage.test.tsaround the real contract: the mirror-era assertions ("keeps mirroring a successful Gemini read") were the bug, so they are replaced with tests that fail on the pre-fix code — Antigravity must report its own number while Gemini reports 42, and must stay healthy while the Gemini fetch is erroring.I manually tested these changes locally
Automated tests added/updated, or explained why not below
Platforms exercised: macOS arm64. Linux/Windows are code-reviewed only — discovery uses
node:fsandnode:pathwith no platform-specific commands, so there is nolsof/ps/PowerShell path to diverge.Review
127.0.0.1and one constant RPC path; the self-signed exception can only ever apply to loopback and is not used at all when the plaintext port is reachable. Responses are capped at 1 MiB, requests at 2.5s. No credential, keychain, or token is read, written, or refreshed. Log reads are bounded to an 8 KiB head over at most 12 candidate files.lsof,ps,where, or PowerShell. Paths are built withpath.joinonos.homedir().agyrunning only inside an SSH or WSL runtime is not reached; that reports as "not running" rather than as an error, and is called out as follow-up rather than silently mis-attributed.bucketsandusageMetadataare existing optional fields onProviderRateLimits.Agent skill upstream boundary
Notes
Follow-ups deliberately left out of scope: reaching an
agythat runs only inside an SSH/WSL runtime, reading the Antigravity desktop app's language server in addition to the CLI's, and the separable question of retiring the Gemini CLI usage provider.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)Author