Skip to content

Add Antigravity quota support#7

Merged
bernardopg merged 5 commits into
bernardopg:mainfrom
arqueon:feat/antigravity-quota
Jun 28, 2026
Merged

Add Antigravity quota support#7
bernardopg merged 5 commits into
bernardopg:mainfrom
arqueon:feat/antigravity-quota

Conversation

@arqueon

@arqueon arqueon commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

This PR adds a dedicated antigravity provider to surface real per-model quota data from the local Antigravity session.

What changed:

  • Adds providers/get-antigravity-usage and wires it into the provider dispatcher and health checks.
  • Reads the Antigravity OAuth session from the Linux Secret Service keyring first, with fallback to the older IDE SQLite state.
  • Calls the internal read-only v1internal:fetchAvailableModels endpoint and maps its quota windows into the shared primary / secondary / tertiary contract.
  • Exposes Claude, Gemini 3 Pro, and Gemini 3 Flash quota windows with usedPercent, resetsAt, and human-readable labels.
  • Updates the widget so Antigravity shows the reset countdown in the subtitle.
  • Adds CI coverage with fixtures for valid responses, 401, 429, missing session, and schema drift.
  • Updates docs and provider lists to include Antigravity.

Notes:

  • The integration is intentionally narrow: no changes to the existing provider model beyond the new Antigravity path.
  • The endpoint is internal and read-only; schema changes are treated as structured errors.

@bernardopg bernardopg self-assigned this Jun 28, 2026
@bernardopg bernardopg self-requested a review June 28, 2026 21:38
bernardopg

This comment was marked as resolved.

@bernardopg bernardopg dismissed their stale review June 28, 2026 22:07

Replacing with the same review text using safer Markdown formatting.

@bernardopg bernardopg left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution, @arqueon. I appreciate the amount of work here: the provider is wired through settings, the dispatcher, health checks, docs, and CI fixtures, and the intent to keep provider failures isolated matches the project architecture.

I cannot approve this as implemented yet, though. After reviewing the current Antigravity documentation and the diff, this does not appear to provide working, supportable Antigravity quota support yet.

Blocking issues:

  1. The live request does not actually send the recovered token.

In providers/get-provider-usage, the curl config builds an Authorization header with a redacted placeholder, but the format string does not interpolate $token. Because there is no %s placeholder, the recovered token is ignored and curl sends the placeholder value instead. That means the real live path should fail authentication, while the fixture tests still pass because they bypass curl entirely.

  1. The PR relies on an undocumented/private Antigravity endpoint as if it were a provider contract.

The current public Antigravity docs expose quota/credit information through the CLI statusline and /credits panel, and the Plans page says baseline usage can be viewed in-product/settings. I did not find documentation for a non-interactive v1internal:fetchAvailableModels quota API, nor for the response schema used by the fixtures. For this project, the coverage model is intentionally honest: when no stable read-only API exists, the provider should be informational rather than reporting fabricated or reverse-engineered quota windows.

  1. The credential discovery path is speculative and not sufficiently verifiable.

The Secret Service lookups use guessed service names/attributes (service gemini username antigravity, Antigravity CLI, antigravity-cli, etc.), and the SQLite fallback reads a VS Code-style state database key (antigravityAuthStatus) that is not documented by Antigravity. Even if this works on one local installation, it is brittle and may break silently across Antigravity releases or platforms.

  1. CI only validates fixtures, not the real integration.

The added tests prove the jq mapping for a synthetic response, but they do not catch the broken Authorization header or validate that Antigravity actually stores credentials at the queried keyring/state locations. So the green CI does not establish that this works on a real machine.

  1. The model/window mapping is not grounded in current public docs.

The docs currently mention Gemini 3.1 Pro and Gemini 3.5 Flash in the baseline quota section. The PR hardcodes buckets for Gemini 3 Pro, Gemini 3 Flash, and Claude, plus fixture model IDs like gemini-3-pro-high; these are not documented as a stable quota schema. If Antigravity changes model names, this could display misleading windows.

Recommended path:

  • Change Antigravity to an honest informational provider for now: detect agy / Antigravity local presence, link to the documented /credits/Plans pages, and clearly state that quota is visible in-product.
  • Do not read private keyrings/state DBs or call undocumented internal endpoints unless there is an official, documented, non-interactive API contract we can cite.
  • If a real API becomes documented later, add it behind a small adapter with live-path validation, schema-drift tests, and docs pointing to the official source.

Thanks again for the contribution. The wiring structure is close, but the current implementation overclaims real quota support and the live path appears broken, so I’m requesting changes rather than merging it as-is.

@bernardopg

Copy link
Copy Markdown
Owner

Update after validating the endpoint locally: I was wrong to treat v1internal:fetchAvailableModels as an undocumented private surface. It is the real production endpoint that both Antigravity IDE and the official gemini-cli use (cloudcode-pa.googleapis.com), and the credential discovery path (secret-tool on Linux for the agy CLI, and the antigravityAuthStatus entry in the IDE state.vscdb for the desktop build) is correct and matches what I can observe on a real Antigravity install.

I confirmed this end-to-end on a live Antigravity IDE session here:

  • POST https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssistHTTP 200, returns the Cloud Companion project id and the current tier.
  • POST https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModelsHTTP 200, returns a models map where each entry has quotaInfo.remainingFraction and quotaInfo.resetTime, exactly as the adapter expects.
  • The same call against daily-cloudcode-pa.googleapis.com also returns 200, so both hosts work.
  • The apiKey field in antigravityAuthStatus (IDE state.vscdb) is a valid ya29.* OAuth bearer for these endpoints.

