Align Antigravity auth, transports, and current models#575
Align Antigravity auth, transports, and current models#575Daltonganger wants to merge 5 commits into
Conversation
|
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:
WalkthroughThis PR introduces a transport boundary (gateway/CLI/managed-agent) with implementations and tests; adds opaque in-memory OAuth state with redirectMode and sensitive-data redaction; updates endpoint selection (non-sandbox daily primary) and endpoint invariants tests; replaces the default model/quota set with Antigravity-only entries and updates resolver logic for Gemini 3.5 and GPT-OSS; changes request/response wiring so non-OAuth transports run via transport interfaces and gateway paths delegate to gatewayTransport; adds local agy version detection and related tests; updates config/schema to include a transport block with deep-merge behavior; and updates many docs, scripts, and package.json to 1.7.0-beta.0. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
|
There was a problem hiding this comment.
💡 Codex Review
opencode-antigravity-auth/src/plugin.ts
Line 1429 in 1acb7be
This early return {} makes the plugin skip installing its fetch interceptor whenever OpenCode auth is missing, which blocks the new cli and managed-agent transports even though both declare requiresOAuth: false. In a fresh setup that only configures transport.managed_agent.api_key (or transport.cli), requests will bypass the transport code entirely until the user performs OAuth login, contradicting the transport contract and effectively disabling the feature.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (cachedAgyAuthState === null) { | ||
| cachedAgyAuthState = await checkAgyAuthState(binaryPath) | ||
| } | ||
| if (cachedAgyAuthState === "unauthenticated") { |
There was a problem hiding this comment.
Recheck agy auth state after an unauthenticated probe
The auth probe result is cached once, and if it is initially "unauthenticated", every later request returns 401 without rechecking. That means following the returned instruction (logging into agy in a terminal) does not recover in the same plugin session; users must restart the process before requests can succeed. This creates a persistent false-negative auth state and breaks expected retry behavior.
Useful? React with 👍 / 👎.
| function readJsonBody(init: RequestInit | undefined): Record<string, unknown> { | ||
| if (typeof init?.body !== "string") return {} | ||
| try { |
There was a problem hiding this comment.
Parse request body from RequestInfo, not only init.body
CliTransport only parses JSON from ctx.init.body, so if callers pass a Request object (with its body on ctx.input and init omitted), prompt extraction fails and prepareRequest throws even for valid generative requests. Since the transport interface accepts RequestInfo, this is a real interoperability regression for request paths that use new Request(...).
Useful? React with 👍 / 👎.
Greptile SummaryThis PR aligns the Antigravity plugin with current CLI behavior across three areas: OAuth (opaque PKCE state storage, broader token redaction,
Confidence Score: 4/5Safe to merge for the Gateway transport path; the new CLI and Managed Agent transports have open issues discussed in prior review threads that should be resolved before those paths go to production. The gateway refactoring is a thin wrapper with no behavior change, and the OAuth hardening (opaque state, broader redaction) is straightforward. The experimental transports carry open issues from prior review rounds: the CLI auth cache permanently locks out the user within a session, managed-agent streaming omits the required ?alt=sse parameter, and dangerously_skip_permissions defaults to opt-in rather than opt-out. These don't affect the default gateway path but would break users who enable the opt-in transports today. src/plugin/transport/managed-agent-transport.ts and src/plugin/config/schema.ts — the streaming issue and permission default discussed in prior review threads are still present and affect anyone enabling those transports. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Incoming fetch request] --> B{transport.matches?}
B -- No --> C[Pass through to native fetch]
B -- Yes --> D{transport.auth.requiresOAuth?}
D -- No: CLI/ManagedAgent --> E{transport.id === cli?}
E -- Yes --> F{cachedAgyBinaryPath?}
F -- null --> G[findAgyBinary]
G --> H{found?}
H -- No --> ERR1[404 AGY_NOT_FOUND]
H -- Yes --> I{cachedAgyAuthState?}
F -- cached --> I
I -- null --> J[checkAgyAuthState]
J --> K{state?}
K -- unauthenticated --> ERR2[401 UNAUTHENTICATED]
K -- authenticated/unknown --> L[executeAgyCommand]
I -- authenticated/unknown --> L
L --> M[transformResponse: geminiTextResponse]
E -- No: ManagedAgent --> N[prepareRequest: build Interactions API body]
N --> O[fetch INTERACTIONS_ENDPOINT]
O --> P{streaming?}
P -- No --> Q[extractManagedAgentText: toGeminiTextResponse]
P -- Yes --> R[return SSE as-is]
D -- Yes: Gateway --> S[account selection + auth refresh]
S --> T[endpoint fallback loop]
T --> U[gatewayTransport.prepareRequest]
U --> V[fetch backend endpoint]
V --> W[gatewayTransport.transformResponse]
W --> X[Return OpenCode-compatible Response]
M --> X
Q --> X
R --> X
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
src/plugin/transform/model-resolver.ts:234-236
Dead-code ternary — both branches return `"low"`. If the intention was to keep a placeholder for when a different default tier is needed for non-3.5-flash Gemini 3 models, the else branch should differ; otherwise the condition can be removed entirely.
```suggestion
const defaultThinkingLevel = "low";
```
### Issue 2 of 2
src/plugin/config/models.ts:66-70
**Smoke-tested model ID has no definition entry**
The PR validation runs against `google/antigravity-gemini-3.5-flash-medium`, and the description lists both `medium` and `high` flash as active quota rows. The resolver silently forces all `gemini-3.5-flash` requests to `-low` (by design), but `antigravity-gemini-3.5-flash-medium` and `antigravity-gemini-3.5-flash-high` are never registered here. Any UI component that enumerates the model registry (context-window display, quota-group picker) will only show `antigravity-gemini-3.5-flash-low`, while docs and the smoke test point users at the `medium` ID. Adding definitions for the other two quota rows would make the registry consistent with the documented quota surface, even if they all resolve to the same underlying API row.
Reviews (5): Last reviewed commit: "fix: align current models with live avai..." | Re-trigger Greptile |
| /** Skip permission prompts in agy. */ | ||
| dangerously_skip_permissions: z.boolean().default(true), |
There was a problem hiding this comment.
dangerously_skip_permissions defaults to true, so every user who enables the CLI transport immediately gets agy --dangerously-skip-permissions on all requests — bypassing all permission checks — without explicitly opting in. The name's own dangerously_ prefix signals this should be an explicit opt-in. With the current default, agy can read, write, or execute files without asking the user the moment they enable the transport.
| /** Skip permission prompts in agy. */ | |
| dangerously_skip_permissions: z.boolean().default(true), | |
| /** Skip permission prompts in agy. */ | |
| dangerously_skip_permissions: z.boolean().default(false), |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin/config/schema.ts
Line: 472-473
Comment:
`dangerously_skip_permissions` defaults to `true`, so every user who enables the CLI transport immediately gets `agy --dangerously-skip-permissions` on all requests — bypassing all permission checks — without explicitly opting in. The name's own `dangerously_` prefix signals this should be an explicit opt-in. With the current default, agy can read, write, or execute files without asking the user the moment they enable the transport.
```suggestion
/** Skip permission prompts in agy. */
dangerously_skip_permissions: z.boolean().default(false),
```
How can I resolve this? If you propose a fix, please make it concise.| return { | ||
| text: JSON.stringify(payload), | ||
| interactionId, | ||
| } |
There was a problem hiding this comment.
When none of the expected fields (
output, text, candidates) are present, the entire raw JSON.stringify(payload) is returned as model text. Any field in the API response — including error details, internal IDs, or debugging artifacts — surfaces directly in the model's reply. A safer fallback would be a descriptive error string so users know parsing failed rather than getting a raw JSON dump.
| return { | |
| text: JSON.stringify(payload), | |
| interactionId, | |
| } | |
| return { | |
| text: "[ManagedAgent] Could not parse response text from API payload.", | |
| interactionId, | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin/transport/managed-agent-transport.ts
Line: 125-128
Comment:
When none of the expected fields (`output`, `text`, `candidates`) are present, the entire raw `JSON.stringify(payload)` is returned as model text. Any field in the API response — including error details, internal IDs, or debugging artifacts — surfaces directly in the model's reply. A safer fallback would be a descriptive error string so users know parsing failed rather than getting a raw JSON dump.
```suggestion
return {
text: "[ManagedAgent] Could not parse response text from API payload.",
interactionId,
}
```
How can I resolve this? If you propose a fix, please make it concise.| * The current plugin uses the v2 endpoint; the official CLI uses the v1 endpoint. | ||
| */ | ||
| export const ANTIGRAVITY_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/auth"; | ||
|
|
||
| /** | ||
| * Redirect mode controls which OAuth callback URI and auth endpoint to use. | ||
| * - `local-callback`: existing behavior, local HTTP server on port 51121. | ||
| * - `official-callback`: experimental, uses the hosted Antigravity callback URI | ||
| * and v1 auth endpoint matching official `agy`. Not fully functional yet | ||
| * because the hosted callback consumes the authorization code server-side. | ||
| */ | ||
| export type AntigravityRedirectMode = "local-callback" | "official-callback"; | ||
|
|
||
| /** | ||
| * Resolve the redirect URI for the given redirect mode. | ||
| */ | ||
| export function getRedirectUri(mode: AntigravityRedirectMode): string { | ||
| return mode === "official-callback" | ||
| ? ANTIGRAVITY_OFFICIAL_REDIRECT_URI |
There was a problem hiding this comment.
official-callback mode exported while broken by design
AntigravityRedirectMode is a public type and getRedirectUri/getAuthEndpoint are exported, so callers can pass "official-callback" to authorizeAntigravity. The constants file itself documents this mode as "Not fully functional yet because the hosted callback consumes the authorization code server-side." If a caller uses this mode, the authorization URL is built correctly but token exchange will always fail. Consider marking the type @internal or gating the mode behind a non-exported constant until it is functional.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/constants.ts
Line: 38-56
Comment:
**`official-callback` mode exported while broken by design**
`AntigravityRedirectMode` is a public type and `getRedirectUri`/`getAuthEndpoint` are exported, so callers can pass `"official-callback"` to `authorizeAntigravity`. The constants file itself documents this mode as "Not fully functional yet because the hosted callback consumes the authorization code server-side." If a caller uses this mode, the authorization URL is built correctly but token exchange will always fail. Consider marking the type `@internal` or gating the mode behind a non-exported constant until it is functional.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/constants.ts (1)
70-73:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSynchronize endpoint doc comment with the new fallback chain.
Line 71–73 still describes sandbox daily → autopush → prod, which no longer matches the exported fallback constants.
📝 Suggested comment update
- * CLIProxy and Vibeproxy use the daily sandbox endpoint first, - * then fallback to autopush and prod if needed. + * Fallback order is non-sandbox daily, then sandbox daily, then prod.🤖 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/constants.ts` around lines 70 - 73, Update the block comment describing root endpoints so it matches the current exported fallback constants: edit the comment referencing CLIProxy and Vibeproxy to reflect the new fallback order (replace the old "sandbox daily → autopush → prod" sequence with the actual sequence used by the exported fallback constants), ensuring the text aligns with the exported constants that define the fallback chain in this module.docs/ARCHITECTURE.md (1)
138-141:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate fallback order text to match current runtime behavior.
Line 140 still documents
daily → autopush → prod, but the current fallback chain is non-sandbox daily → sandbox daily → prod.📝 Suggested doc correction
-- Endpoint fallback (daily → autopush → prod) +- Endpoint fallback (non-sandbox daily → sandbox daily → prod)🤖 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 `@docs/ARCHITECTURE.md` around lines 138 - 141, Update the documentation line that currently reads "Endpoint fallback (daily → autopush → prod)" to reflect the actual runtime fallback order "non-sandbox daily → sandbox daily → prod"; locate the list item by its current text "Endpoint fallback (daily → autopush → prod)" and replace it with the updated fallback chain so docs match runtime behavior.
🧹 Nitpick comments (4)
src/plugin/transport/cli-transport.ts (2)
117-119: ⚡ Quick winClarify error message for empty prompts.
The error message states "could not extract a text prompt" but the actual issue is that the extracted prompt is empty or whitespace-only. Consider a more precise message like
"Extracted prompt is empty or contains only whitespace."to help users distinguish between parsing failures and empty input.🤖 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/transport/cli-transport.ts` around lines 117 - 119, The thrown error for an empty/whitespace-only prompt is misleading; update the check in the CliTransport code path that uses the prompt variable (the block that does if (!prompt.trim()) { ... }) to throw a clearer message such as "Extracted prompt is empty or contains only whitespace." so callers can distinguish empty input from extraction/parsing failures—modify the Error thrown in that conditional inside the CliTransport method that extracts `prompt`.
158-164: ⚡ Quick winAdd error handling for JSON parsing.
ctx.response.json()can throw if the response body is not valid JSON. Consider wrapping in try/catch to provide a clearer error message or fallback behavior.🛡️ Suggested error handling
async transformResponse(ctx: TransformTransportResponseContext): Promise<Response> { if (!ctx.response.ok) return ctx.response - const payload = await ctx.response.json() as { stdout?: unknown; stderr?: unknown } - const stdout = typeof payload.stdout === "string" ? payload.stdout : "" + try { + const payload = await ctx.response.json() as { stdout?: unknown; stderr?: unknown } + const stdout = typeof payload.stdout === "string" ? payload.stdout : "" + return geminiTextResponse(stdout.trim()) + } catch (error) { + throw new Error(`Failed to parse CLI response: ${error instanceof Error ? error.message : String(error)}`) + } - - return geminiTextResponse(stdout.trim()) }🤖 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/transport/cli-transport.ts` around lines 158 - 164, The transformResponse function should guard against invalid JSON from ctx.response.json() by wrapping the parse in a try/catch: catch JSON parse errors when calling ctx.response.json(), log or attach the error context (including ctx.response.status) and fall back to returning the original ctx.response or a safe geminiTextResponse with an empty string; update transformResponse (reference function transformResponse, variable payload, call to ctx.response.json(), and return geminiTextResponse(stdout.trim())) to implement this try/catch and clear fallback behavior.src/plugin/version.ts (2)
28-33: 💤 Low valueFilter out the
~/.local/bin/agycandidate whenHOMEis unset.When
process.env.HOMEis undefined/empty, the first candidate becomes the literal/.local/bin/agy, which is harmless (ENOENT) but wastes a process spawn on every plugin start and pollutes any future debug logs. Either skip the candidate or only include it whenHOMEis set.♻️ Proposed fix
-const AGY_CANDIDATES = [ - `${process.env["HOME"] ?? ""}/.local/bin/agy`, - "agy", -]; +const AGY_CANDIDATES = [ + ...(process.env["HOME"] ? [`${process.env["HOME"]}/.local/bin/agy`] : []), + "agy", +];🤖 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/version.ts` around lines 28 - 33, AGY_CANDIDATES currently includes `${process.env["HOME"] ?? ""}/.local/bin/agy` which becomes `/.local/bin/agy` when HOME is unset and causes unnecessary spawns; update the AGY_CANDIDATES definition to only include the HOME-based path when process.env.HOME is a non-empty string (e.g., build the array conditionally or filter falsy entries) so the HOME candidate is omitted when HOME is not set, leaving only "agy" as the fallback.
47-79: 💤 Low valueCascade keeps spawning
agyprocesses after the outer timeout resolves.
tryNextrecurses throughAGY_CANDIDATESpurely fromexecFilecallbacks and never checks whether the outersetTimeouthas already resolved the promise withnull. If a candidate hits its owntimeout(or simply errors) after the outer 2s timer has already fireddone(null), the next candidate is still spawned (a fresh 2sexecFile), and so on. The promise result is correct, but the helper can keep launchingagysubprocesses after it has logically completed.Short-circuit the chain when
resolvedis set:♻️ Proposed fix
const tryNext = (candidates: string[]): void => { + if (resolved) return; if (candidates.length === 0) { clearTimeout(timer); done(null); return; } const [candidate, ...rest] = candidates; execFile(candidate!, ["--version"], { timeout: AGY_BINARY_TIMEOUT_MS }, (err, stdout, stderr) => { + if (resolved) return; if (err) { tryNext(rest); return; } const version = parseVersion((stdout || stderr).trim()); clearTimeout(timer); done(version); }); };🤖 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/version.ts` around lines 47 - 79, The tryLocalAgyVersion helper can continue spawning execFile calls after the outer timeout sets resolved; update tryNext/execFile usage in tryLocalAgyVersion so the chain short-circuits when resolved is true: before calling execFile check if resolved and return early, store the child returned by execFile and, in the outer timeout/done path, ensure any in-flight child is killed, and inside the execFile callback immediately return if resolved is set (and avoid calling tryNext). Make these changes around the functions/variables tryLocalAgyVersion, tryNext, done, resolved, timer, AGY_CANDIDATES and the execFile invocation so no new processes are spawned after resolution.
🤖 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 382-384: Change the JSON schema for the experimental transport so
the property "dangerously_skip_permissions" is opt-in: locate the
"dangerously_skip_permissions" property in assets/antigravity.schema.json and
change its "default" value from true to false; ensure the property's "type"
remains "boolean" and run schema validation/tests to confirm no other code
assumes the old default.
In `@docs/ANTIGRAVITY_CLI_MIGRATION_PLAN.md`:
- Around line 788-797: The document contradicts itself by saying “Start Phase 1
with tests first:” under the "## Recommended Immediate Next Step" header while
an earlier section already marks Phase 1 complete; update the wording to match
the actual state — either change "Start Phase 1 with tests first:" to "Begin
Phase 2 with tests first:" (keeping the existing 1–4 checklist: OAuth tests, add
openid/redirect-mode, verify local callback, experiment with hosted callback)
or, if Phase 1 is not actually complete, remove the earlier "Phase 1 complete"
marker so the current instruction remains correct; ensure the header and the
checklist consistently reference the same phase ("Phase 1" or "Phase 2")
throughout the doc.
In `@docs/ARCHITECTURE.md`:
- Around line 69-78: The fenced code block in the ARCHITECTURE.md snippet is
missing a language tag; update the block opener to include a language identifier
(e.g., "text" or "txt") so the markdown linter passes—leave the content
unchanged (the diagram referencing plugin.ts and gatewayTransport methods:
matches(), getRequestMetadata(), prepareRequest() / prepareAntigravityRequest(),
transformResponse() / transformAntigravityResponse()) and only add the language
tag to the initial ``` fence.
In `@README.md`:
- Around line 686-687: The README currently instructs users to "disable
`quota_fallback`" even though `quota_fallback` is a deprecated no-op; update the
Gemini CLI sunset note to remove that recommendation and replace it with
actionable guidance — mention `gemini-cli` sunset date and advise concrete next
steps such as choosing an alternate transport (e.g., switch from quota-based
transport to authenticated Google AI transport), migrating to supported models
or tiers (Google AI Pro/Ultra alternatives), and updating any config fields that
actually affect routing (call out the `quota_fallback` key as deprecated/ignored
and recommend the real config keys or workflows to change). Ensure the copy
explicitly references the `quota_fallback` key as deprecated and provides clear
migration/transport selection steps and links to relevant docs or config keys.
In `@script/test-cross-model-e2e.sh`:
- Line 6: Update the header comment that lists the Gemini models to correct the
second model ID by adding the missing google/antigravity- prefix so both entries
match the full model IDs (change "gemini-3.5-flash-medium" to
"google/antigravity-gemini-3.5-flash-medium" in the comment line that starts
with "1. Gemini").
In `@src/antigravity/oauth.ts`:
- Around line 31-56: The current regexes only match parameters when preceded by
? or &, so "code=..." or "state=..." at the start of the string bypasses
redaction; update each pattern that begins with ([?&]PARAM=) to allow
start-of-string by changing it to /(^|[?&])PARAM=[^&\s"']+/gi and change the
replacement to include the captured prefix and the param name (e.g.,
"$1code=[REDACTED]" for the patterns referencing code), applying this change for
code, state, refresh_token, access_token, id_token, client_secret,
code_verifier, and code_challenge in the same replace chain in
src/antigravity/oauth.ts so start-of-string params are redacted.
In `@src/plugin.ts`:
- Around line 1490-1546: The current logic in the cli transport block caches
negative results permanently: cachedAgyBinaryPath and cachedAgyAuthState are set
even when no binary is found or when checkAgyAuthState returns
"unauthenticated", which blocks recovery until plugin restart; change the
caching policy so only positive findings are sticky: set cachedAgyBinaryPath
only when a valid binary path is found (leave it null if not found) and set
cachedAgyAuthState to "authenticated" only when checkAgyAuthState returns that;
do not cache "unauthenticated" (keep it null or "unknown") so subsequent
requests will re-run findAgyBinary() and checkAgyAuthState() and allow recovery
after the user installs or signs in; update the cli branch where
findAgyBinary(), cachedAgyBinaryPath and checkAgyAuthState() are used to
implement this behavior.
In `@src/plugin/transport/agy-cli.ts`:
- Around line 37-53: The execFileText function calls execFile without a
maxBuffer which can cause stdout/stderr truncation for large outputs; update
execFileText to pass a larger maxBuffer in the options object passed to execFile
(e.g., { timeout: timeoutMs, maxBuffer: <suitable byte size> }) or switch
execFile usage to a streaming approach (spawn and stream stdout/stderr) if you
expect arbitrarily large output; locate the execFile call inside execFileText
and either add the maxBuffer option or refactor execFileText to use spawn and
stream handling to avoid Node's default buffer limit.
---
Outside diff comments:
In `@docs/ARCHITECTURE.md`:
- Around line 138-141: Update the documentation line that currently reads
"Endpoint fallback (daily → autopush → prod)" to reflect the actual runtime
fallback order "non-sandbox daily → sandbox daily → prod"; locate the list item
by its current text "Endpoint fallback (daily → autopush → prod)" and replace it
with the updated fallback chain so docs match runtime behavior.
In `@src/constants.ts`:
- Around line 70-73: Update the block comment describing root endpoints so it
matches the current exported fallback constants: edit the comment referencing
CLIProxy and Vibeproxy to reflect the new fallback order (replace the old
"sandbox daily → autopush → prod" sequence with the actual sequence used by the
exported fallback constants), ensuring the text aligns with the exported
constants that define the fallback chain in this module.
---
Nitpick comments:
In `@src/plugin/transport/cli-transport.ts`:
- Around line 117-119: The thrown error for an empty/whitespace-only prompt is
misleading; update the check in the CliTransport code path that uses the prompt
variable (the block that does if (!prompt.trim()) { ... }) to throw a clearer
message such as "Extracted prompt is empty or contains only whitespace." so
callers can distinguish empty input from extraction/parsing failures—modify the
Error thrown in that conditional inside the CliTransport method that extracts
`prompt`.
- Around line 158-164: The transformResponse function should guard against
invalid JSON from ctx.response.json() by wrapping the parse in a try/catch:
catch JSON parse errors when calling ctx.response.json(), log or attach the
error context (including ctx.response.status) and fall back to returning the
original ctx.response or a safe geminiTextResponse with an empty string; update
transformResponse (reference function transformResponse, variable payload, call
to ctx.response.json(), and return geminiTextResponse(stdout.trim())) to
implement this try/catch and clear fallback behavior.
In `@src/plugin/version.ts`:
- Around line 28-33: AGY_CANDIDATES currently includes `${process.env["HOME"] ??
""}/.local/bin/agy` which becomes `/.local/bin/agy` when HOME is unset and
causes unnecessary spawns; update the AGY_CANDIDATES definition to only include
the HOME-based path when process.env.HOME is a non-empty string (e.g., build the
array conditionally or filter falsy entries) so the HOME candidate is omitted
when HOME is not set, leaving only "agy" as the fallback.
- Around line 47-79: The tryLocalAgyVersion helper can continue spawning
execFile calls after the outer timeout sets resolved; update tryNext/execFile
usage in tryLocalAgyVersion so the chain short-circuits when resolved is true:
before calling execFile check if resolved and return early, store the child
returned by execFile and, in the outer timeout/done path, ensure any in-flight
child is killed, and inside the execFile callback immediately return if resolved
is set (and avoid calling tryNext). Make these changes around the
functions/variables tryLocalAgyVersion, tryNext, done, resolved, timer,
AGY_CANDIDATES and the execFile invocation so no new processes are spawned after
resolution.
🪄 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: aafccb17-7d5f-4e4d-b424-ef9c5c2234f4
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (47)
.github/ISSUE_TEMPLATE/bug_report.ymlCHANGELOG.mdREADME.mdassets/antigravity.schema.jsondocs/ANTIGRAVITY_API_SPEC.mddocs/ANTIGRAVITY_AUTH_RECOVERY_PLAN.mddocs/ANTIGRAVITY_CLI_MIGRATION_PLAN.mddocs/ANTIGRAVITY_PHASE0_BASELINE.mddocs/ARCHITECTURE.mddocs/CONFIGURATION.mddocs/MODEL-VARIANTS.mddocs/MULTI-ACCOUNT.mddocs/SUPPORT_MATRIX.mddocs/TROUBLESHOOTING.mdindex.tsscript/test-cross-model-e2e.shscript/test-gemini-cli-e2e.shscript/test-models.tsscript/test-regression.tsscripts/check-quota.mjsscripts/setup-opencode-pi.shsrc/antigravity/oauth.test.tssrc/antigravity/oauth.tssrc/constants.endpoint.test.tssrc/constants.tssrc/plugin.tssrc/plugin/accounts.test.tssrc/plugin/config/loader.tssrc/plugin/config/models.test.tssrc/plugin/config/models.tssrc/plugin/config/schema.tssrc/plugin/config/updater.test.tssrc/plugin/quota.tssrc/plugin/request.tssrc/plugin/transform/model-resolver.test.tssrc/plugin/transform/model-resolver.tssrc/plugin/transport/agy-cli.test.tssrc/plugin/transport/agy-cli.tssrc/plugin/transport/cli-transport.test.tssrc/plugin/transport/cli-transport.tssrc/plugin/transport/gateway-transport.test.tssrc/plugin/transport/gateway-transport.tssrc/plugin/transport/managed-agent-transport.test.tssrc/plugin/transport/managed-agent-transport.tssrc/plugin/transport/types.tssrc/plugin/version.test.tssrc/plugin/version.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
🪛 LanguageTool
docs/ANTIGRAVITY_PHASE0_BASELINE.md
[style] ~208-~208: The double modal “Requires authenticated” is nonstandard (only accepted in certain dialects). Consider “to be authenticated”.
Context: ...ix:** Not captured in Phase 0. Requires authenticated fetchAvailableModels call. --- ## F...
(NEEDS_FIXED)
[locale-violation] ~373-~373: The phrase ‘in future’ is British English. Did you mean: “in the future”?
Context: ...t should be moved to env var or keyring in future. --- ## OAuth Test Coverage **Source...
(IN_FUTURE)
[style] ~498-~498: The double modal “requires authenticated” is nonstandard (only accepted in certain dialects). Consider “to be authenticated”.
Context: ... Not captured in Phase 0 (requires authenticated OpenCode session + debug logging): - [...
(NEEDS_FIXED)
CHANGELOG.md
[style] ~11-~11: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...point()helpers inconstants.ts. - Added redactOAuthSensitiveData()` to scrub c...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~12-~12: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...PKCE verifiers from error messages. - Added 32 OAuth tests covering URL constructio...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~66-~66: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...tions. - docs/ANTIGRAVITY_API_SPEC.md updated with endpoint status table and openid...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
docs/SUPPORT_MATRIX.md
[style] ~160-~160: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...the antigravity header style only. **If you stored accounts before this release...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
docs/ANTIGRAVITY_CLI_MIGRATION_PLAN.md
[style] ~84-~84: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... PKCE verifiers, or keyring material. - Do not replace the default gateway shim wi...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~85-~85: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...without a stable structured protocol. - Do not rewrite auth, request transformatio...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~86-~86: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... transport architecture in one phase. - Do not remove existing account storage unt...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~87-~87: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...l migration is proven and reversible. - Do not assume preview Managed Agents APIs ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~359-~359: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...chAvailableModels` on all candidates. - Test one Gemini model and one Claude model p...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~409-~409: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... - Keep recovery semantics unchanged. - Keep quota/account rotation outside optional...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~517-~517: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hangelog` or another stable command. 3. Detect authentication state without triggering...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~617-~617: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...evious_interaction_id` if supported. 5. Prototype streaming if available. 6. Compare tool...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🪛 markdownlint-cli2 (0.22.1)
docs/ANTIGRAVITY_PHASE0_BASELINE.md
[warning] 538-538: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/ANTIGRAVITY_API_SPEC.md
[warning] 58-58: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/ARCHITECTURE.md
[warning] 69-69: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Shellcheck (0.11.0)
scripts/setup-opencode-pi.sh
[warning] 30-30: schema is referenced but not assigned.
(SC2154)
🔇 Additional comments (45)
.github/ISSUE_TEMPLATE/bug_report.yml (1)
44-50: LGTM!index.ts (1)
6-7: LGTM!src/plugin/accounts.test.ts (1)
1851-1851: LGTM!script/test-regression.ts (1)
55-57: LGTM!src/plugin/config/updater.test.ts (1)
69-70: LGTM!Also applies to: 238-238
src/plugin/config/loader.ts (1)
108-127: LGTM!script/test-models.ts (1)
6-6: LGTM!Also applies to: 10-22, 93-93, 100-100
scripts/check-quota.mjs (1)
94-210: LGTM!CHANGELOG.md (1)
3-72: LGTM!src/plugin/quota.ts (1)
16-227: LGTM!docs/ANTIGRAVITY_API_SPEC.md (1)
23-76: LGTM!src/constants.endpoint.test.ts (1)
1-124: LGTM!src/plugin/request.ts (1)
758-1567: LGTM!scripts/setup-opencode-pi.sh (1)
28-160: LGTM!src/plugin/transport/cli-transport.test.ts (1)
1-224: LGTM!src/plugin/version.ts (1)
107-129: LGTM!docs/TROUBLESHOOTING.md (1)
33-57: LGTM!Also applies to: 454-476, 506-541
src/plugin/config/models.ts (2)
41-60: LGTM!Also applies to: 66-75
61-65: ⚡ Quick winConfirm Antigravity quota-based
limitvalues forantigravity-gpt-oss-120b-medium
src/plugin/config/models.tssetsantigravity-gpt-oss-120b-medium.limittocontext: 200000, output: 64000(same as the Claude “thinking” entries). The plugin code does not appear to readmodel.limitwhen constructing the AntigravitygenerationConfig(token caps are set elsewhere, e.g.CLAUDE_THINKING_MAX_OUTPUT_TOKENS), so a mismatch would mainly impact any downstream UI/token-budgeting that consumes this config. Iflimitis meant to mirror the Antigravity quota view, confirm these numbers against the quota row before merge.docs/SUPPORT_MATRIX.md (1)
1-172: LGTM!src/plugin/transform/model-resolver.ts (1)
218-247: LGTM!Also applies to: 278-290
src/plugin/transport/managed-agent-transport.test.ts (1)
1-270: LGTM!docs/CONFIGURATION.md (1)
247-356: LGTM!docs/MODEL-VARIANTS.md (1)
1-75: LGTM!src/plugin/transport/gateway-transport.ts (1)
1-104: LGTM!src/plugin/transport/types.ts (1)
1-109: LGTM!docs/MULTI-ACCOUNT.md (1)
15-58: LGTM!src/plugin/transport/managed-agent-transport.ts (1)
1-238: LGTM!src/plugin/config/schema.ts (1)
274-287: LGTM!Also applies to: 443-487, 550-552
src/antigravity/oauth.test.ts (1)
1-535: LGTM!src/plugin/transform/model-resolver.test.ts (1)
120-131: LGTM!Also applies to: 188-196
assets/antigravity.schema.json (1)
338-381: LGTM!Also applies to: 385-434
README.md (1)
9-16: LGTM!Also applies to: 77-77, 100-100, 111-131, 141-273, 460-462, 598-601, 631-631, 676-685, 688-689, 724-724
docs/ANTIGRAVITY_AUTH_RECOVERY_PLAN.md (1)
1-161: LGTM!src/plugin/transport/agy-cli.ts (1)
1-36: LGTM!Also applies to: 55-160
src/plugin/transport/gateway-transport.test.ts (1)
1-212: LGTM!script/test-gemini-cli-e2e.sh (1)
6-7: LGTM!Also applies to: 118-120, 133-134
src/plugin/transport/agy-cli.test.ts (1)
1-184: LGTM!docs/ANTIGRAVITY_CLI_MIGRATION_PLAN.md (1)
13-787: LGTM!docs/ARCHITECTURE.md (1)
50-60: LGTM!Also applies to: 65-67, 80-127, 135-136
src/plugin/version.test.ts (1)
16-34: LGTM!Also applies to: 69-110
src/plugin/config/models.test.ts (1)
13-38: LGTM!src/antigravity/oauth.ts (1)
148-228: LGTM!Also applies to: 324-394
src/plugin.ts (1)
252-267: LGTM!Also applies to: 2090-2113, 2501-2507, 2583-2633, 3149-3161, 3353-3368
src/constants.ts (1)
20-20: LGTM!Also applies to: 28-67, 79-114
| "dangerously_skip_permissions": { | ||
| "default": true, | ||
| "type": "boolean" |
There was a problem hiding this comment.
Set dangerously_skip_permissions default to false.
This is currently secure-by-default inverted for an experimental transport. Keep it explicit opt-in only.
Suggested fix
"dangerously_skip_permissions": {
- "default": true,
+ "default": false,
"type": "boolean"
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "dangerously_skip_permissions": { | |
| "default": true, | |
| "type": "boolean" | |
| "dangerously_skip_permissions": { | |
| "default": false, | |
| "type": "boolean" |
🤖 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 `@assets/antigravity.schema.json` around lines 382 - 384, Change the JSON
schema for the experimental transport so the property
"dangerously_skip_permissions" is opt-in: locate the
"dangerously_skip_permissions" property in assets/antigravity.schema.json and
change its "default" value from true to false; ensure the property's "type"
remains "boolean" and run schema validation/tests to confirm no other code
assumes the old default.
| ## Recommended Immediate Next Step | ||
|
|
||
| Start Phase 1 with tests first: | ||
|
|
||
| 1. Add OAuth URL/body tests for current behavior. | ||
| 2. Add `openid` and redirect-mode support. | ||
| 3. Verify local callback still works. | ||
| 4. Only then experiment with official hosted callback. | ||
|
|
||
| This keeps the highest-risk auth change small, testable, and reversible. |
There was a problem hiding this comment.
Resolve the phase-status contradiction in the final action section.
Line 790 says to “Start Phase 1,” but Line 153 already marks Phase 1 as complete. This will confuse readers about current execution state.
📝 Suggested wording update
-## Recommended Immediate Next Step
-
-Start Phase 1 with tests first:
+## Recommended Immediate Next Step (for new migration cycles)
+
+If this roadmap is reused for a future migration cycle, start with Phase 1 tests first:🤖 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 `@docs/ANTIGRAVITY_CLI_MIGRATION_PLAN.md` around lines 788 - 797, The document
contradicts itself by saying “Start Phase 1 with tests first:” under the "##
Recommended Immediate Next Step" header while an earlier section already marks
Phase 1 complete; update the wording to match the actual state — either change
"Start Phase 1 with tests first:" to "Begin Phase 2 with tests first:" (keeping
the existing 1–4 checklist: OAuth tests, add openid/redirect-mode, verify local
callback, experiment with hosted callback) or, if Phase 1 is not actually
complete, remove the earlier "Phase 1 complete" marker so the current
instruction remains correct; ensure the header and the checklist consistently
reference the same phase ("Phase 1" or "Phase 2") throughout the doc.
| ``` | ||
| OpenCode request | ||
| └─ plugin.ts (fetch interceptor) | ||
| ├─ account selection, quota rotation, rate limiting, retries | ||
| └─ gatewayTransport | ||
| ├─ matches() — request recognition | ||
| ├─ getRequestMetadata() — model/family extraction | ||
| ├─ prepareRequest() — delegates to prepareAntigravityRequest() | ||
| └─ transformResponse() — delegates to transformAntigravityResponse() | ||
| ``` |
There was a problem hiding this comment.
Add a language tag to the fenced block to satisfy markdown lint.
Line 69 opens a fenced block without a language identifier.
🧹 Minimal fix
-```
+```text
OpenCode request
└─ plugin.ts (fetch interceptor)
├─ account selection, quota rotation, rate limiting, retries
└─ gatewayTransport
├─ matches() — request recognition
├─ getRequestMetadata() — model/family extraction
├─ prepareRequest() — delegates to prepareAntigravityRequest()
└─ transformResponse() — delegates to transformAntigravityResponse()</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 69-69: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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 `@docs/ARCHITECTURE.md` around lines 69 - 78, The fenced code block in the
ARCHITECTURE.md snippet is missing a language tag; update the block opener to
include a language identifier (e.g., "text" or "txt") so the markdown linter
passes—leave the content unchanged (the diagram referencing plugin.ts and
gatewayTransport methods: matches(), getRequestMetadata(), prepareRequest() /
prepareAntigravityRequest(), transformResponse() /
transformAntigravityResponse()) and only add the language tag to the initial ```
fence.
| > **⚠️ Gemini CLI sunset: 2026-06-18.** The `gemini-cli` quota pool stops serving requests for Google AI Pro/Ultra and free Gemini Code Assist individuals after this date. If requests fail after June 18, disable `quota_fallback` in your config. | ||
|
|
There was a problem hiding this comment.
Troubleshooting points to a deprecated no-op setting.
This guidance tells users to disable quota_fallback, but that key is documented as ignored. Replace with actionable advice (for example, transport selection/model migration guidance).
🤖 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 `@README.md` around lines 686 - 687, The README currently instructs users to
"disable `quota_fallback`" even though `quota_fallback` is a deprecated no-op;
update the Gemini CLI sunset note to remove that recommendation and replace it
with actionable guidance — mention `gemini-cli` sunset date and advise concrete
next steps such as choosing an alternate transport (e.g., switch from
quota-based transport to authenticated Google AI transport), migrating to
supported models or tiers (Google AI Pro/Ultra alternatives), and updating any
config fields that actually affect routing (call out the `quota_fallback` key as
deprecated/ignored and recommend the real config keys or workflows to change).
Ensure the copy explicitly references the `quota_fallback` key as deprecated and
provides clear migration/transport selection steps and links to relevant docs or
config keys.
| # | ||
| # Models tested: | ||
| # 1. Gemini (google/antigravity-gemini-3-pro-low, gemini-3-flash) | ||
| # 1. Gemini (google/antigravity-gemini-3.1-pro-low, gemini-3.5-flash-medium) |
There was a problem hiding this comment.
Fix the model ID typo in the header comment.
The second model in the comment is missing the google/antigravity- prefix, which can confuse manual reruns/copy-paste from this script.
Proposed fix
-# 1. Gemini (google/antigravity-gemini-3.1-pro-low, gemini-3.5-flash-medium)
+# 1. Gemini (google/antigravity-gemini-3.1-pro-low, google/antigravity-gemini-3.5-flash-medium)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # 1. Gemini (google/antigravity-gemini-3.1-pro-low, gemini-3.5-flash-medium) | |
| # 1. Gemini (google/antigravity-gemini-3.1-pro-low, google/antigravity-gemini-3.5-flash-medium) |
🤖 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 `@script/test-cross-model-e2e.sh` at line 6, Update the header comment that
lists the Gemini models to correct the second model ID by adding the missing
google/antigravity- prefix so both entries match the full model IDs (change
"gemini-3.5-flash-medium" to "google/antigravity-gemini-3.5-flash-medium" in the
comment line that starts with "1. Gemini").
| .replace(/([?&]code=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // OAuth state as query/body params. State is now opaque, but still sensitive enough to redact. | ||
| .replace(/([?&]state=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // Authorization codes as JSON keys ("code=...":"...") | ||
| .replace(/"code=[^"]*"(\s*:\s*"[^"]*")?/gi, '"code=[REDACTED]"') | ||
| // Authorization codes as JSON fields | ||
| .replace(/"code"\s*:\s*"[^"]+"/gi, '"code":"[REDACTED]"') | ||
| // OAuth state as JSON fields | ||
| .replace(/"state"\s*:\s*"[^"]+"/gi, '"state":"[REDACTED]"') | ||
| // Refresh tokens (common patterns in JSON error bodies) | ||
| .replace(/"refresh_token"\s*:\s*"[^"]+"/gi, '"refresh_token":"[REDACTED]"') | ||
| .replace(/(refresh_token=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // Access tokens | ||
| .replace(/"access_token"\s*:\s*"[^"]+"/gi, '"access_token":"[REDACTED]"') | ||
| .replace(/(access_token=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // ID tokens and client secrets | ||
| .replace(/"id_token"\s*:\s*"[^"]+"/gi, '"id_token":"[REDACTED]"') | ||
| .replace(/(id_token=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| .replace(/"client_secret"\s*:\s*"[^"]+"/gi, '"client_secret":"[REDACTED]"') | ||
| .replace(/(client_secret=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // Bearer tokens in Authorization headers | ||
| .replace(/(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi, "$1[REDACTED]") | ||
| // PKCE verifiers (code_verifier= query/body param) | ||
| .replace(/(code_verifier=)[^&\s"']+/gi, "$1[REDACTED]") | ||
| // PKCE challenges (code_challenge= query param) | ||
| .replace(/(code_challenge=)[^&\s"']+/gi, "$1[REDACTED]"); |
There was a problem hiding this comment.
Redaction misses sensitive params at start-of-string.
Line 31 and related patterns only match ?code=/&code= style params. Inputs like code=... or state=... at string start bypass redaction.
🔒 Suggested regex hardening
- .replace(/([?&]code=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])code=[^&\s"']+/gi, "$1code=[REDACTED]")
- .replace(/([?&]state=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])state=[^&\s"']+/gi, "$1state=[REDACTED]")
...
- .replace(/(refresh_token=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])refresh_token=[^&\s"']+/gi, "$1refresh_token=[REDACTED]")
- .replace(/(access_token=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])access_token=[^&\s"']+/gi, "$1access_token=[REDACTED]")
- .replace(/(id_token=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])id_token=[^&\s"']+/gi, "$1id_token=[REDACTED]")
- .replace(/(client_secret=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])client_secret=[^&\s"']+/gi, "$1client_secret=[REDACTED]")
- .replace(/(code_verifier=)[^&\s"']+/gi, "$1[REDACTED]")
+ .replace(/(^|[?&])code_verifier=[^&\s"']+/gi, "$1code_verifier=[REDACTED]")
- .replace(/(code_challenge=)[^&\s"']+/gi, "$1[REDACTED]");
+ .replace(/(^|[?&])code_challenge=[^&\s"']+/gi, "$1code_challenge=[REDACTED]");🤖 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/antigravity/oauth.ts` around lines 31 - 56, The current regexes only
match parameters when preceded by ? or &, so "code=..." or "state=..." at the
start of the string bypasses redaction; update each pattern that begins with
([?&]PARAM=) to allow start-of-string by changing it to
/(^|[?&])PARAM=[^&\s"']+/gi and change the replacement to include the captured
prefix and the param name (e.g., "$1code=[REDACTED]" for the patterns
referencing code), applying this change for code, state, refresh_token,
access_token, id_token, client_secret, code_verifier, and code_challenge in the
same replace chain in src/antigravity/oauth.ts so start-of-string params are
redacted.
| // Cache agy auth state per plugin session to avoid probing on every request. | ||
| // Null means not yet checked; "unknown" means probe was inconclusive. | ||
| let cachedAgyAuthState: "authenticated" | "unauthenticated" | "unknown" | null = null | ||
| let cachedAgyBinaryPath: string | null = null | ||
|
|
||
| return { | ||
| apiKey: "", | ||
| async fetch(input, init) { | ||
| if (!isGenerativeLanguageRequest(input)) { | ||
| if (!transport.matches(input)) { | ||
| return fetch(input, init); | ||
| } | ||
|
|
||
| // Non-OAuth transports skip account management entirely | ||
| if (!transport.auth.requiresOAuth) { | ||
| const debugLines: string[] = [] | ||
| const pushDebug = (line: string) => { | ||
| if (!isDebugEnabled()) return | ||
| debugLines.push(line) | ||
| } | ||
| pushDebug(`transport=${transport.id}`) | ||
|
|
||
| try { | ||
| const prepared = transport.prepareRequest({ | ||
| input, | ||
| init, | ||
| accessToken: "", | ||
| projectId: "", | ||
| headerStyle: "antigravity", | ||
| }) | ||
|
|
||
| let backendResponse: Response | ||
|
|
||
| if (transport.id === "cli") { | ||
| // CliTransport: execute agy binary. | ||
| // Binary detection and auth state are cached per plugin session | ||
| // to avoid spawning agy on every request. | ||
| if (cachedAgyBinaryPath === null) { | ||
| const configuredBinary = config.transport?.cli?.binary | ||
| const detectedBinary = configuredBinary ? null : await findAgyBinary() | ||
| cachedAgyBinaryPath = configuredBinary ?? detectedBinary?.path ?? "" | ||
| } | ||
| const binaryPath = cachedAgyBinaryPath | ||
| if (!binaryPath) { | ||
| return Response.json({ | ||
| error: { | ||
| code: 404, | ||
| status: "AGY_NOT_FOUND", | ||
| message: "Could not find agy binary. Install Antigravity CLI (https://antigravity.google/cli) or set transport.cli.binary in config.", | ||
| }, | ||
| }, { status: 404 }) | ||
| } | ||
|
|
||
| if (cachedAgyAuthState === null) { | ||
| cachedAgyAuthState = await checkAgyAuthState(binaryPath) | ||
| } | ||
| if (cachedAgyAuthState === "unauthenticated") { | ||
| return Response.json({ |
There was a problem hiding this comment.
Avoid sticky agy auth/binary cache failures across the whole session.
Line 1542 only probes auth when cache is null. If first probe returns unauthenticated (or no binary), this path remains blocked until plugin restart even after the user fixes it.
♻️ Recovery-friendly cache behavior
- if (cachedAgyBinaryPath === null) {
+ if (cachedAgyBinaryPath === null || cachedAgyBinaryPath === "") {
const configuredBinary = config.transport?.cli?.binary
const detectedBinary = configuredBinary ? null : await findAgyBinary()
cachedAgyBinaryPath = configuredBinary ?? detectedBinary?.path ?? ""
}
const binaryPath = cachedAgyBinaryPath
@@
- if (cachedAgyAuthState === null) {
+ if (cachedAgyAuthState !== "authenticated") {
cachedAgyAuthState = await checkAgyAuthState(binaryPath)
}🤖 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.ts` around lines 1490 - 1546, The current logic in the cli
transport block caches negative results permanently: cachedAgyBinaryPath and
cachedAgyAuthState are set even when no binary is found or when
checkAgyAuthState returns "unauthenticated", which blocks recovery until plugin
restart; change the caching policy so only positive findings are sticky: set
cachedAgyBinaryPath only when a valid binary path is found (leave it null if not
found) and set cachedAgyAuthState to "authenticated" only when checkAgyAuthState
returns that; do not cache "unauthenticated" (keep it null or "unknown") so
subsequent requests will re-run findAgyBinary() and checkAgyAuthState() and
allow recovery after the user installs or signs in; update the cli branch where
findAgyBinary(), cachedAgyBinaryPath and checkAgyAuthState() are used to
implement this behavior.
| function execFileText( | ||
| file: string, | ||
| args: string[], | ||
| timeoutMs: number, | ||
| ): Promise<AgyResult> { | ||
| return new Promise((resolve) => { | ||
| execFile(file, args, { timeout: timeoutMs }, (err, stdout, stderr) => { | ||
| const nodeErr = err as NodeJS.ErrnoException | null | ||
| resolve({ | ||
| stdout: String(stdout ?? ""), | ||
| stderr: String(stderr ?? ""), | ||
| exitCode: typeof nodeErr?.code === "number" ? nodeErr.code : err ? 1 : 0, | ||
| timedOut: Boolean((nodeErr as unknown as Record<string, unknown>)?.killed) || nodeErr?.code === "ETIMEDOUT", | ||
| }) | ||
| }) | ||
| }) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify current execFile option usage and absence/presence of maxBuffer in this module.
rg -n 'execFile\(' src/plugin/transport/agy-cli.ts -C2
rg -n 'maxBuffer' src/plugin/transport/agy-cli.ts || trueRepository: NoeFabris/opencode-antigravity-auth
Length of output: 304
Set maxBuffer for execFile in execFileText.
src/plugin/transport/agy-cli.ts calls execFile(file, args, { timeout: timeoutMs }, ...) without any maxBuffer setting (no maxBuffer found in the file). For large agy stdout/stderr, Node’s default buffering limit can be exceeded, leading to flaky CLI transport failures—add an explicit maxBuffer (or switch to streaming).
🤖 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/transport/agy-cli.ts` around lines 37 - 53, The execFileText
function calls execFile without a maxBuffer which can cause stdout/stderr
truncation for large outputs; update execFileText to pass a larger maxBuffer in
the options object passed to execFile (e.g., { timeout: timeoutMs, maxBuffer:
<suitable byte size> }) or switch execFile usage to a streaming approach (spawn
and stream stdout/stderr) if you expect arbitrarily large output; locate the
execFile call inside execFileText and either add the maxBuffer option or
refactor execFileText to use spawn and stream handling to avoid Node's default
buffer limit.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 89f3ed8e65
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const body = readJsonBody(ctx.init) | ||
| const input = extractInput(body) |
There was a problem hiding this comment.
Read Managed Agent input from RequestInfo body
prepareRequest only parses ctx.init.body, so calls that pass a Request object (with JSON body attached to ctx.input and init omitted) are treated as empty input and fail with "could not extract input text." Since the transport API accepts RequestInfo, this breaks valid managed-agent requests in the same interoperability scenario already handled elsewhere.
Useful? React with 👍 / 👎.
| */ | ||
| function getModelFamilyFromUrl(urlString: string): string { | ||
| const model = extractModelFromUrl(urlString) | ||
| return model?.includes("claude") ? "claude" : "gemini" |
There was a problem hiding this comment.
Classify gpt-oss separately from Gemini fallback pool
This family inference buckets every non-Claude model as gemini, which causes the new antigravity-gpt-oss-120b-medium path to participate in Gemini quota fallback logic (allowQuotaFallback), including switching to gemini-cli headers/endpoints when rate-limited. That fallback is incompatible with the gpt-oss model route and can turn recoverable Antigravity throttling into hard request failures for that model.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e39f134e4a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Non-OAuth transports skip account management entirely | ||
| if (!transport.auth.requiresOAuth) { |
There was a problem hiding this comment.
Allow non-OAuth transports to initialize without OAuth auth
The new cli/managed-agent transports are configured here as non-OAuth, but they still cannot run in an unauthenticated session because loader returns {} earlier when !isOAuthAuth(auth) (lines 1423–1429), so this fetch path is never installed in that scenario. In practice this makes the new non-OAuth transport feature unusable unless users already have OAuth credentials, which contradicts the transport auth contract and breaks the advertised flow for these backends.
Useful? React with 👍 / 👎.
| // 1. Try local agy binary (most accurate — reflects what's actually installed) | ||
| version = await tryLocalAgyVersion(); | ||
| if (version) { | ||
| source = "api"; | ||
| source = "local-agy"; |
There was a problem hiding this comment.
Prefer remote/latest version over local agy version for headers
This now prioritizes agy --version over the remote updater/changelog version. If a user has an older local agy binary, the plugin will send stale Antigravity version headers even when newer supported versions are available remotely, which can reintroduce the “version no longer supported” request failures this initializer is meant to prevent. The local binary version is not a safe source of truth for gateway compatibility.
Useful? React with 👍 / 👎.
| if (cachedAgyAuthState === null) { | ||
| cachedAgyAuthState = await checkAgyAuthState(binaryPath) | ||
| } | ||
| if (cachedAgyAuthState === "unauthenticated") { | ||
| return Response.json({ | ||
| error: { | ||
| code: 401, | ||
| status: "UNAUTHENTICATED", | ||
| message: "agy is not logged into Antigravity. Run `agy` manually in a terminal and complete the browser OAuth flow.", | ||
| }, | ||
| }, { status: 401 }) | ||
| } |
There was a problem hiding this comment.
Permanent auth lockout within the plugin session
Once cachedAgyAuthState is set to "unauthenticated", every subsequent request in that OpenCode session returns HTTP 401 — the cache is never invalidated. The error message tells users to "Run agy manually in a terminal and complete the browser OAuth flow," implying that action will unblock them. It won't: after they log in via agy, the next request still hits the cached "unauthenticated" guard and returns 401 again. The only recovery is restarting OpenCode entirely, which nothing in the error output hints at.
For contrast, the "unknown" state falls through to executeAgyCommand, which re-probes agy on every call and can recover naturally. The "unauthenticated" branch should either be given the same retry behaviour, or the error message must explicitly instruct the user to restart OpenCode after logging in.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin.ts
Line: 1542-1553
Comment:
**Permanent auth lockout within the plugin session**
Once `cachedAgyAuthState` is set to `"unauthenticated"`, every subsequent request in that OpenCode session returns HTTP 401 — the cache is never invalidated. The error message tells users to "Run `agy` manually in a terminal and complete the browser OAuth flow," implying that action will unblock them. It won't: after they log in via `agy`, the next request still hits the cached `"unauthenticated"` guard and returns 401 again. The only recovery is restarting OpenCode entirely, which nothing in the error output hints at.
For contrast, the `"unknown"` state falls through to `executeAgyCommand`, which re-probes agy on every call and can recover naturally. The `"unauthenticated"` branch should either be given the same retry behaviour, or the error message must explicitly instruct the user to restart OpenCode after logging in.
How can I resolve this? If you propose a fix, please make it concise.| return { | ||
| request: INTERACTIONS_ENDPOINT, | ||
| init: { |
There was a problem hiding this comment.
When
config.stream is true, prepareRequest sets streaming: true and transformResponse returns the backend response as-is (expecting SSE), but the outgoing request goes to INTERACTIONS_ENDPOINT without any streaming indicator. The Generative Language API requires ?alt=sse on the URL to switch to SSE format; without it the server returns a regular JSON body, which the streaming branch never parses. Every streaming request will silently deliver a raw JSON blob to the caller instead of the expected SSE event stream.
| return { | |
| request: INTERACTIONS_ENDPOINT, | |
| init: { | |
| const endpoint = config.stream | |
| ? `${INTERACTIONS_ENDPOINT}?alt=sse` | |
| : INTERACTIONS_ENDPOINT | |
| return { | |
| request: endpoint, | |
| init: { |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin/transport/managed-agent-transport.ts
Line: 184-186
Comment:
When `config.stream` is `true`, `prepareRequest` sets `streaming: true` and `transformResponse` returns the backend response as-is (expecting SSE), but the outgoing request goes to `INTERACTIONS_ENDPOINT` without any streaming indicator. The Generative Language API requires `?alt=sse` on the URL to switch to SSE format; without it the server returns a regular JSON body, which the streaming branch never parses. Every streaming request will silently deliver a raw JSON blob to the caller instead of the expected SSE event stream.
```suggestion
const endpoint = config.stream
? `${INTERACTIONS_ENDPOINT}?alt=sse`
: INTERACTIONS_ENDPOINT
return {
request: endpoint,
init: {
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41beb3dcbd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (cachedAgyBinaryPath === null) { | ||
| const configuredBinary = config.transport?.cli?.binary | ||
| const detectedBinary = configuredBinary ? null : await findAgyBinary() | ||
| cachedAgyBinaryPath = configuredBinary ?? detectedBinary?.path ?? "" | ||
| } |
There was a problem hiding this comment.
Re-probe agy binary after an initial miss
When findAgyBinary() fails once, this assignment caches "" in cachedAgyBinaryPath; subsequent requests skip detection because the guard only checks for null. In a common recovery path (user installs agy or fixes PATH after the first failure), the plugin keeps returning AGY_NOT_FOUND for the rest of the session, even though the binary is now available.
Useful? React with 👍 / 👎.
| }, | ||
| body: JSON.stringify(requestBody), | ||
| }, | ||
| streaming: config.stream, |
There was a problem hiding this comment.
Derive managed-agent streaming from request semantics
This transport marks every request as streaming purely from static config, but prepareRequest does not include any stream directive in the outbound Interactions payload. In transformResponse, prepared.streaming=true bypasses normalization and returns the raw backend response, so enabling transport.managed_agent.stream can return an Interactions-native payload instead of Gemini-compatible candidates output, breaking callers that rely on the plugin’s normalized response shape.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/plugin/transform/model-resolver.ts (1)
233-236: 💤 Low valueDead ternary — both branches return
"low".
defaultThinkingLevelevaluates to"low"regardless of whether the model starts withgemini-3.5-flash, so the conditional and the dedicated comment about 3.5-flash add no behavior. Either collapse to a constant, or — if Pro and 3.5-Flash defaults are expected to diverge later — pick the intended distinct value now so the special case is real.♻️ Suggested simplification
- if (isEffectiveGemini3) { - const defaultThinkingLevel = resolvedModel.toLowerCase().startsWith("gemini-3.5-flash") - ? "low" - : "low"; - - return { - actualModel: resolvedModel, - thinkingLevel: defaultThinkingLevel, + if (isEffectiveGemini3) { + return { + actualModel: resolvedModel, + thinkingLevel: "low", isThinkingModel: true, quotaPreference, explicitQuota, }; }🤖 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/transform/model-resolver.ts` around lines 233 - 236, The ternary assigning defaultThinkingLevel under the isEffectiveGemini3 branch is dead (both outcomes are "low"); replace the conditional with a plain constant assignment (const defaultThinkingLevel = "low") and remove or update any 3.5-flash-specific comment, or if you intend a different default for gemini-3.5-flash, change the second branch to the correct value; update references to isEffectiveGemini3/resolvedModel accordingly so the special-case no longer implies differing behavior.docs/MODEL-VARIANTS.md (1)
61-66: ⚡ Quick winClarify the Claude section wording to avoid “thinking” ambiguity.
Line 63 says “Current Claude Thinking rows,” but Line 65 lists
google/antigravity-claude-sonnet-4-6(non-thinking). Renaming this subsection/body text would avoid misinterpretation.🤖 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 `@docs/MODEL-VARIANTS.md` around lines 61 - 66, The wording "Claude thinking" is ambiguous because the list includes both non-thinking and thinking model IDs (e.g., google/antigravity-claude-sonnet-4-6 and google/antigravity-claude-opus-4-6-thinking); rename the subsection and rephrase the sentence to clarify that these are Claude model entries and that models with a "-thinking" suffix indicate higher-budget variants, and explicitly state the plugin behavior that it enables the high-budget "thinking" variant by default when no tier/budget is provided (update the text around "Current Claude Thinking rows are direct model IDs" to something like "Claude model entries and thinking-budget variants" and add the note about "-thinking" suffix and plugin default).
🤖 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 @.github/ISSUE_TEMPLATE/bug_report.yml:
- Around line 46-47: The dropdown in .github/ISSUE_TEMPLATE/bug_report.yml
contains a duplicated option "antigravity-gemini-3.5-flash-low"; update that
second entry to the intended variant (e.g.,
"antigravity-gemini-3.5-flash-medium" per the PR and smoke-test) or remove the
duplicate so the list matches the actual keys exposed by
OPENCODE_MODEL_DEFINITIONS / resolver aliases; ensure the final set of options
aligns with the model names used elsewhere (flash-medium/flash-high) to avoid
duplicate/incorrect choices.
In `@docs/MODEL-VARIANTS.md`:
- Around line 11-12: Remove the duplicate Gemini 3.5 Flash (Low) quota row and
ensure the model ID google/antigravity-gemini-3.5-flash-low appears only once;
consolidate the repeated row name at line 28 into a single entry and resolve the
conflicting thinkingLevel mappings by choosing the correct thinkingLevel value
for google/antigravity-gemini-3.5-flash-low and updating the thinkingLevel key
so each model ID maps to exactly one thinkingLevel; verify no other duplicate
rows remain and keep the table entries and model→thinkingLevel mapping
consistent.
---
Nitpick comments:
In `@docs/MODEL-VARIANTS.md`:
- Around line 61-66: The wording "Claude thinking" is ambiguous because the list
includes both non-thinking and thinking model IDs (e.g.,
google/antigravity-claude-sonnet-4-6 and
google/antigravity-claude-opus-4-6-thinking); rename the subsection and rephrase
the sentence to clarify that these are Claude model entries and that models with
a "-thinking" suffix indicate higher-budget variants, and explicitly state the
plugin behavior that it enables the high-budget "thinking" variant by default
when no tier/budget is provided (update the text around "Current Claude Thinking
rows are direct model IDs" to something like "Claude model entries and
thinking-budget variants" and add the note about "-thinking" suffix and plugin
default).
In `@src/plugin/transform/model-resolver.ts`:
- Around line 233-236: The ternary assigning defaultThinkingLevel under the
isEffectiveGemini3 branch is dead (both outcomes are "low"); replace the
conditional with a plain constant assignment (const defaultThinkingLevel =
"low") and remove or update any 3.5-flash-specific comment, or if you intend a
different default for gemini-3.5-flash, change the second branch to the correct
value; update references to isEffectiveGemini3/resolvedModel accordingly so the
special-case no longer implies differing behavior.
🪄 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: 2d011a99-d5b4-4477-9268-e1c175e55548
📒 Files selected for processing (18)
.github/ISSUE_TEMPLATE/bug_report.ymlCHANGELOG.mdREADME.mddocs/ANTIGRAVITY_AUTH_RECOVERY_PLAN.mddocs/MODEL-VARIANTS.mddocs/MULTI-ACCOUNT.mddocs/SUPPORT_MATRIX.mddocs/TROUBLESHOOTING.mdscript/test-cross-model-e2e.shscript/test-gemini-cli-e2e.shscript/test-models.tsscript/test-regression.tsscripts/setup-opencode-pi.shsrc/plugin/config/models.test.tssrc/plugin/config/models.tssrc/plugin/config/updater.test.tssrc/plugin/transform/model-resolver.test.tssrc/plugin/transform/model-resolver.ts
✅ Files skipped from review due to trivial changes (5)
- docs/MULTI-ACCOUNT.md
- docs/SUPPORT_MATRIX.md
- CHANGELOG.md
- docs/TROUBLESHOOTING.md
- docs/ANTIGRAVITY_AUTH_RECOVERY_PLAN.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 (12)
script/test-cross-model-e2e.sh (2)
6-6: 💤 Low valueHeader comment still missing
google/antigravity-prefix on the second model id.After the rename to
gemini-3.5-flash-low, the second entry in the header listing is still bare and inconsistent with the first. This was previously flagged and not addressed in this revision.🛠️ Proposed fix
-# 1. Gemini (google/antigravity-gemini-3.1-pro-low, gemini-3.5-flash-low) +# 1. Gemini (google/antigravity-gemini-3.1-pro-low, google/antigravity-gemini-3.5-flash-low)
206-206: LGTM!Also applies to: 246-246
src/plugin/config/updater.test.ts (1)
70-70: LGTM!Also applies to: 238-238
script/test-models.ts (1)
6-21: LGTM!Also applies to: 101-101
script/test-gemini-cli-e2e.sh (1)
1-12: LGTM!Also applies to: 118-119, 133-134
src/plugin/config/models.ts (1)
40-71: ⚡ Quick winQuota-row count diverges from PR description (6 here vs. "7 quota rows" in objectives).
PR objectives list 7 Antigravity rows including
antigravity-gemini-3.5-flash-medium,antigravity-gemini-3.5-flash-high, andantigravity-claude-sonnet-4-6-thinking, plus mentionflash-mediumas the validated smoke-test target. This file exposes 6 rows (onlyflash-low, only the non--thinkingSonnet). If the consolidation to single live rows + resolver aliases is intentional, please update the PR description and bug-report dropdown to match; otherwise, the missing rows need to be added back here.src/plugin/transform/model-resolver.ts (1)
196-204: LGTM!Also applies to: 261-274, 293-305
script/test-regression.ts (1)
55-57: ConfirmGEMINI_FLASH_CLI_QUOTAremoval has no remaining referencesSearch across the repository shows zero occurrences of
GEMINI_FLASH_CLI_QUOTA, so there shouldn’t be any stale imports/usage remaining.src/plugin/transform/model-resolver.test.ts (1)
9-12: LGTM!Also applies to: 138-167, 205-211
scripts/setup-opencode-pi.sh (1)
71-73: LGTM!Also applies to: 122-124
README.md (1)
9-9: LGTM!Also applies to: 117-120, 126-127, 180-182, 231-233, 443-443, 581-583
src/plugin/config/models.test.ts (1)
18-22: LGTM!Also applies to: 26-30, 33-33
| - antigravity-gemini-3.5-flash-low | ||
| - antigravity-gemini-3.5-flash-low |
There was a problem hiding this comment.
Duplicate dropdown option — second flash-low likely meant flash-medium or flash-high.
Both entries are identical, so the dropdown has two indistinguishable rows. Either drop the duplicate or replace one with the intended variant (the PR objectives reference both flash-medium and flash-high, and the validated smoke-test in the PR description used antigravity-gemini-3.5-flash-medium).
🛠️ Proposed fix
- antigravity-gemini-3.1-pro-low
- antigravity-gemini-3.1-pro-high
- antigravity-gemini-3.5-flash-low
- - antigravity-gemini-3.5-flash-low
+ - antigravity-gemini-3.5-flash-medium
+ - antigravity-gemini-3.5-flash-high
- antigravity-claude-sonnet-4-6
+ - antigravity-claude-sonnet-4-6-thinking
- antigravity-claude-opus-4-6-thinking
- antigravity-gpt-oss-120b-mediumAdjust the added rows to match whatever is actually exposed by OPENCODE_MODEL_DEFINITIONS / resolver aliases.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - antigravity-gemini-3.5-flash-low | |
| - antigravity-gemini-3.5-flash-low | |
| - antigravity-gemini-3.5-flash-low | |
| - antigravity-gemini-3.5-flash-medium | |
| - antigravity-gemini-3.5-flash-high |
🤖 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 @.github/ISSUE_TEMPLATE/bug_report.yml around lines 46 - 47, The dropdown in
.github/ISSUE_TEMPLATE/bug_report.yml contains a duplicated option
"antigravity-gemini-3.5-flash-low"; update that second entry to the intended
variant (e.g., "antigravity-gemini-3.5-flash-medium" per the PR and smoke-test)
or remove the duplicate so the list matches the actual keys exposed by
OPENCODE_MODEL_DEFINITIONS / resolver aliases; ensure the final set of options
aligns with the model names used elsewhere (flash-medium/flash-high) to avoid
duplicate/incorrect choices.
| | Gemini 3.5 Flash (Low) | `google/antigravity-gemini-3.5-flash-low` | | ||
| | Gemini 3.5 Flash (Low) | `google/antigravity-gemini-3.5-flash-low` | |
There was a problem hiding this comment.
Fix duplicate and contradictory Gemini 3.5 Flash documentation entries.
Line 11 and Line 12 duplicate the same quota row/model ID, Line 28 repeats the same row name twice, and Line 34/Line 35 map the same model ID to two different thinkingLevel values. This is internally inconsistent and likely to confuse model selection/migration.
Suggested doc fix
-| Gemini 3.5 Flash (Low) | `google/antigravity-gemini-3.5-flash-low` |
-| Gemini 3.5 Flash (Low) | `google/antigravity-gemini-3.5-flash-low` |
+| Gemini 3.5 Flash (Low) | `google/antigravity-gemini-3.5-flash-low` |
-The current Antigravity quota UI exposes rows such as "Gemini 3.5 Flash (Low)" and "Gemini 3.5 Flash (Low)". OpenCode only treats configured model keys as selectable model IDs in all contexts, including scripts and agent configs. Direct IDs therefore avoid "Model not found" errors in non-interactive usage.
+The current Antigravity quota UI exposes rows such as "Gemini 3.5 Flash (Low)". OpenCode only treats configured model keys as selectable model IDs in all contexts, including scripts and agent configs. Direct IDs therefore avoid "Model not found" errors in non-interactive usage.
-- `antigravity-gemini-3.5-flash-low` → API model `gemini-3.5-flash-low` + `thinkingLevel: "medium"`
-- `antigravity-gemini-3.5-flash-low` → API model `gemini-3.5-flash-low` + `thinkingLevel: "high"`
+- `antigravity-gemini-3.5-flash-low` → API model `gemini-3.5-flash-low` + `thinkingLevel: "low"`
+- `antigravity-gemini-3.5-flash-medium` / `antigravity-gemini-3.5-flash-high` → alias to `gemini-3.5-flash-low` + `thinkingLevel: "low"`Also applies to: 28-28, 34-35
🤖 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 `@docs/MODEL-VARIANTS.md` around lines 11 - 12, Remove the duplicate Gemini 3.5
Flash (Low) quota row and ensure the model ID
google/antigravity-gemini-3.5-flash-low appears only once; consolidate the
repeated row name at line 28 into a single entry and resolve the conflicting
thinkingLevel mappings by choosing the correct thinkingLevel value for
google/antigravity-gemini-3.5-flash-low and updating the thinkingLevel key so
each model ID maps to exactly one thinkingLevel; verify no other duplicate rows
remain and keep the table entries and model→thinkingLevel mapping consistent.
|
so? |
|
Not trying to spam, but I've merged similar PR (#576) to https://github.com/insign/opencode-antigravity-auth-updated and it is easy available using |
|
@insign if you want a cleaner deploy, reset your main to chrisgeo/opencode-antigravity-auth#main It'll eliminate any extraneous changes that may be causing the spam. |
Summary
openid, redirect modes, safer opaque PKCE state storage, broader redaction, and auth recovery docs.agyCLI and Managed Agents transports.Current Antigravity models
google/antigravity-gemini-3.1-pro-lowgoogle/antigravity-gemini-3.1-pro-highgoogle/antigravity-claude-sonnet-4-6-thinkinggoogle/antigravity-claude-opus-4-6-thinkinggoogle/antigravity-gpt-oss-120b-mediumgoogle/antigravity-gemini-3.5-flash-mediumgoogle/antigravity-gemini-3.5-flash-highValidation
npm run typechecknpm run buildnpm test— 1132 passed, 25 todogoogle/antigravity-gemini-3.5-flash-mediumpassedNotes
cliandmanaged-agenttransports are opt-in/experimental and documented as separate agent backends.