Add Antigravity quota support#7
Conversation
Replacing with the same review text using safer Markdown formatting.
bernardopg
left a comment
There was a problem hiding this comment.
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:
- 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.
- 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.
- 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.
- 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.
- 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.
|
Update after validating the endpoint locally: I was wrong to treat I confirmed this end-to-end on a live Antigravity IDE session here:
So this PR is viable as a real quota provider, not just an informational one. Thank you for pushing on this. My earlier Remaining items (none of them change the core approach, which is sound):
This is the only real bug. The curl config line omits the format specifier: --config <(printf 'header = "Authorization: Bearer ***"\n' "$token")There is no --config <(printf 'header = "Authorization: Bearer %s"\n' "$token")or pass it as
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
Both hosts work today, but
The official clients send Optional nicety, not blocking: the 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
left a comment
There was a problem hiding this comment.
All checks green on the latest commit. Thank you again for the contribution, @arqueon.
To summarize what I validated and adjusted before approving:
-
I confirmed
v1internal:fetchAvailableModelsagainst a live Antigravity IDE session on my machine. BothloadCodeAssistandfetchAvailableModelsreturnHTTP 200with realquotaInfo.remainingFraction/resetTimeper model. The credential path (secret-toolforagy,antigravityAuthStatus.apiKeyinstate.vscdbfor the IDE) is correct and matches what I observe locally. This is a real quota provider. -
Fixed the Authorization header bug that was blocking the live path: the
printfformat string was missing%s, so$tokenwas 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. -
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 Flashgrouping no longer matched what the endpoint returns. -
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 theX-Goog-Api-Clientheader to match official clients. -
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).
This PR adds a dedicated
antigravityprovider to surface real per-model quota data from the local Antigravity session.What changed:
providers/get-antigravity-usageand wires it into the provider dispatcher and health checks.v1internal:fetchAvailableModelsendpoint and maps its quota windows into the sharedprimary/secondary/tertiarycontract.usedPercent,resetsAt, and human-readable labels.Notes: