feat: gemini-cli as a codeoid backend over ACP (bundled, Google-subscription auth) - #143
Merged
Conversation
…ription auth) Fourth native harness backend: Google's gemini-cli driven over ACP (the Agent Client Protocol — standardized editor<->agent JSON-RPC/stdio; gemini-cli exposes it via the stable --acp flag). Auth is the user's Google-account OAuth in ~/.gemini (free tier / AI Pro / Code Assist) — subscription posture like claude/codex; codeoid never touches tokens. - providers/jsonrpc-stdio.ts: the codex transport generalized into a shared StdioJsonRpcProcess (codex/rpc.ts is now a thin wrapper baking in the app-server subcommand — all codex tests unchanged). - acp/index.ts: GeminiAcpProvider — session/new is the backing session, session/prompt resolves at turn end (stopReason -> turn_done; honest zero usage, ACP carries none), session/update chunks -> text/thinking deltas + tool_call/tool_call_update -> tool records, session/request_permission -> canUseTool (deny picks the reject option; fail-closed: no gate or no reject option -> cancelled; fs/terminal capabilities DECLINED at initialize and any stray request refused), session/cancel -> interrupt. Deliberately protocol-thin: any ACP agent can reuse the shape with a different binary. - Bundled: @google/gemini-cli@0.80->0.50.0 pinned optionalDependency (pure JS, runs under the daemon runtime — live smoke in tests); resolution config -> PATH -> bundled, with the #141 unavailable-hint path. buildGeminiCliEnv allowlist (GEMINI_/GOOGLE_/LC_ + *_API_KEY). - Config providers.geminiCli {enabled, command}; provider id gemini-cli (distinct from the stateless gemini API backend). No wire changes. Tests: fake-acp fixture (long-running session/prompt answered at turn end, permission options, cancellation) driving A1-A9 + resolution/ registry states + live bundled smoke. Registry catalog test updated for the bundled backend.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #143 +/- ##
==========================================
+ Coverage 82.55% 82.81% +0.25%
==========================================
Files 101 104 +3
Lines 17404 17722 +318
==========================================
+ Hits 14368 14676 +308
- Misses 3036 3046 +10
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
🤖 Gemini code reviewThe implementation of the Gemini ACP provider is very well-structured and generic. However, a potential reliability issue was identified in the shared stdio JSON-RPC transport where synchronous write errors on a destroyed stdin stream can crash the host daemon. Findings: 🔴 0 · 🟠 1 · 🟡 0 · 🟢 0
Tokens spent · ⬆️ Input: 18,980 · ⬇️ Output: 285 · Σ Total: 26,663 |
…i review) write() on a destroyed stream throws synchronously — the #exited flag and the stdin error listener only cover the async paths. All frame writes now go through a #write helper that swallows the throw (exit handler owns diagnostics) and routes request-path write errors to the pending rejection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The fourth native harness backend: Google's gemini-cli, driven over ACP (Agent Client Protocol — the standardized editor↔agent JSON-RPC/stdio protocol; gemini-cli exposes it via its stable
--acpflag). Auth is the user's Google-account OAuth living in~/.gemini(free tier / AI Pro / Code Assist) — the same subscription posture as claude and codex; codeoid never touches tokens. Design + spike findings:docs/provider-gemini-acp-design.md(notably: there is no official Antigravity SDK — the community package by that name is an IDE-extension kit pointing the wrong way; ACP is the sanctioned machine surface).Design
providers/jsonrpc-stdio.ts(StdioJsonRpcProcess);codex/rpc.tsis now a thin wrapper baking in theapp-serversubcommand. All codex tests pass unchanged — same wire behavior, one implementation.GeminiAcpProvider(acp/index.ts), deliberately protocol-thin so any ACP-speaking agent can become a backend with a different binary + registry entry:session/new {cwd}→ backing session id;session/promptis the long-running request whose result is the turn boundary (stopReason→turn_done; usage reported as honest zeros — ACP carries none).session/update→agent_message_chunk/agent_thought_chunkstream as text/thinking deltas;tool_call/tool_call_updatebecome tool records (ACP tool kinds map to codeoid names: execute→Bash, read→Read, …).session/request_permission→canUseTool— deny picks the agent's reject option; fail-closed throughout: no gate wired or no reject option offered →cancelled;fs/*andterminal/*client capabilities are declined at initialize (gemini-cli falls back to its own tools, all permission-gated) and any stray server request is refused, not guessed.session/cancel→ interrupt (turn resolvesstopReason: "cancelled"— covered by a test).@google/gemini-cli@0.50.0pinned as anoptionalDependency(pure JS — runs under the daemon's own runtime, proven by a live smoke test). Resolution: config → PATH → bundled, with the feat: bundle pi so the backend works with zero install #141 supported-but-unavailable hint path.buildGeminiCliEnvallowlist (GEMINI_/GOOGLE_/LC_+*_API_KEY;~/.geminivia HOME).gemini-cli, distinct from the statelessgeminiAPI backend. No wire changes.Tests
fake-acpfixture models the ACP shape faithfully —session/promptstays pending until the turn script finishes, permission requests carry allow/reject options, cancellation flips the hanging turn. A1–A9 cover streaming + stopReason, permission allow/deny round-trips, non-gated tool pairs, the structured history seed (one-shot), interrupt-as-cancel, fail-closed unknown requests, missing binary, and lifecycle; plus resolution order, registry activation/unavailable/disabled, and the live bundled smoke. Coverage checked locally before pushing this time:acp/index.ts100% lines,resolve.ts93%, shared transport 99%.Known limits (in the design doc): no
session/loadresume yet (the canonical-history seed carries context instead), no model catalog (ACP has none — gemini-cli picks from its own config), plan/mode updates ignored for now. A live smoke needs a Google-logged-in gemini-cli.bun run test(1267 pass),typecheck,lintgreen.🤖 Generated with Claude Code