Add Antigravity (agy) provider via an ACP compatibility bridge#4497
Add Antigravity (agy) provider via an ACP compatibility bridge#4497agentool wants to merge 1 commit into
Conversation
Antigravity ships no native agent protocol: `agy agent stdio` is not a
thing, and the bundled `language_server` speaks Codeium gRPC rather than
ACP. So this adds a bridge that presents the ACP surface
`AcpSessionRuntime` needs and runs each turn through the documented
non-interactive `agy --print`.
The bridge ships as hidden subcommands of the server binary (`t3 agy-acp`,
`t3 agy-hook`) so it always versions with the server and needs no separate
artifact.
A live event stream is reconstructed from two documented Antigravity
sources that correlate on step index (a hook's `stepIdx` is the transcript
record's `step_index`):
- Hooks (PreToolUse/PostToolUse/Stop) supply tool name, arguments and
completion status. They are registered through a throwaway `--add-dir`
workspace, so nothing is written into the user's repository. Both the
session cwd and that hook workspace are passed, because `--add-dir`
replaces the workspace rather than extending cwd -- passing only the
hook dir hides the project from the agent.
- The trajectory transcript supplies assistant text and real tool output
as the turn runs. Its format is undocumented, so every parse path
degrades to emitting nothing rather than failing a turn.
File contents for an edit diff are captured inside the hook process. The
bridge cannot read them when it drains hook output: both hooks for a fast
edit land within a single poll interval, by which point "before" would
read back as "after".
Any `agy` subcommand spawned for a probe sets `stdin: "ignore"`. `agy`
starts a language server and emits nothing while stdin stays open, so the
default "pipe" hangs it and model discovery returns empty.
Known constraints, all inherent to print mode and documented in AGENTS.md:
tools auto-approve (`--dangerously-skip-permissions`) so no approval flow
is possible; no image attachments; no session modes; the model binds at
spawn, so `sessionModelSwitch` is "unsupported".
The three ProviderRegistry fixtures assert an exact provider list or that
only the subject provider probes, so they gain the new driver.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 5 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.
| return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId) | ||
| ? sessionId | ||
| : undefined; | ||
| } |
There was a problem hiding this comment.
Tool output dropped by drain order
Medium Severity
When the session map is missing or unreadable, lookupConversationId (lines 94-102) treats any UUID-formatted sessionId as an Antigravity conversation ID. This can cause session/load to incorrectly attempt resuming a conversation with the bridge's internal session ID instead of starting fresh.
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.
| } | ||
| const condensed = reported.replace(/transcript_full\.jsonl$/, "transcript.jsonl"); | ||
| return NodeFS.existsSync(condensed) ? condensed : reported; | ||
| } |
There was a problem hiding this comment.
Transcript path switch reuses offset
Medium Severity
resolveTranscriptPath can switch from transcript_full.jsonl to transcript.jsonl mid-turn while transcriptOffset keeps the prior file's byte position. Reads then skip or misalign early condensed records, dropping assistant text and tool output for that turn.
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.
| input.assistantText.emitted = true; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Tool output lost after post hook
High Severity
Each drain processes hooks before the transcript, and postToolUseUpdate removes the step from activeToolCalls. Transcript tool output only attaches while that step is still active, so when PostToolUse and the matching transcript record arrive in the same poll—common for fast tools—command and search output is dropped permanently. Post hooks never carry tool bodies, so there is no fallback.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.
| cancelledSessions.add(sessionId); | ||
| } | ||
| activeChild?.kill("SIGTERM"); | ||
| return; |
There was a problem hiding this comment.
Stale cancel poisons next turn
High Severity
session/cancel always adds the session to cancelledSessions, but that flag is only consumed at the end of runTurn. A cancel that arrives after a turn already finished—or while no child is running—stays set and makes the next successful prompt report stopReason: "cancelled".
Additional Locations (1)
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.
| issue: | ||
| "Turn requires non-empty text. Antigravity print mode does not accept attachments.", | ||
| }); | ||
| } |
There was a problem hiding this comment.
Turn starts before empty prompt check
Medium Severity
turn.started is emitted before the adapter rejects attachment-only or whitespace-only prompts. Those requests then fail validation with no matching turn.completed, so the turn can remain in progress in the UI even though Antigravity never accepted the prompt.
Reviewed by Cursor Bugbot for commit df9a3f1. Configure here.


Adds
antigravityas a provider driver alongside Codex, Claude, Cursor, Grok and OpenCode.Up front, re: CONTRIBUTING: this is large (+3442) and unsolicited, and I did not open an issue first. Opening it anyway as a working reference rather than a request for your time — if the answer is no, close it and it costs you nothing. Notes on scope and on splitting it are at the bottom.
Why this needs a bridge rather than another ACP driver
Antigravity ships no native agent protocol. Verified against
agy1.1.7:agy agent stdio→unexpected arguments: [stdio](Grok's entrypoint isgrok agent stdio)--acpflag; the binary carriesjsonrpc2and MCP, but no ACP methodsAntigravity.app/Contents/Resources/bin/language_serverspeaks Codeium gRPC (exa.language_server_pb), not ACPSo
provider/acp/antigravity/agyBridge.tspresents the ACP surfaceAcpSessionRuntimealready expects, and runs each turn through the documented non-interactiveagy --print. It ships as hidden subcommands of the server binary (t3 agy-acp,t3 agy-hook) so it versions with the server and adds no build artifact.How the event stream is reconstructed
Two documented Antigravity sources correlate on step index — a hook's
stepIdxis the transcript record'sstep_index:toolSummary)PreToolUsehookstep_indexPostToolUsehookPLANNER_RESPONSErecords as they landconversationIdfor resumeNeither source alone is sufficient: hooks never carry tool output, the transcript never carries tool arguments.
Three things that cost real debugging time
--add-dirreplaces the workspace, it does not extend cwd. Hooks are registered via a throwaway--add-dirworkspace so nothing is written into the user's repo — but passing only that dir makes the project invisible to the agent. Both the session cwd and the hook workspace are passed.Edit diffs must be captured inside the hook process. Both hooks for a fast edit land within one 50ms poll, so reading the file while draining hook output makes "before" read back as "after". The hook brackets the tool call and is the only place that sees true pre-edit state.
Probes must set
stdin: "ignore".agystarts a language server and emits nothing while stdin stays open;ChildProcessdefaultsstdinto"pipe", which hangs it. Presented asinstalled: true, models: 0whileagy modelsworked by hand.Known constraints
All inherent to print mode, documented in
AGENTS.md:--dangerously-skip-permissions); no approval flow is possiblesessionModelSwitchis"unsupported"The trajectory JSONL format is undocumented. Every parse path degrades to emitting nothing rather than failing a turn, so an
agyrelease that changes it costs observability, not correctness.UI surface
No new components. The provider renders through the existing rows:
PROVIDER_OPTIONS,PROVIDER_ICON_BY_PROVIDER, andPROVIDER_CLIENT_DEFINITIONS, reusing theAntigravityIconalready inIcons.tsxfor the editor integration, with anExperimentalbadge in the same slot Cursor and Grok use forEarly Access. CONTRIBUTING asks for before/after images on UI changes — I don't have a clean way to attach them here; the visible delta is one additional provider row.Verification
agyEvents,agyTranscript,AntigravityAcpSupportpnpm buildclean; bridge bundles intodist/bin.mjsand all three entrypoints work off the built binarystatus: ready | version: 1.1.7 | models: 11agy: tool calls, real tool output, a file edit with diff,stopReason: end_turn, file on disk actually changedThree
ProviderRegistryfixtures assert an exact provider list or that only the subject provider probes, so they gain the new driver.On size
Most of the diff is
AntigravityAdapter.ts(~690 lines), which follows the existing convention of one standalone adapter per provider (Cursor 1.2k, Grok 1.5k, Claude 3.9k) over the shared ACP helpers. I deliberately did not refactor a shared adapter core out ofGrokAdapter, since that would mean touching a working provider to land a new one.Happy to split this into (1) contracts + bridge + tests and (2) driver + UI wiring, or to drop the text-generation backend, if either would make it reviewable. Equally happy for you to take the bridge approach and reimplement it your way — the
--add-dir, hook-timing andstdinfindings above are the parts that were expensive to discover.Note
High Risk
Large new agent execution path that auto-approves tools via
--dangerously-skip-permissionsand shells out toagy; transcript parsing is best-effort so behavior can drift with CLI changes.Overview
Adds an experimental
antigravityprovider for the Antigravity CLI (agy), which has no native agent protocol. Sessions talk to a bundled ACP compatibility bridge (t3 agy-acp/t3 agy-hook) that runs each turn withagy --printand maps hook events plustranscript.jsonl(correlated by step index) into the same runtime events other ACP drivers use.Server: new driver, adapter, health/model discovery (
agy models/--versionwithstdin: "ignore"), spawn wiring viaAntigravityAcpSupport, optional git/text-generation through the bridge, and hidden CLI subcommands registered on thet3binary. Contracts & web:AntigravitySettings, defaults/aliases, settings form, picker row, and icon. Docs/tests:AGENTS.mdbridge constraints; unit tests for hooks/transcript parsing; registry tests disable or expect the new built-in instance.Reviewed by Cursor Bugbot for commit df9a3f1. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Antigravity (agy) provider via an ACP compatibility bridge
antigravityprovider driver that wraps theagyCLI tool using a stdio JSON-RPC bridge (t3 agy-acp) rather than native ACP, since Antigravity lacks a built-in ACP server.agyin print mode and reconstructs session events (tool calls, assistant text, file diffs) by polling hooks (t3 agy-hook) and tailing JSONL transcript files.TextGenerationsupport (commit messages, PR content, branch names, thread titles) with a 180-second timeout and structured JSON decoding.agy --versionandagy models, and an 'Experimental' badge in the provider picker UI.Macroscope summarized df9a3f1.