So this PR is viable as a real quota provider, not just an informational one. Thank you for pushing on this. My earlier CHANGES_REQUESTED was based on an incorrect assumption about the endpoint's legitimacy; I'll clear it once the items below are addressed.

Remaining items (none of them change the core approach, which is sound):

  1. Authorization header is not actually sent

This is the only real bug. The curl config line omits the format specifier:

--config <(printf 'header = "Authorization: Bearer ***"\n' "$token")

There is no %s, so $token is discarded and curl sends the literal placeholder. In my live test the token is required (without it the endpoint returns 401), so the current live path can never succeed even though the fixture tests pass. Suggested fix, keeping the no-arg/no-file invariant:

--config <(printf 'header = "Authorization: Bearer %s"\n' "$token")

or pass it as -H "Authorization: Bearer $token" if you prefer. Either is fine as long as the token actually reaches the server.

  1. Model grouping does not match the current catalog

fetchAvailableModels on a current session returns model ids like claude-opus-4-6-thinking, claude-sonnet-4-6, gemini-3.1-pro-high, gemini-3.5-flash-low, gemini-3.5-flash-extra-low, gpt-oss-120b-medium. The PR's family() buckets (Claude, Gemini 3 Pro, Gemini 3 Flash) collapse all of Claude and all of Gemini into two generic windows, which loses information and produces labels that no longer match what users see in the Antigravity UI (e.g. "Claude Opus 4.6 (Thinking)", "Gemini 3.1 Pro (High)").

Could you widen the buckets to the current model families, e.g. Claude Opus 4.6 / Claude Sonnet 4.6 / Gemini 3.1 Pro / Gemini 3.5 Flash / GPT-OSS 120B? The displayName field from the response is a reliable source for the labels.

  1. Default endpoint host

Both hosts work today, but cloudcode-pa.googleapis.com is the stable production host used by gemini-cli and is what I'd recommend as the default (ANTIGRAVITY_API_BASE_URL), keeping daily-cloudcode-pa.googleapis.com only as an opt-in override.

  1. Optional: include the X-Goog-Api-Client header

The official clients send X-Goog-Api-Client: google-cloud-sdk vscode_cloudshelleditor/0.1. It is not strictly required (my calls succeeded without it), but including it reduces the chance of being routed to a different backend.

Optional nicety, not blocking: the loadCodeAssist project id could be resolved automatically instead of reading default_project_id.txt, but the current cached-file approach is fine if agy reliably writes it.

Once item 1 is fixed, the live path works — I verified the exact request shape. Items 2-4 are about correctness of labels and long-term stability. Happy to help land this if useful.

…e host

- Authorization header was not interpolating $token (printf had no %s),
  so the live endpoint always failed auth while fixture tests passed.
  Now interpolates correctly via the pipe-backed curl config.
- Update model family buckets to current catalog: Claude Opus 4.6,
  Claude Sonnet 4.6, Gemini 3.5 Flash, Gemini 3.1 Pro, GPT-OSS 120B.
- Switch default endpoint to cloudcode-pa.googleapis.com (production host
  used by gemini-cli) instead of the daily preview host.
- Add X-Goog-Api-Client header to match official clients.
- Update fixture and CI assertions to the new model families.

Validated end-to-end against the real endpoint with a live IDE session.

@bernardopg bernardopg left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All checks green on the latest commit. Thank you again for the contribution, @arqueon.

To summarize what I validated and adjusted before approving:

  1. I confirmed v1internal:fetchAvailableModels against a live Antigravity IDE session on my machine. Both loadCodeAssist and fetchAvailableModels return HTTP 200 with real quotaInfo.remainingFraction / resetTime per model. The credential path (secret-tool for agy, antigravityAuthStatus.apiKey in state.vscdb for the IDE) is correct and matches what I observe locally. This is a real quota provider.

  2. Fixed the Authorization header bug that was blocking the live path: the printf format string was missing %s, so $token was dropped and the bearer header never reached the server. The fixture tests passed because they bypass curl, which is why CI stayed green while the real request would have 401'd. Now the token is interpolated correctly.

  3. Updated the model family buckets to the current catalog: Claude Opus 4.6, Claude Sonnet 4.6, Gemini 3.5 Flash, Gemini 3.1 Pro, GPT-OSS 120B. The previous Claude / Gemini 3 Pro / Gemini 3 Flash grouping no longer matched what the endpoint returns.

  4. Switched the default endpoint to cloudcode-pa.googleapis.com (the stable production host used by gemini-cli) instead of the daily preview host, and added the X-Goog-Api-Client header to match official clients.

  5. Updated the fixture and CI assertions to the new model families and percentages.

End-to-end test with a live session:

  • providers/get-provider-usage "antigravity" "" → returns real quota windows for Claude Opus 4.6, Claude Sonnet 4.6, GPT-OSS 120B with correct reset times.

Approving. The coverage model is honored: this surfaces real usedPercent + resetsAt from an actual provider protocol, which is the Quota level.

- architecture.md: document stable cloudcode-pa host and current model
  families (Opus/Sonnet 4.6, 3.5 Flash, 3.1 Pro, GPT-OSS) instead of
  stale 'Claude / Gemini 3 Pro / Flash' buckets.
- providers.md: endpoint is the documented Cloud Code Assist surface,
  not 'undocumented'; coverage is 'Quota (Cloud Code Assist)'.
- README.md / README.pt-BR.md: integration line now references the
  Cloud Code Assist endpoint used by Antigravity IDE and gemini-cli.
- CHANGELOG: add 1.5.0 entry covering the Antigravity provider, the
  auth-header fix, dual credential discovery, and the sqlite3 note.
- plugin.json: 1.4.12 -> 1.5.0 (new provider, minor bump).
@bernardopg bernardopg merged commit 293725e into bernardopg:main Jun 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants