Skip to content

feat: Add AntiGravity SDK support & Gemini API key routing, introduce dynamic model discovery#576

Open
chrisgeo wants to merge 34 commits into
NoeFabris:mainfrom
chrisgeo:agy-sdk-support
Open

feat: Add AntiGravity SDK support & Gemini API key routing, introduce dynamic model discovery#576
chrisgeo wants to merge 34 commits into
NoeFabris:mainfrom
chrisgeo:agy-sdk-support

Conversation

@chrisgeo
Copy link
Copy Markdown

@chrisgeo chrisgeo commented May 23, 2026

Summary

  • add Gemini API-key routing with key pooling, fallback behavior, and model ID normalization
  • add runtime model discovery from Gemini and Antigravity model APIs with static definitions as fallback
  • normalize discovered models for OpenCode provider hooks and harden API-key redaction in request/debug paths

Verification

  • npm run typecheck
  • npm test
  • npm run build

Closes #573 #572 #571 #549

chrisgeo and others added 14 commits May 20, 2026 18:28
…names

Add gemini-3.5-flash, gemini-3.5-pro, and gemini-3.1-flash across both quota
pools, and align the Gemini CLI model-name convention with the antigravity
(agy) and gemini CLIs: the 3.1+ generation uses bare names, not the legacy
-preview suffix used by the 3.0 line.

Registry (src/plugin/config/models.ts):
- Antigravity: antigravity-gemini-3.1-flash, antigravity-gemini-3.5-flash,
  antigravity-gemini-3.5-pro
- Gemini CLI (bare): gemini-3.1-flash, gemini-3.5-flash, gemini-3.5-pro, and
  gemini-3.1-pro (renamed from gemini-3.1-pro-preview)
- Pro variants low/high; Flash variants minimal/low/medium/high
- Kept gemini-3.1-pro-preview-customtools as a legacy entry

Resolver (src/plugin/transform/model-resolver.ts):
- resolveModelForHeaderStyle appends -preview only for the legacy 3.0 line;
  dotted-minor generations (gemini-3.1+) use bare names. Previously configured
  -preview model strings still route correctly via the resolver.

Updated tests (models, model-resolver, request), README tables + copy-paste
config, and CHANGELOG. Full suite 1014 passing; typecheck clean.
Fix default Gemini 3 thinkingLevel injection
Remove Gemini 3.1 Flash and Gemini 3.5 Pro models
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Antigravity SDK (AGY) API-key credential discovery and fetch helpers, Gemini 3.5 Flash model definitions and thinking-level mapping, model discovery factories and merging into provider definitions, request preparation and AGY fetch paths with rate-limit tracking and fallbacks, resolver updates for antigravity/gemini-cli/agy-sdk header styles, schema and DEFAULT_CONFIG extensions, debug header/URL redaction helpers, quota helper exports, many unit tests, and README/CHANGELOG documentation updates.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • NoeFabris
  • tctinh
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: adding AntiGravity SDK support, Gemini API key routing, and dynamic model discovery.
Description check ✅ Passed The description is directly related to the changeset, detailing Gemini API-key routing, model discovery, and API-key redaction improvements with verification steps.
Linked Issues check ✅ Passed The PR successfully addresses #573 by adding Gemini 3.5 Flash support with multi-API-key routing and model discovery, enabling the requested Google AI Studio-like functionality.
Out of Scope Changes check ✅ Passed All code changes directly support the stated objectives: AGY SDK integration, Gemini API-key routing/pooling, model discovery, and API-key redaction are cohesively implemented across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chrisgeo chrisgeo changed the title feat: add Gemini API key routing and dynamic model discovery feat: Add AntiGravity SDK support & Gemini API key routing, introduce dynamic model discovery May 23, 2026
@chrisgeo
Copy link
Copy Markdown
Author

@emilioarvidisaksson This version might work more cleanly.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR introduces Gemini API-key routing with credential pooling and fallback, runtime model discovery via both the public Gemini API and the Antigravity available-models endpoint, and a new agy-sdk header style for translating Antigravity model IDs to their public API equivalents.

  • API-key credential path (src/plugin/api-key.ts): new module for round-robin credential selection, rate-limit tracking, model-ID normalization, paginated Gemini model discovery, and pre-flight / post-hoc 404 enhancement for Antigravity-only model requests.
  • OAuth fallback & mixed-mode routing (src/plugin.ts): disk-OAuth promotion over API-key auth, triedSwitchIndices to prevent account-spin loops, a loopGuard safety net, tryAgySdkFallbackForRequest wired into every quota-exhaustion branch, and a new provider.models hook for dynamic model lists.
  • Gemini synthetic error shape (src/plugin/request-helpers.ts): createSyntheticErrorResponse now dispatches to a Gemini-shaped SSE stream for non-Claude families, fixing previously unparseable error responses.

Confidence Score: 3/5

Two correctness issues in quota aggregation and API-key fallback handling need to be addressed before merging.

The aggregateQuota inversion from minimum-remaining to maximum-remaining causes the stored resetTime to reflect the model with the most quota rather than the one actually depleted, so getMinWaitTimeForSoftQuota may tell users to wait longer than necessary. Separately, tryFetchWithAgySdkCredentials always returns a non-null Response when credentials exist, so every tryAgySdkFallbackForRequest call site short-circuits the OAuth quota-wait path when all API keys are simultaneously rate-limited.

src/plugin/quota.ts (aggregateQuota logic) and src/plugin.ts (tryAgySdkFallbackForRequest return-value handling in the soft-quota and rate-limit wait branches)

Important Files Changed

Filename Overview
src/plugin/api-key.ts New file: implements Gemini API-key credential pooling, round-robin selection, rate-limit tracking, request preparation, paginated model discovery, and enhanced 404 error responses for Antigravity-only models.
src/plugin.ts Major additions: API-key-only fetch handler, OAuth-from-disk promotion, prefer_for_gemini fast-path, tryAgySdkFallbackForRequest in multiple quota-exhaustion branches, provider.models hook, and loop-guard + triedSwitchIndices. Two correctness issues found in fallback handling.
src/plugin/quota.ts Quota aggregation semantics inverted from min-remaining to max-remaining; resetTime is now tied to the most-remaining model in a group, which can surface incorrect wait times when depleted variants reset earlier.
src/plugin/transform/model-resolver.ts New agy-sdk header style, resolveAntigravityGemini35FlashBackendModel mapping gemini-3.5-flash variants to two backend IDs, and dotted-minor Gemini generation bare-name routing. minimal/medium thinking levels silently collapse to the low-backend model.
src/plugin/config/models.ts Adds GeminiApiModel and AntigravityAvailableModel types plus modelsFromGeminiApi, modelsFromAntigravityAvailableModels, and mergeModelDefinitions for runtime model discovery.
src/plugin/request.ts Refactors prepareAntigravityRequest to accept Request objects, adds signatureCacheProjectKey for project-independent Gemini-3 signature caching, and Gemini thinking-signature restore on the request side.
src/plugin/debug.ts Adds sanitizeUrlForLog to redact ?key= query params and widens maskHeadersForLog to cover any header containing api-key and proxy-authorization.
src/plugin/config/schema.ts New AgySdkConfigSchema and ModelDiscoveryConfigSchema added to AntigravityConfigSchema with matching defaults.
src/plugin/accounts.ts Adds excludeIndices parameter to getCurrentOrNextForFamily and getNextForFamily to prevent re-picking already-tried accounts.
src/plugin/request-helpers.ts Adds createGeminiSyntheticErrorResponse and updates createSyntheticErrorResponse to dispatch on model family, ensuring error streams match the provider shape.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Incoming fetch request] --> B{Is OAuth auth available?}
    B -- No OAuth, API keys present --> C[API-key-only loader branch]
    C --> D{isAntigravityOnlyGenerativeLanguageRequest?}
    D -- Yes --> E[Return synthetic 404 with OAuth guidance]
    D -- No --> F{isAgySdkSupportedRequest?}
    F -- No --> G[Native fetch passthrough]
    F -- Yes --> H[tryFetchWithAgySdkCredentials round-robin key pool]
    H --> I{All keys rate-limited?}
    I -- Yes --> J[Return 429 All keys exhausted]
    I -- No --> K[Return API response with enhanced 404 if needed]
    B -- OAuth present --> L[OAuth / AccountManager path]
    L --> M{prefer_for_gemini and API keys present?}
    M -- Yes --> H
    M -- No --> N[Select OAuth account via triedSwitchIndices]
    N --> O{Account found?}
    O -- No: all tried --> P[tryAgySdkFallbackForRequest]
    P --> Q{Keys available and not all 429?}
    Q -- Yes --> K
    Q -- No --> R[Return last failure or rate-limit error]
    O -- Yes --> S[prepareAntigravityRequest await Request body]
    S --> T[Fetch via Antigravity/Gemini CLI backend]
    T --> U{Success?}
    U -- Yes --> V[transformAntigravityResponse]
    U -- 429/quota --> W{Retry / switch account?}
    W -- Switch --> N
    W -- All exhausted --> P
Loading

Comments Outside Diff (1)

  1. src/plugin.ts, line 95-115 (link)

    P1 API-key-exhausted response always returned instead of falling through to quota wait

    tryFetchWithAgySdkCredentials returns a non-null Response even when every credential was rate-limited — either lastResponse (a real 429) or the synthetic "All Gemini API keys are temporarily rate-limited" 429. Because every call site that uses tryAgySdkFallbackForRequest immediately returns on a truthy result, a fully-exhausted API-key pool short-circuits the upstream OAuth wait logic instead of falling through to it. When all API keys are simultaneously rate-limited, users get an instant 429 even though the OAuth quota would have recovered after the wait.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/plugin.ts
    Line: 95-115
    
    Comment:
    **API-key-exhausted response always returned instead of falling through to quota wait**
    
    `tryFetchWithAgySdkCredentials` returns a non-null `Response` even when every credential was rate-limited — either `lastResponse` (a real 429) or the synthetic `"All Gemini API keys are temporarily rate-limited"` 429. Because every call site that uses `tryAgySdkFallbackForRequest` immediately `return`s on a truthy result, a fully-exhausted API-key pool short-circuits the upstream OAuth wait logic instead of falling through to it. When all API keys are simultaneously rate-limited, users get an instant 429 even though the OAuth quota would have recovered after the wait.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/plugin/quota.ts:146-152
**`aggregateQuota` now surfaces the wrong reset time for depleted models**

The refactor flips `aggregateQuota` from tracking the *minimum* remaining fraction (most depleted model in a group) to the *maximum* (healthiest model), and couples the stored `resetTime` to that same healthiest model. When `getMinWaitTimeForSoftQuota` later uses `groupData.resetTime` to tell users how long to wait, it reports the reset time of the model that still has capacity — which may be *later* than when the actually-depleted models recover. Concretely: if `gemini-3-flash-low` is at 3% (resets in 45 min) and `gemini-3-flash-high` is at 82% (resets in 4 h), the stored reset time becomes 4 h. Soft-quota protection may never trigger (82% > most thresholds), but if it does, users see "wait 4 h" when the model they're hitting resets in 45 min.

### Issue 2 of 3
src/plugin.ts:95-115
**API-key-exhausted response always returned instead of falling through to quota wait**

`tryFetchWithAgySdkCredentials` returns a non-null `Response` even when every credential was rate-limited — either `lastResponse` (a real 429) or the synthetic `"All Gemini API keys are temporarily rate-limited"` 429. Because every call site that uses `tryAgySdkFallbackForRequest` immediately `return`s on a truthy result, a fully-exhausted API-key pool short-circuits the upstream OAuth wait logic instead of falling through to it. When all API keys are simultaneously rate-limited, users get an instant 429 even though the OAuth quota would have recovered after the wait.

### Issue 3 of 3
src/plugin/transform/model-resolver.ts:1158-1170
**`minimal` and `medium` thinking levels silently collapse to the `low` backend model**

`resolveAntigravityGemini35FlashBackendModel` has only two output paths: `level === "high"``gemini-3-flash-agent`, everything else → `gemini-3.5-flash-low`. The static model definitions expose four variants (`minimal`, `low`, `medium`, `high`), so users who choose `gemini-3.5-flash-medium` get routed to `gemini-3.5-flash-low` without indication. If `gemini-3.5-flash-low` ignores higher thinking budgets by design, "medium" silently under-delivers.

Reviews (13): Last reviewed commit: "test: add live diagnostics for Gemini-3 ..." | Re-trigger Greptile

Comment thread src/plugin/api-key.ts Outdated
Comment thread src/plugin/api-key.ts Outdated
Comment thread src/plugin/api-key.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/plugin/request.ts (1)

1787-1857: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Retry-After extraction is unreachable in the normal Google error shape.

Any payload with { error: ... } returns from the earlier block first, so this google.rpc.RetryInfo parsing never runs and callers never get the backoff headers. Move the details scan before that return, or set the retry headers inside the same errorBody?.error branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugin/request.ts` around lines 1787 - 1857, The Retry-After extraction
logic is unreachable because any payload with errorBody.error returns early;
update the handling in request.ts by moving the google.rpc.RetryInfo scan (the
block that finds detail['`@type`'] === 'type.googleapis.com/google.rpc.RetryInfo'
and sets Retry-After/retry-after-ms) into the same branch that processes
errorBody.error (the block that builds rawErrorMessage, debugInfo, sets
errorBody.error.message, checks detectErrorType, and sets
x-antigravity-context-error), or alternatively run that details scan immediately
before the existing early return; adjust references to errorBody, headers, and
retryInfo accordingly so callers receive the backoff headers.
🧹 Nitpick comments (1)
src/plugin/config/schema.test.ts (1)

72-80: ⚡ Quick win

Add JSON-schema parity test for model_discovery as well.

agy_sdk verifies both defaults and schema docs, but model_discovery currently verifies defaults only. Adding the schema assertion prevents drift.

Suggested test addition
 describe("model_discovery config", () => {
   it("includes model_discovery defaults in DEFAULT_CONFIG", () => {
     expect(DEFAULT_CONFIG.model_discovery).toMatchObject({
       enabled: true,
       gemini_api: true,
       antigravity: true,
     });
   });
+
+  it("documents model_discovery in the JSON schema", () => {
+    const schemaPath = new URL("../../../assets/antigravity.schema.json", import.meta.url);
+    const schema = JSON.parse(readFileSync(schemaPath, "utf8")) as {
+      properties?: Record<string, { type?: string; default?: unknown }>;
+    };
+    const modelDiscovery = schema.properties?.model_discovery;
+    expect(modelDiscovery).toBeDefined();
+    expect(modelDiscovery?.type).toBe("object");
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugin/config/schema.test.ts` around lines 72 - 80, Add a JSON-schema
parity assertion for model_discovery by importing the plugin config JSON schema
(e.g., CONFIG_SCHEMA or PLUGIN_CONFIG_SCHEMA) and asserting the schema's default
for properties.model_discovery matches DEFAULT_CONFIG.model_discovery;
specifically, inside the "model_discovery config" test add an expectation like
expect(CONFIG_SCHEMA.properties.model_discovery.default).toMatchObject(DEFAULT_CONFIG.model_discovery)
so schema and defaults cannot drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/antigravity.schema.json`:
- Around line 200-203: The JSON Schema marks "api_key" and "enabled" as required
but your runtime uses Zod defaults so these may be omitted; update the schema by
removing "api_key" and "enabled" from the "required" arrays (and the analogous
fields at the other block around lines 208-213) or mark them as
optional/defaulted so the schema matches the Zod runtime defaults; locate the
"required" arrays in antigravity.schema.json and adjust them to reflect the
runtime defaulting behavior rather than forcing presence.

In `@README.md`:
- Line 143: Update the README bullet so the fallback to configured
agy_sdk.cloud_projects is described as conditional: state that this fallback
occurs only when the AGY SDK is enabled, the fallback option is turned on, and
valid AGY SDK credentials (cloud_projects) are available; reference the existing
config key agy_sdk.cloud_projects and the AGY SDK enablement setting when
rewording the sentence to avoid implying unconditional behavior.

In `@src/plugin.ts`:
- Around line 1620-1633: The current discovery uses Promise.all for
modelsFromAgySdkCredentials and modelsFromOAuthAuth so a single rejection forces
returning fallbackModels; change this to a partial-success approach (e.g.,
Promise.allSettled or separate try/catch calls) to collect successful results
and their errors, then call mergeModelDefinitions with fallbackModels plus only
the successfully-resolved model lists before passing to
normalizeProviderHookModels (referencing modelsFromAgySdkCredentials,
modelsFromOAuthAuth, mergeModelDefinitions, normalizeProviderHookModels,
fallbackModels, providerId, provider, client); log individual source errors at
debug/warn and only use fallbackModels for sources that failed rather than
discarding all discovery.

In `@src/plugin/api-key.ts`:
- Around line 61-64: The code currently selects only one of GEMINI_API_KEY or
GOOGLE_API_KEY via `GEMINI_API_KEY || GOOGLE_API_KEY`, causing the other valid
key to be ignored; change the logic in the block that builds
`envKeys`/`singleEnvKey` so both environment single-key vars are collected
(e.g., gather `process.env.GEMINI_API_KEY` and `process.env.GOOGLE_API_KEY` into
an array, filter out empty/undefined values, trim them, deduplicate if needed)
and then iterate over that combined list when pushing into `credentials`
(reference the variables `envKeys`, `GEMINI_API_KEY`, `GOOGLE_API_KEY`, and the
`credentials.push(...)` site to make the change).
- Around line 225-265: prepareAgySdkGeminiRequest currently only rebuilds
headers/body from init and drops Request metadata when input is a Request; fix
it by detecting when input is a Request, cloning/reading it (e.g.,
request.clone().text()), and preserving its method, signal, and original headers
(merge with the new Headers logic) before applying resolveModelForHeaderStyle
and applyAgySdkGeminiBodyTransforms; alternatively make the helper async so it
can await request.text(), then return init that includes method, signal, headers
(merged), and the transformed body so callers of prepareAgySdkGeminiRequest get
the same HTTP method/signal/body as the original Request.

In `@src/plugin/config/schema.ts`:
- Line 46: Update the zod validation for the api_key field so it rejects
whitespace-only strings; replace the current api_key: z.string().min(1) rule
with one that ensures after trimming the value is non-empty (e.g., use a refine
or equivalent check) so values like "   " fail validation rather than being
normalized later by project.api_key.trim(); modify the schema entry named
api_key in src/plugin/config/schema.ts accordingly and include a clear
validation message for failure.

In `@src/plugin/debug.ts`:
- Around line 308-310: Update isSensitiveHeader to also treat
Proxy-Authorization as sensitive: inside the isSensitiveHeader(key: string)
function, lower-case the header name as done now and add a check for
"proxy-authorization" (or more generally any header that
endsWith("-authorization") if you prefer wider coverage) in addition to
"authorization" and the existing api-key check so Proxy-Authorization values are
redacted from debug logs.

In `@src/plugin/request.ts`:
- Around line 757-764: isGenerativeLanguageRequest currently does a substring
check and should instead parse the URL and compare the hostname exactly so only
real Google Generative Language API requests are intercepted; update
isGenerativeLanguageRequest to call requestInfoUrl(input), construct a new
URL(...) (wrap in try/catch for invalid URLs), and return parsed.hostname ===
"generativelanguage.googleapis.com" (use the hostname property so ports or
credentials are handled consistently); keep requestInfoUrl as-is to support
string and Request inputs and ensure callers like prepareAntigravityRequest use
the updated function.
- Around line 805-807: The current construction of requestUrl/baseInit/headers
in request.ts drops original Request properties when input is a Request and init
is undefined; update the logic in the code that builds baseInit (and uses
requestInfoUrl/requestUrl and headers) to detect when input is an instance of
Request and merge its method, body, signal, and other fetch-relevant fields into
baseInit (with init taking precedence), and carry over headers from the original
Request so the JSON body-rewrite path still sees the original body; ensure you
use the same symbols (requestInfoUrl, requestUrl, baseInit, headers) and only
override fields when init explicitly provides them.

In `@src/plugin/transform/model-resolver.ts`:
- Around line 410-422: The model-transform logic in transform/model-resolver.ts
incorrectly treats the "-minimal" tier as part of the base name because the
replace chain on requestedModel only strips "-low|-medium|-high" and not
"-minimal", causing transformedModel to become e.g.
"gemini-3-flash-minimal-preview" which is invalid; update the normalization so
that requestedModel has "-minimal" removed alongside the other tier suffixes
(modify the initial replace that produces transformedModel), and ensure the
subsequent hasPreviewSuffix and usesBareName checks (which reference
transformedModel and GEMINI_DOTTED_MINOR_REGEX) still operate on the cleaned
name so that the correct "-preview" fallback logic applies.

---

Outside diff comments:
In `@src/plugin/request.ts`:
- Around line 1787-1857: The Retry-After extraction logic is unreachable because
any payload with errorBody.error returns early; update the handling in
request.ts by moving the google.rpc.RetryInfo scan (the block that finds
detail['`@type`'] === 'type.googleapis.com/google.rpc.RetryInfo' and sets
Retry-After/retry-after-ms) into the same branch that processes errorBody.error
(the block that builds rawErrorMessage, debugInfo, sets errorBody.error.message,
checks detectErrorType, and sets x-antigravity-context-error), or alternatively
run that details scan immediately before the existing early return; adjust
references to errorBody, headers, and retryInfo accordingly so callers receive
the backoff headers.

---

Nitpick comments:
In `@src/plugin/config/schema.test.ts`:
- Around line 72-80: Add a JSON-schema parity assertion for model_discovery by
importing the plugin config JSON schema (e.g., CONFIG_SCHEMA or
PLUGIN_CONFIG_SCHEMA) and asserting the schema's default for
properties.model_discovery matches DEFAULT_CONFIG.model_discovery; specifically,
inside the "model_discovery config" test add an expectation like
expect(CONFIG_SCHEMA.properties.model_discovery.default).toMatchObject(DEFAULT_CONFIG.model_discovery)
so schema and defaults cannot drift.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 585aabb2-0d2b-419e-a92f-24fb060f337f

📥 Commits

Reviewing files that changed from the base of the PR and between 740e315 and 4b53c69.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • CHANGELOG.md
  • README.md
  • assets/antigravity.schema.json
  • src/constants.ts
  • src/plugin.test.ts
  • src/plugin.ts
  • src/plugin/api-key.test.ts
  • src/plugin/api-key.ts
  • src/plugin/config/models.test.ts
  • src/plugin/config/models.ts
  • src/plugin/config/schema.test.ts
  • src/plugin/config/schema.ts
  • src/plugin/debug.test.ts
  • src/plugin/debug.ts
  • src/plugin/quota.ts
  • src/plugin/request.test.ts
  • src/plugin/request.ts
  • src/plugin/transform/index.ts
  • src/plugin/transform/model-resolver.test.ts
  • src/plugin/transform/model-resolver.ts
  • src/plugin/types.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
🪛 OpenGrep (1.21.0)
src/plugin.ts

[ERROR] 1146-1146: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 1157-1157: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (12)
CHANGELOG.md (1)

3-12: LGTM!

src/plugin/config/models.ts (1)

35-50: LGTM!

Also applies to: 86-97, 126-140, 148-241

src/plugin/config/models.test.ts (1)

3-7: LGTM!

Also applies to: 27-35, 56-62, 72-119

src/plugin/transform/index.ts (1)

25-25: LGTM!

src/plugin/transform/model-resolver.test.ts (1)

45-50: LGTM!

Also applies to: 70-87, 145-161, 331-386

src/plugin/config/schema.ts (1)

51-77: LGTM!

Also applies to: 332-350, 531-541

src/constants.ts (1)

148-148: LGTM!

assets/antigravity.schema.json (1)

216-243: LGTM!

src/plugin/config/schema.test.ts (1)

50-70: LGTM!

src/plugin/types.ts (1)

12-12: LGTM!

Also applies to: 26-44, 109-109

src/plugin/quota.ts (1)

65-76: LGTM!

Also applies to: 185-188, 343-343

src/plugin.test.ts (1)

1-100: LGTM!

Comment thread assets/antigravity.schema.json
Comment thread README.md Outdated
Comment thread src/plugin.ts Outdated
Comment thread src/plugin/api-key.ts Outdated
Comment thread src/plugin/api-key.ts Outdated
Comment thread src/plugin/config/schema.ts Outdated
Comment thread src/plugin/debug.ts Outdated
Comment thread src/plugin/request.ts
Comment thread src/plugin/request.ts Outdated
Comment thread src/plugin/transform/model-resolver.ts
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/plugin/api-key.test.ts`:
- Around line 101-126: The test is incorrectly asserting Request.body identity;
update the test for prepareAgySdkGeminiRequest to read/parse the
prepared.init.body (or prepared.request body string) and assert the
rewritten/normalized payload contents instead of using toBe(original.body).
Specifically, replace the identity check
expect(prepared.init.body).toBe(original.body) with code that reads
prepared.init.body (or constructs a text/json from prepared.request) and asserts
the payload JSON has the expected contents (e.g., the contents/parts/text value
"hi" and any normalization you expect), while keeping the other header
assertions (x-request-id removed Authorization and x-goog-api-key present)
intact so the test verifies body equality not reference identity.

In `@src/plugin/api-key.ts`:
- Around line 257-275: The current logic only rewrites JSON when originalBody is
a non-empty string, missing cases where requestInput?.body is a ReadableStream;
update the prepare logic around originalBody/requestInput/init so that if the
incoming body is a ReadableStream you read/buffer it to text (clone or
stream-to-string) into originalBody, run
applyAgySdkGeminiBodyTransforms(payload, resolved?.actualModel ?? rawModel ??
"", resolved?.thinkingLevel) then set body = JSON.stringify(payload), and
finally ensure init.duplex = "half" whenever you forward a ReadableStream (or
any stream-like body) to satisfy Undici; keep existing string-path behaviour but
add stream detection and conversion before returning request/init.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 772f34eb-6c20-49e0-b618-9a8fad61ec31

📥 Commits

Reviewing files that changed from the base of the PR and between 4b53c69 and 9602133.

📒 Files selected for processing (2)
  • src/plugin/api-key.test.ts
  • src/plugin/api-key.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review

Comment thread src/plugin/api-key.test.ts Outdated
Comment thread src/plugin/api-key.ts Outdated
chrisgeo and others added 7 commits May 22, 2026 19:25
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/plugin/api-key.ts (1)

278-304: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the original Request options when rebuilding init.

This new Request path only carries over method. signal, redirect, cache, credentials, mode, referrer, and similar options are dropped once the call becomes fetch(prepared.request, prepared.init), so aborts and other request semantics can silently stop working.

🔧 Suggested fix
 export async function prepareAgySdkGeminiRequest(
   input: RequestInfo,
   init: RequestInit | undefined,
   credential: AgySdkCredential,
 ): Promise<PreparedAgySdkGeminiRequest> {
   const requestInput = typeof input === "string" ? undefined : input;
+  const inheritedInit: RequestInit = requestInput
+    ? {
+        method: requestInput.method,
+        signal: requestInput.signal,
+        cache: requestInput.cache,
+        credentials: requestInput.credentials,
+        integrity: requestInput.integrity,
+        keepalive: requestInput.keepalive,
+        mode: requestInput.mode,
+        redirect: requestInput.redirect,
+        referrer: requestInput.referrer,
+        referrerPolicy: requestInput.referrerPolicy,
+      }
+    : {};
   const urlString = requestInput?.url ?? input.toString();
   const url = new URL(urlString);
   const match = url.pathname.match(/\/models\/([^:]+):(\w+)/);
   const rawModel = match?.[1] ?? undefined;
   const action = match?.[2] ?? undefined;
@@
   return {
     request: url.toString(),
     init: {
-      method: requestInput?.method,
+      ...inheritedInit,
       ...init,
       headers,
       body,
     },
     model: resolved?.actualModel ?? rawModel,
   };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugin/api-key.ts` around lines 278 - 304, The rebuilt init currently
only preserves method and spreads init, losing Request-specific options (signal,
redirect, cache, credentials, mode, referrer, referrerPolicy, integrity,
keepalive, duplex, etc.); extract those options from requestInput when it is a
Request (e.g., create requestOptions = requestInput instanceof Request ? {
signal: requestInput.signal, redirect: requestInput.redirect, cache:
requestInput.cache, credentials: requestInput.credentials, mode:
requestInput.mode, referrer: requestInput.referrer, referrerPolicy:
requestInput.referrerPolicy, integrity: requestInput.integrity, keepalive:
requestInput.keepalive, /* duplex if available */ } : {}) and then build the
returned init by spreading requestOptions before spreading init and the other
overrides (ensuring method and headers/body remain correct) so abort signals and
all original request semantics are preserved (reference symbols: requestInput,
requestTextBody, originalBody, headers, the returned init).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@script/build-schema.ts`:
- Around line 101-112: The post-processing in alignAgySdkDefaults only strips
required from agy_sdk but misses model_discovery, so update alignAgySdkDefaults
to do the same for props?.model_discovery: if present delete
model_discovery.required and then locate
model_discovery.properties?.cloud_projects?.items and, when items.required is an
array, filter out "enabled" (same logic as for agy_sdk.cloud_projects). Use the
same symbol names (alignAgySdkDefaults, agy_sdk, model_discovery,
cloud_projects, items) so the changes mirror the existing removal behavior.

In `@src/plugin/request.ts`:
- Around line 845-892: The Request normalization drops original Request headers
and other Request-specific fields; update the logic around requestInput,
baseInit and headers so you fully preserve and merge the original Request
semantics: start baseInit by shallow-copying all relevant Request fields from
requestInput (method, body, signal, redirect, credentials, cache, referrer,
referrerPolicy, mode, integrity, keepalive, etc.) and then overlay any
properties from init, and build headers by constructing new
Headers(requestInput?.headers) and then merging/overwriting with init?.headers
(instead of choosing one or the other) so existing Request headers are retained
and only overridden by init headers; keep prepareAntigravityRequest and
requestInfoUrl usages intact.

---

Duplicate comments:
In `@src/plugin/api-key.ts`:
- Around line 278-304: The rebuilt init currently only preserves method and
spreads init, losing Request-specific options (signal, redirect, cache,
credentials, mode, referrer, referrerPolicy, integrity, keepalive, duplex,
etc.); extract those options from requestInput when it is a Request (e.g.,
create requestOptions = requestInput instanceof Request ? { signal:
requestInput.signal, redirect: requestInput.redirect, cache: requestInput.cache,
credentials: requestInput.credentials, mode: requestInput.mode, referrer:
requestInput.referrer, referrerPolicy: requestInput.referrerPolicy, integrity:
requestInput.integrity, keepalive: requestInput.keepalive, /* duplex if
available */ } : {}) and then build the returned init by spreading
requestOptions before spreading init and the other overrides (ensuring method
and headers/body remain correct) so abort signals and all original request
semantics are preserved (reference symbols: requestInput, requestTextBody,
originalBody, headers, the returned init).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 263a5e14-f353-4ca1-a2fe-b984bf1764a0

📥 Commits

Reviewing files that changed from the base of the PR and between 9602133 and b63c786.

📒 Files selected for processing (16)
  • README.md
  • assets/antigravity.schema.json
  • script/build-schema.ts
  • src/plugin.ts
  • src/plugin/api-key.test.ts
  • src/plugin/api-key.ts
  • src/plugin/config/models.test.ts
  • src/plugin/config/models.ts
  • src/plugin/config/schema.test.ts
  • src/plugin/config/schema.ts
  • src/plugin/debug.test.ts
  • src/plugin/debug.ts
  • src/plugin/request.test.ts
  • src/plugin/request.ts
  • src/plugin/transform/model-resolver.test.ts
  • src/plugin/transform/model-resolver.ts
✅ Files skipped from review due to trivial changes (1)
  • README.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🔇 Additional comments (10)
src/plugin/debug.test.ts (1)

79-93: LGTM!

assets/antigravity.schema.json (1)

200-202: LGTM!

src/plugin/config/schema.test.ts (1)

4-4: LGTM!

Also applies to: 71-74

src/plugin/config/models.test.ts (1)

97-119: LGTM!

src/plugin/config/models.ts (1)

202-202: LGTM!

src/plugin/debug.ts (1)

310-312: LGTM!

src/plugin/api-key.test.ts (1)

25-28: LGTM!

Also applies to: 37-37, 55-55, 62-63, 95-95, 108-108, 110-110, 121-121, 129-137, 143-144, 165-165, 179-180, 192-192, 203-204, 222-222

src/plugin/transform/model-resolver.ts (1)

409-427: LGTM!

src/plugin/request.test.ts (1)

80-88: LGTM!

Also applies to: 560-588

src/plugin/api-key.ts (1)

19-23: LGTM!

Also applies to: 36-43, 84-94, 135-145, 330-330

Comment thread script/build-schema.ts
Comment thread src/plugin/request.ts
The interactive auth-login menu uses select() with clearScreen: true, so
on every re-render the terminal is cleared. Actions that print results
and then continue back to the menu (check quotas, verify, verify-all,
manage, configure-models) had their output wiped before the user could
read it.

Add a pressEnterToContinue() helper in cli.ts and call it at every
menu-loop branch that prints user-visible output. No-op when stdin is
not a TTY so CI / piped input is unaffected.
@chrisgeo
Copy link
Copy Markdown
Author

@thaihoc215 Resolved the previous issue for the plugin:
image

@titet11
Copy link
Copy Markdown

titet11 commented May 25, 2026

I installed this on Windows and it's causing several errors:

The first error is that it sometimes displays the following message:

"" Your account does not have the required IAM permission "cloudaicompanion.companions.generateChat" on the resource "projects/rising-fact-p41fc". Contact your administrator.

""

The next error is that it freezes; that is, it stops responding for a long time.

@chrisgeo
Copy link
Copy Markdown
Author

@titet11 feel free to submit a PR against this fork resolving any issues you run across.

The error message hasn't changed from upstream.

@thaihoc215
Copy link
Copy Markdown

@chrisgeo tested and model work well on my windows device, thank you
@NoeFabris very appreciative if we could have this change to the main branch

@titet11
Copy link
Copy Markdown

titet11 commented May 26, 2026

@chrisgeo

After further analysis, the error I found is not related to this request. The problem is that, with Gemini models, the extension doesn't detect when the quota limit has been reached and continues sending requests to accounts that have already returned error 429.

@chrisgeo
Copy link
Copy Markdown
Author

@chrisgeo

After further analysis, the error I found is not related to this request. The problem is that, with Gemini models, the extension doesn't detect when the quota limit has been reached and continues sending requests to accounts that have already returned error 429.

It still uses the same fallback methods as the original, with new models.

The docs in the fork have one update if you don't want a fallback to Gemini CLI:

In antigravity.json set api_key_fallack to false.

{
  "agy_sdk": {
      "default": {
        "enabled": true,
        "prefer_for_gemini": false,
        "api_key_fallback": true,
        "cloud_projects": []
      }
 }

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented May 26, 2026

Code Review Summary

The review did not run because the selected model is no longer available.

Choose another model in Kilo Code review settings: https://app.kilo.ai/code-reviews

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 26, 2026

Want your agent to iterate on Greptile's feedback? Try greploops.

chrisgeo added 4 commits May 26, 2026 05:42
The plugin had isLikelyAntigravityOnlyModel() but only used it post-hoc
in enhanceAgySdkErrorResponse to dress up 404s after the public Gemini
API rejected the request. isAgySdkSupportedRequest() accepted any
gemini-* URL, so bare Antigravity-only ids (gemini-3.1-pro, gemini-3-pro,
gemini-3-flash, gemini-3.1-flash) leaked to the public API whenever
agy_sdk.api_key_fallback kicked in or auth was API-key only.

- isAgySdkSupportedRequest now rejects Antigravity-only ids so the
  api-key path can never route them. The existing antigravity \u2194 gemini-cli
  OAuth quota fallback (allowQuotaFallback) handles these models as
  originally intended.
- Add isAntigravityOnlyGenerativeLanguageRequest + extractRequestedGeminiModel
  + createAntigravityOnlyModelErrorResponse so the api-key-only auth paths
  short-circuit with a Gemini-shaped 404 carrying the same OAuth guidance
  message, no wasted round trip.
- Refactor enhanceAgySdkErrorResponse to share buildAntigravityModelGuidanceMessage
  with the pre-flight helper to prevent message drift.
- Update isAgySdkSupportedRequest tests for the new contract; add tests
  for the new helpers.
Two coupled defects surfaced when running alongside oh-my-opencode (which
flips the google provider into API-key mode):

1. Disk-stored OAuth accounts were ignored. `auth.loader` only branched
   on `isOAuthAuth(auth)` from OpenCode's getAuth(), so when the provider
   was API-key but `antigravity-accounts.json` held usable refresh tokens,
   the API-key-only interceptor short-circuited `antigravity-*` requests
   with a synthetic 404. Now `auth.loader` consults `loadAccounts()` first
   and synthesizes an OAuth auth from the active disk account; the OAuth
   fetch handler gates on `accountManager.getAccountCount() === 0` so
   per-request behavior follows real disk state.

2. Antigravity-only Gemini ids had no working api-key fallback. The public
   Gemini API doesn't serve bare `gemini-3.x-pro/flash` (verified via
   `GET v1beta/models?key=$GEMINI_API_KEY`), so `isAgySdkSupportedRequest`
   refused to forward them, leaving OAuth-exhaustion fallback a no-op for
   exactly the models that needed it. Added `mapAntigravityModelToPublicApi`
   with the verified mapping (gemini-3-pro -> -preview, gemini-3-flash ->
   -preview, gemini-3.1-pro -> -preview, gemini-3.1-flash -> -lite). Applied
   in `resolveModelForHeaderStyle`'s agy-sdk branch; the gate now consults
   a shared `canRouteAsPublicGeminiApiModel` helper that classifies after
   stripping the prefix and tier suffix.

Mixed-mode safety guards (from two rounds of code review):

- `client.auth.set` (invalid_grant cleanup) is wrapped in
  `if (initialAuthWasOAuth)` so promoted-from-disk OAuth failures don't
  wipe OpenCode's API-key auth by writing empty OAuth credentials.
- OAuth-branch credentials include the captured `apiKeyAuth` so OpenCode's
  API key counts as a fallback credential alongside env vars and
  `agy_sdk.cloud_projects`.
- Last-OAuth-account `invalid_grant` attempts `tryAgySdkFallbackForRequest`
  before throwing, giving mixed-mode setups a real response instead of
  reauth guidance they can't act on.
- `canRouteAsPublicGeminiApiModel` requires `antigravity-` prefixed inputs
  without a known mapping to strip to `^gemini-...` so unknown ids
  (`antigravity-mystery-model`) still hit the synthetic 404 instead of
  being raw-forwarded.

Tests verify the OAuth promotion path is taken (and `client.auth.set` is
NOT called in mixed mode after invalid_grant), the per-id translation
table, and the loosened gate contract. 1070 tests pass; typecheck clean.
@angelo0098
Copy link
Copy Markdown

hello! i fixed the installation issue with locally installing the plugin since for some reason using the config you provided it never worked.
now I'm back to ask a question: does your fork allows for multiple studio api keys to be used? and switch them like the accounts? it would be a great addition!

@chrisgeo
Copy link
Copy Markdown
Author

@angelo0098 yes. Please read the documentation.

@titet11
Copy link
Copy Markdown

titet11 commented May 29, 2026

Frankly, it's starting to bother me that the owner of this repository isn't releasing new versions, and even more so that it takes days or weeks to approve a single request. If any of you would like to clone the repository and provide more active support than the creator himself, that would be excellent.

…usted

Background agents using an Antigravity-only Gemini model (e.g. the OMO
visual-engineering category -> antigravity-gemini-3.1-pro, plus the
per-run gemini-3-flash title generation) could pin a CPU core at 100%
and hang opencode indefinitely once the antigravity quota pool was
exhausted across all accounts. The request loop spun synchronously
(no fetch, no progress), so it was unkillable by SIGTERM and froze the
whole process including the parent session.

Root cause: hybrid account selection judged availability at family level
(isRateLimitedForFamily requires BOTH pools exhausted) and kept
re-selecting an antigravity-exhausted account whose gemini-cli pool was
still open, while the routing check rejected it per header style and set
shouldSwitchAccount without making the next selection exclude it ->
select/switch forever.

- Track accounts switched-away-from within a request (triedSwitchIndices)
  and pass them as excludeIndices to getCurrentOrNextForFamily /
  getNextForFamily so each switch makes forward progress (or selection
  returns null). Cleared after a rate-limit/quota wait so accounts are
  retried once resets free them.
- Add a loop guard and a fast give-up when every account has been tried,
  so the request loop provably terminates (returns the real error or the
  api-key fallback) instead of spinning the event loop.
- Make createSyntheticErrorResponse family-aware: emit a Gemini-shaped SSE
  stream for Gemini requests instead of the Claude-shaped stream, which
  OpenCode cannot parse for a Gemini model and would leave hanging.

Adds regression tests for exclusion-based selection and the Gemini-format
synthetic response.
@volcanonn
Copy link
Copy Markdown

Frankly, it's starting to bother me that the owner of this repository isn't releasing new versions, and even more so that it takes days or weeks to approve a single request. If any of you would like to clone the repository and provide more active support than the creator himself, that would be excellent.

In the discord he said he archived the project and that he doesn't have the time or interest to keep working on it. So we need someone to clone the repository to continue working on it.

@xeropresence
Copy link
Copy Markdown

hello, how can i use your version of the plugin prematurely? so i can use it before they add it to they main version! please answer quickly i beg 🙏

@angelo0098 if you’re on macOS or Linux open ~/.config/opencode/opencode.json (or .jsonc) and add this to your plugin list:

"plugin": [
    “opencode-antigravity-auth@git+https://github.com/chrisgeo/opencode-antigravity-auth.git#0cacb7b9c150c82e49e55b5b3462acbdc0330321”
]

This did not work for me either, on either windows or linux.

@titet11
Copy link
Copy Markdown

titet11 commented May 30, 2026

@volcán
In fact, I'm planning to create a similar extension for the AMP code provider.

I've tried countless times, but I can't establish a connection.

I even tried using a proxy that links to the AMP code, which I've already configured, but without success.

To answer the relevant question, I'd be willing to clone the repository and approve the requests.

…-planning

A Gemini-3 Antigravity agent re-derived the same plan every turn (visible as
an agent looping on one instruction, e.g. repeatedly searching for "Phase 3P").
shouldCacheThinkingSignatures already enabled signature caching for gemini-3 and
the response side cached them, but the input-side restore was gated to Claude
only, so every Gemini-3 turn shipped the skip_thought_signature_validator
sentinel instead of the real signature and the model lost its signed
chain-of-thought.

- Defect 1: sanitizeRequestPayloadForAntigravity now takes optional
  { sessionKey, getSignature } and restores the cached real signature onto the
  first functionCall part (looked up by the block's thinking text) before
  falling back to the sentinel. Wired for non-Claude gemini-3 requests.
- Defect 2: the signature cache key embedded projectId, so a quota-driven
  account/project switch changed the key and missed the cache (the bridge that
  turned the old account-switch freeze into a re-plan loop). Add
  signatureCacheProjectKey() to drop projectId for gemini-3 at all three
  buildSignatureSessionKey sites, so continuity survives account switches. A
  live A/B test confirmed gemini-3 thoughtSignatures are accepted across
  projects (HTTP 200), so reusing them is safe.

Adds regression tests for the restore and the project-independent cache key.
Standalone tsx probes used to validate the signature-loop fix (manual run; both
hit the live Antigravity endpoint and consume quota):

- ab-signature-scope.ts: replays a captured thoughtSignature under a different
  account/project to test cross-project portability. Confirmed signatures are
  accepted across projects (HTTP 200), so the project-independent cache key is safe.
- signature-continuity-probe.ts: A/B-compares real-signature vs sentinel on a
  multi-step tool task to probe whether the model re-plans.
Comment thread src/plugin/quota.ts
@thaihoc215
Copy link
Copy Markdown

Hi @chrisgeo , I see the latest changes from your fork repo. Do you have a plan to publish as a new plugin? Or do I have to clone your repo to build and run it from my local machine?

@chrisgeo
Copy link
Copy Markdown
Author

chrisgeo commented Jun 3, 2026

Hi @chrisgeo , I see the latest changes from your fork repo. Do you have a plan to publish as a new plugin? Or do I have to clone your repo to build and run it from my local machine?

@thaihoc215 I don't have plans to publish separately. Likely plugins need to move to an org to allow better maintenance.

You can install it with a clone or using the direct git reference from the opencode docs.

insign pushed a commit to insign/opencode-antigravity-auth-updated that referenced this pull request Jun 5, 2026
AGENT_PLAN_ANCHOR

## Original User Request (verbatim)
O projeto https://github.com/NoeFabris/opencode-antigravity-auth/ e o nosso projeto atual seguem a mesma base, portanto vamos
  mesclar NoeFabris/opencode-antigravity-auth#576 no nosso projeto.

## Objective
Port upstream PR #576 into the current fork so the project gains AntiGravity SDK support, Gemini API-key routing/pooling, dynamic model discovery, and the later stability fixes included on the PR branch.

## Why This Plan
- The current fork and upstream PR share commit 09ccf4b as a merge base, but both sides diverged afterward.
- A blind branch replacement would overwrite fork-specific package metadata, repository URLs, Node 25 ESM fixes, and local docs updates.
- A normal merge preview reports conflicts in package-lock.json, src/plugin.ts, src/plugin/quota.ts, and model resolver files; resolving those intentionally is safer than copying files wholesale.

## Scope
- In scope: upstream PR #576 feature and fix changes, conflict resolution, tests, typecheck/build verification, and a code review loop.
- Out of scope: pushing to GitHub, changing container/infrastructure config, broad Desloppify cleanup unrelated to the merge, or changing package identity away from opencode-antigravity-auth-updated.

## Current Context
- Working directory: /home/ubuntu/MEGA/WORK/opencode-antigravity-auth-updated.
- Current branch is main at e168501.
- Remote origin is git@github.com:insign/opencode-antigravity-auth-updated.git.
- Upstream PR ref fetched as refs/remotes/upstream/pr-576.
- Project has no Makefile and no lib directory; required lib Desloppify scan is not applicable, so src scan was used for evidence.
- User clarified this project does not use Docker or Podman; native npm commands must be used.

## Constraints, Preferences, and Biases to Preserve
- Preserve fork package name, repository URL, homepage, bug URL, README package references, and build script compatibility.
- Preserve local Node 25 ESM import fix behavior unless the PR explicitly supersedes it.
- Do not use Docker or Podman.
- Do not stage generated Desloppify artifacts unless intentionally part of the merge.
- Prefer minimal conflict resolutions that retain upstream behavior and fork-specific metadata.

## Assumptions to Validate
- The PR branch can be merged with manual conflict resolution.
  - Validation: git merge --no-commit succeeds after resolving conflicts and tests pass.
  - If false: manually apply the PR diff by file and discard unrelated upstream metadata changes.
- Existing local tests cover the merge sufficiently once PR tests are included.
  - Validation: npm test and npm run typecheck pass.
  - If false: fix merge regressions and rerun checks.

## Options Considered
- Accepted: no-commit merge followed by targeted conflict resolution, because it preserves history relationships and applies the full PR surface.
- Rejected: replacing current tree with upstream PR branch, because it would discard fork-specific package/docs/CI details.
- Rejected: cherry-picking 34 commits one by one, because conflict repetition would be high and final behavior matters more than preserving upstream micro-commits.

## Execution Plan
- [ ] Step 1: Merge PR #576 into the worktree without committing and resolve conflicts.
  - Why now: this captures the complete upstream feature surface while preserving the chance to inspect all conflicts before committing.
  - Validation: no unresolved conflict markers remain and git status shows only intended files.
- [ ] Step 2: Adapt fork-specific metadata and ESM/build compatibility.
  - Why now: package identity and Node compatibility must be correct before tests/build.
  - Validation: package.json/package-lock/README/package references remain fork-specific and imports resolve under Node ESM.
- [ ] Step 3: Run native verification.
  - Why now: the merge touches core request routing, auth, quota, model resolution, and tests.
  - Validation: npm test, npm run typecheck, and npm run build where feasible pass.
- [ ] Step 4: Commit the port and run reviewer loop.
  - Why now: code review should evaluate the complete merged code commit.
  - Validation: reviewers report no judge-approved remaining fixes, or approved fixes are committed and re-reviewed.
- [ ] Step 5: Final docs/context check and report.
  - Why now: ensure user receives merge state, verification, and review decisions.
  - Validation: final response includes tests and Code Review section.

## Do
- Use native npm commands for tests/checks.
- Keep upstream PR behavior where it does not conflict with fork-specific identity or existing fixes.
- Resolve conflicts with source inspection, not assumptions.
- Avoid unrelated cleanup.

## Do Not
- Do not use Docker or Podman.
- Do not push unless explicitly requested.
- Do not revert unrelated user changes.
- Do not let upstream package metadata overwrite the fork identity.

## References
- NoeFabris/opencode-antigravity-auth#576
- refs/remotes/upstream/pr-576
- package.json
- README.md
- src/plugin.ts
- src/plugin/api-key.ts
- src/plugin/transform/model-resolver.ts

## Risks and Dependencies
- Risk: PR #576 is large and touches core routing behavior.
  - Mitigation: run full tests/typecheck/build and independent reviewer loop.
- Risk: local fork has changes not present upstream.
  - Mitigation: preserve local metadata and inspect conflicts manually.
- Risk: generated Desloppify artifacts could pollute the commit.
  - Mitigation: stage only intended merge files.

## Handoff Notes
- The latest plan anchor should be used for any resumed work.
- Upstream PR #576 includes later fixes for quota aggregation, OAuth/API-key fallback, infinite account-switch loop, and Gemini-3 thought-signature continuity; do not stop at the early feature commits.
- User explicitly stated the project does not use Docker nor Podman.

## Definition of Done
- PR #576 feature/fix changes are present in this fork.
- Fork package identity remains opencode-antigravity-auth-updated.
- Native tests and typecheck pass, with build attempted if feasible.
- Code changes are committed with PLAN_REF.
- Reviewer loop completes with no judge-approved unresolved findings.
insign pushed a commit to insign/opencode-antigravity-auth-updated that referenced this pull request Jun 5, 2026
PLAN_REF: 374c922
PREVIOUS_STEP: 374c922 — plan anchor for PR 576 port

## Completed in This Step
- Merged upstream PR #576 into the fork with manual conflict resolution.
- Preserved fork package identity as opencode-antigravity-auth-updated.
- Added API-key routing, agy-sdk fallback, dynamic model discovery, model-resolution updates, quota fixes, and PR regression coverage.
- Preserved local stale-provider reload behavior and proactive quota refresh while adding PR test exports.
- Restored AccountManager.updateQuotaCache index-or-token support needed by PR tests.
- Updated auto-update checker tests to the fork package name.

## References Used
- NoeFabris/opencode-antigravity-auth#576
- refs/remotes/upstream/pr-576
- package.json
- src/plugin.ts
- src/plugin/accounts.ts
- src/plugin/quota.ts
- src/plugin/transform/model-resolver.ts

## Debts and Warnings
- Desloppify generated unstaged artifacts during required scan attempts; these were intentionally not staged.
- Desloppify scan --path lib is not applicable because this repo has no lib directory, and a later scan was blocked by Desloppify's active queue state.
- Live diagnostic scripts from upstream are included but should consume quota only when run manually.

## Progress (ref: 374c922)
- [x] Step 1: Merge PR #576 into the worktree without committing and resolve conflicts.
- [x] Step 2: Adapt fork-specific metadata and ESM/build compatibility.
- [x] Step 3: Run native verification.
- [ ] Step 4: Commit the port and run reviewer loop.
- [ ] Step 5: Final docs/context check and report.

## Verification
- npm test: passed via tester subagent
- npm run typecheck: passed via tester subagent
- npm run build: passed via tester subagent

## Next Step
chore(agent): [Step 2/5] run reviewer loop for PR 576 port
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.

Gemini 3.5 Flash add please

7 participants