@estebanforge/pi-antigravity-bridge 1.6.2 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/extensions/index.ts +17 -8
- package/package.json +5 -21
- package/src/approval-hook.ts +116 -98
- package/src/driver.ts +6 -1
- package/docs/ACP-ADOPTION-PLAN.md +0 -940
- package/docs/ACP-PROTOCOL-REFERENCE.md +0 -462
- package/docs/ANTIGRAVITY-INTEGRATIONS.md +0 -50
- package/docs/APPROVAL-GATE.md +0 -33
- package/docs/ARCHITECTURE.md +0 -116
- package/docs/DEVELOPMENT.md +0 -110
- package/docs/ENGINES.md +0 -46
- package/docs/PI-BRIDGE-GAPS.md +0 -97
- package/docs/TODO.md +0 -21
|
@@ -1,940 +0,0 @@
|
|
|
1
|
-
# ACP Adoption Plan: Official Google `antigravity-acp` Server
|
|
2
|
-
|
|
3
|
-
Status: PROPOSED. Phase 0 COMPLETE + Phase 1 COMPLETE (2026-09-03): ACP engine
|
|
4
|
-
implemented behind `config.engine` (default off), full suite green, live smoke
|
|
5
|
-
PASS through the full stack. Gate F VERIFIED live (`scripts/smoke-acp-bridge.mjs`):
|
|
6
|
-
the real server lists bridge tools and completes a tool call through the
|
|
7
|
-
registered mcpServers entry. §6 parity run LIVE on both engines: 14/14
|
|
8
|
-
(`scripts/parity-live.mjs`). Phase-1 acceptance: ALL `[x]` (docs included).
|
|
9
|
-
Gates: A PASS, B ABSENT (managed — streaming engine retained
|
|
10
|
-
until upstream ships usage), C PASS, D FAIL on RC01 (kill+reload fallback
|
|
11
|
-
VERIFIED live, incl. the stale-exit race fix), E PASS, F PASS (verified
|
|
12
|
-
live 2026-09-03). Verdicts in section 8.1; full captured protocol data in
|
|
13
|
-
[ACP-PROTOCOL-REFERENCE.md](./ACP-PROTOCOL-REFERENCE.md); raw traffic
|
|
14
|
-
gitignored in `probe-logs/`.
|
|
15
|
-
Peer review 1: Claude, 2026-09-03. Verdict PROCEED WITH CHANGES. Findings 1-6
|
|
16
|
-
integrated: third round-trip kind for permissions (P1), parked-overall-timer
|
|
17
|
-
pause (P1), cumulative-resend guard port, deferred-capability dispositions,
|
|
18
|
-
capability-posture prose, concurrency note.
|
|
19
|
-
Peer review 2: Antigravity (agy), 2026-09-03. Verdict PROCEED WITH CHANGES.
|
|
20
|
-
7 findings integrated: Gate A made a blocking gate for the default flip (the
|
|
21
|
-
ACP binary takes no model flags, so the recycle fallback could not carry a
|
|
22
|
-
model), sessions re-keyed per engine (`@acp` suffix) after the engine-field
|
|
23
|
-
design was shown to erase streaming bindings on rollback, parked-timer pause
|
|
24
|
-
changed to remaining-budget semantics, acp-permission plumbing specified
|
|
25
|
-
through a TurnDriver interface, session/cancel + session/close pulled into
|
|
26
|
-
phase 1, AskAntigravity migration moved from phase 3 to phase 4.
|
|
27
|
-
Peer reviews 3-4 (plan-stage second rounds, Claude and agy): findings folded
|
|
28
|
-
into the two entries above and the section 8/9 design; no separate deltas.
|
|
29
|
-
Peer review 5 (implementation): Antigravity (agy), 2026-09-03. Verdict
|
|
30
|
-
PROCEED WITH CHANGES. 7 findings, all valid, all fixed: P0 jsonrpc line
|
|
31
|
-
buffering (stdio chunks are not newline-aligned; partial frames were dropped),
|
|
32
|
-
P1 tool args preserved through tool_done, P1 typed protocol errors survive
|
|
33
|
-
translation (cancelSupported stuck null), P1 parked-deadline nulled on pause,
|
|
34
|
-
P2 tilde expansion, P2 per-turn config read dedup, P2 coverage gaps filled.
|
|
35
|
-
Peer review 6 (post-build): Claude, 2026-09-03, isolated and read-only.
|
|
36
|
-
Verdict PROCEED WITH CHANGES. 6 findings, 5 valid, all fixed: P1 bridge 403
|
|
37
|
-
gate had no vitest coverage (HTTP-level test added: no header / wrong-length /
|
|
38
|
-
same-length wrong token → 403, correct → 200), P1 sessionKey recorded the
|
|
39
|
-
config engine instead of the selected driver's (fixed), P2 arm-time park
|
|
40
|
-
left a stale deadline (fixed: paused-from-birth invariant), P2 duplicated
|
|
41
|
-
timeout body (extracted), P2 abort-before-prompt probed cancel (now guarded
|
|
42
|
-
by promptStarted). Sixth finding (untracked parity script) resolved by
|
|
43
|
-
commit.
|
|
44
|
-
|
|
45
|
-
Adopt the official Google ACP server (`agy_acp_server.par`, registry id
|
|
46
|
-
`antigravity-acp`) as a second turn engine for the bridge, behind a config
|
|
47
|
-
switch. The existing stream-json engine stays the default until the ACP
|
|
48
|
-
engine proves parity. Every change is an improvement or a one-to-one
|
|
49
|
-
replacement.
|
|
50
|
-
|
|
51
|
-
STANDING DECISION (user, 2026-09-07): BOTH engines are permanently
|
|
52
|
-
maintained peers. The streaming engine is never deleted - no phase removes
|
|
53
|
-
it, regardless of upstream progress (including Gate B).
|
|
54
|
-
|
|
55
|
-
Cross-references: [ARCHITECTURE.md](./ARCHITECTURE.md),
|
|
56
|
-
[PI-BRIDGE-GAPS.md](./PI-BRIDGE-GAPS.md), [DEVELOPMENT.md](./DEVELOPMENT.md).
|
|
57
|
-
|
|
58
|
-
## 1. Decision summary
|
|
59
|
-
|
|
60
|
-
| Question | Answer |
|
|
61
|
-
| --- | --- |
|
|
62
|
-
| Adopt? | Yes, phased, behind `config.engine: "acp"` |
|
|
63
|
-
| Why | Protocol-native permissions, image prompts, thought text, graceful cancel, session resume/list, sanctioned auth path, stable public protocol |
|
|
64
|
-
| Why not a rewrite | The provider layer (G1 digest, G10 system prompt, G9 park/resume, pi event mapping) is engine-agnostic and already proven. The driver is the only engine-coupled part |
|
|
65
|
-
| Default flip | Phase 4, after a soak release with both engines |
|
|
66
|
-
| Regression guard | Parity checklist (section 6) must be all `[x]` before the default flips |
|
|
67
|
-
|
|
68
|
-
## 2. Verified evidence
|
|
69
|
-
|
|
70
|
-
All facts below were verified live on 2026-09-03, not taken from docs. Probe
|
|
71
|
-
artifacts live in `~/tmp/agy-acp-probe/` (binary, handshake transcripts).
|
|
72
|
-
|
|
73
|
-
### 2.1 The registry entry
|
|
74
|
-
|
|
75
|
-
Source: `agentclientprotocol/registry`, path `antigravity-acp/agent.json`
|
|
76
|
-
(folder contains only `agent.json` + `icon.svg`).
|
|
77
|
-
|
|
78
|
-
| Field | Value |
|
|
79
|
-
| --- | --- |
|
|
80
|
-
| id | `antigravity-acp` |
|
|
81
|
-
| name / publisher | Google Antigravity / Google LLC, proprietary |
|
|
82
|
-
| version | 1.0.0 |
|
|
83
|
-
| build | `agy_acp_server_20260818_01_RC01` |
|
|
84
|
-
| binaries | darwin-aarch64, linux-x86_64, linux-aarch64, windows-x86_64, windows-aarch64 |
|
|
85
|
-
| linux cmd | `./agy_acp_server.par`, registry args `["--uid="]` |
|
|
86
|
-
| flags | `--[no]debug`, `--[no]notices` only. No model/effort/conversation flags |
|
|
87
|
-
|
|
88
|
-
The registry README states agents are CI-verified to return valid
|
|
89
|
-
`authMethods` in the handshake, and the index is re-fetched hourly.
|
|
90
|
-
|
|
91
|
-
### 2.2 Live initialize response
|
|
92
|
-
|
|
93
|
-
Sent:
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{"fs":{"readTextFile":true,"writeTextFile":true},"terminal":false}}}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Got (abridged to capability names):
|
|
100
|
-
|
|
101
|
-
```json
|
|
102
|
-
{"protocolVersion":1,
|
|
103
|
-
"agentCapabilities":{
|
|
104
|
-
"loadSession":true,
|
|
105
|
-
"promptCapabilities":{"image":true,"audio":true,"embeddedContext":true},
|
|
106
|
-
"mcpCapabilities":{"http":true,"sse":true},
|
|
107
|
-
"sessionCapabilities":{"list":{},"resume":{}},
|
|
108
|
-
"auth":{"logout":{}}},
|
|
109
|
-
"authMethods":[
|
|
110
|
-
{"id":"oauth-personal","name":"Log in with Google"},
|
|
111
|
-
{"id":"oauth-business","name":"Log in with Gemini Enterprise"},
|
|
112
|
-
{"id":"gemini-api-key","name":"Gemini API key"},
|
|
113
|
-
{"id":"agent-platform","name":"Gemini Enterprise Agent Platform"}],
|
|
114
|
-
"agentInfo":{"name":"antigravity-acp","title":"Google Antigravity",
|
|
115
|
-
"version":"agy_acp_server_20260818_01_RC01"}}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### 2.3 Unauthenticated session/new
|
|
119
|
-
|
|
120
|
-
`session/new` returned `-32000 Authentication required` with the full recipe:
|
|
121
|
-
call `authenticate`, or set `auth.type` in
|
|
122
|
-
`~/.gemini/antigravity-acp/settings.json`. Accepted settings types:
|
|
123
|
-
`oauth-personal`, `gemini-api-key` (reads `GEMINI_API_KEY`), `oauth-business`
|
|
124
|
-
(needs `gcp.project` + `gcp.location`), `agent-platform` (ADC or
|
|
125
|
-
`GOOGLE_API_KEY`, project/location from `GOOGLE_CLOUD_PROJECT` /
|
|
126
|
-
`GOOGLE_CLOUD_LOCATION`). Confirmed by the official Zed setup page
|
|
127
|
-
(`antigravity.google/docs/ide/extensions/zed/`), which publishes exactly these
|
|
128
|
-
`settings.json` shapes.
|
|
129
|
-
|
|
130
|
-
### 2.4 Binary
|
|
131
|
-
|
|
132
|
-
1,529,513,909 bytes ELF x86-64, plus a 117 MB `localharness_external`
|
|
133
|
-
sibling. Cold start measured at a few seconds on this machine (handshake
|
|
134
|
-
answered well inside the probe timeout).
|
|
135
|
-
|
|
136
|
-
### 2.5 ACP v1 method surface
|
|
137
|
-
|
|
138
|
-
From `agentclientprotocol/agent-client-protocol` schema source (`v1/agent.rs`,
|
|
139
|
-
`v1/client.rs`):
|
|
140
|
-
|
|
141
|
-
- Client to agent: `initialize`, `authenticate`, `session/new`, `session/load`,
|
|
142
|
-
`session/prompt`, `session/cancel`, `session/list`, `session/resume`,
|
|
143
|
-
`session/fork`, `session/close`, `session/delete`, `session/set_mode`,
|
|
144
|
-
`session/set_config_option`.
|
|
145
|
-
- Agent to client (requests): `session/request_permission`,
|
|
146
|
-
`fs/read_text_file`, `fs/write_text_file`, `terminal/create`, `terminal/kill`,
|
|
147
|
-
`terminal/output`, `terminal/release`, `terminal/wait_for_exit`.
|
|
148
|
-
- Agent to client (notifications): `session/update`.
|
|
149
|
-
- Extension namespace observed in schema: `nes/*` (IDE edit surfaces). Ignore
|
|
150
|
-
for this plan.
|
|
151
|
-
|
|
152
|
-
### 2.6 Governance
|
|
153
|
-
|
|
154
|
-
`zed-industries/zed#57221` records the chain: Zed maintainers declined a
|
|
155
|
-
standalone SDK integration, waited for Google, and Google shipped the official
|
|
156
|
-
server. The same thread documents the Antigravity FAQ position that
|
|
157
|
-
third-party access to an Antigravity login violates ToS. The community
|
|
158
|
-
adapters carry that risk. Google's own server is the sanctioned client
|
|
159
|
-
channel. Our undocumented stream-json driver carries the same class of risk
|
|
160
|
-
today. Adoption retires it.
|
|
161
|
-
|
|
162
|
-
Also dated in that thread: Gemini CLI / Code Assist stop serving 2026-06-18.
|
|
163
|
-
`agy` is the only first-party CLI going forward, and its stream-json dialect
|
|
164
|
-
is an unmaintained contract. ACP is the maintained one.
|
|
165
|
-
|
|
166
|
-
## 3. Current architecture inventory and disposition
|
|
167
|
-
|
|
168
|
-
| Module | Role today | Disposition under ACP |
|
|
169
|
-
| --- | --- | --- |
|
|
170
|
-
| `src/provider.ts` | streamSimple: pi Context to agy turn to pi events; G9 round-trips; G1 digest; G10 system prompt | KEEP unchanged (additive thought-delta `if` only). Engine-agnostic by contract |
|
|
171
|
-
| `src/driver.ts` | persistent stream-json process, turn queue, recycle, timers | KEEP permanently - both engines are maintained peers |
|
|
172
|
-
| `src/stream-events.ts` | NDJSON parser + usage mapping | KEEP permanently - both engines are maintained peers |
|
|
173
|
-
| `src/sessions.ts` | pi session to agy conversation store | KEEP. Add `engine` tag (section 9.4) |
|
|
174
|
-
| `src/config.ts` | runtime config | KEEP. Add engine + acp block (section 9.5) |
|
|
175
|
-
| `src/models.ts` | `agy models` to pi Model projection | KEEP. Catalog source stays the CLI until ACP exposes one (probe A.6) |
|
|
176
|
-
| `src/mcp-server.ts` | bridge HTTP MCP server; G9 park | KEEP unchanged. Registered via `mcpServers` under ACP |
|
|
177
|
-
| `src/skills.ts` | `activate_skill` bridge | KEEP unchanged |
|
|
178
|
-
| `src/native-tools.ts` | agy read-only steps to pi builtins | KEEP through phase 2. Phase 3 re-evaluates against `tool_call` content (gate C) |
|
|
179
|
-
| `WrapperReplay` (provider.ts) | display-only `antigravity` wrapper tool | Same: re-evaluate in phase 3 (gate C) |
|
|
180
|
-
| `src/diff-render.ts` | git-sourced diffs for agy edits | KEEP while agy self-executes edits (our fs capabilities off) |
|
|
181
|
-
| `src/ask-tool.ts` | AskAntigravity one-shot via `agy -p` | MIGRATE to ACP one-shot in phase 3 |
|
|
182
|
-
| `src/discovery.ts` | snapshot-diff + `/proc` fd-scan conversation binding | DELETE in phase 3 (ACP returns real session ids) |
|
|
183
|
-
| `src/patch-cleanup.ts` | pre-1.3.0 patch cleanup | KEEP unrelated |
|
|
184
|
-
| `extensions/index.ts` | registration, `/agy` command, notices | EXTEND: engine switch, acp auth command, doctor rebuild |
|
|
185
|
-
|
|
186
|
-
## 4. Capability matrix
|
|
187
|
-
|
|
188
|
-
Verdicts: IMPROVEMENT (strictly better), PARITY (equal), RISK (may regress,
|
|
189
|
-
mitigation required). Originally assessed pre-probe; verdict column SYNCED to
|
|
190
|
-
the Phase 0 results (§8.1, 2026-09-03). Pre-probe reasoning for any row lives
|
|
191
|
-
in git history.
|
|
192
|
-
|
|
193
|
-
| Dimension | Bridge today (stream-json) | Official ACP | Verdict |
|
|
194
|
-
| --- | --- | --- | --- |
|
|
195
|
-
| Wire contract | Undocumented NDJSON, shapes captured live, cumulative-resend heuristic, `OK`/`SUCCESS` mapping | Public versioned protocol, negotiated handshake | IMPROVEMENT |
|
|
196
|
-
| Text streaming | `text_delta` + dedupe guard | `agent_message_chunk` deltas, native | PARITY |
|
|
197
|
-
| Thinking | Token count only, floor 64, no text body | `agent_thought_chunk` carries text | IMPROVEMENT |
|
|
198
|
-
| Tool call visibility | start/done/error + native re-exec + wrapper replay | `tool_call` / `tool_call_update` with kind, status, content, locations, rawInput/output | IMPROVEMENT (VERIFIED: diffs arrive in content; Gate C PASS — machinery retirement confirmed for phase 3) |
|
|
199
|
-
| Permissions | `skipPermissions: true` default, `--dangerously-skip-permissions`, commands run unreviewed | `session/request_permission` flows to the client | PARITY under adoption (`auto` policy, 9.3). The primitive exists for whoever gates later; per-tool gating stays extension-owned via G9 |
|
|
200
|
-
| Images in prompt | Dropped in `extractUserPrompt` | `promptCapabilities.image: true` | IMPROVEMENT (VERIFIED end-to-end, run 6: "Red") |
|
|
201
|
-
| Audio | Dropped | `promptCapabilities.audio: true` | IMPROVEMENT (low priority) |
|
|
202
|
-
| Session resume | `sessions.json` + `--conversation` flag, per pi session only | `session/load`, `list`, `resume`, server-side | IMPROVEMENT (load VERIFIED across restart, run 6; full-text replay rules in 9.2) |
|
|
203
|
-
| Cancel | Kill process group; in-flight turn dies | `session/cancel` to `stopReason: cancelled`, process survives | **REGRESSION-MANAGED (Gate D FAIL on RC01): cancel NOT implemented.** Fallback kill + `session/load` VERIFIED; re-check per build |
|
|
204
|
-
| Process lifecycle | One agy child per provider; recycle on model/effort/mode/cwd/conversation drift | One server hosts N sessions | IMPROVEMENT |
|
|
205
|
-
| Model + effort selection | CLI flags + recycle | `session/set_config_option` (`configId`) | PASS (VERIFIED live, Gate A): per-session switching, no recycle |
|
|
206
|
-
| Usage tokens | `toPiUsage` from step events | Not in any payload (Gate B FINAL) | **ABSENT on RC01.** Zero-usage documented and ACCEPTED for the flip (user decision 2026-09-07: Gate B no longer blocks the default). Both engines are permanently maintained - no deletion |
|
|
207
|
-
| MCP tools (G9) | Our HTTP bridge server via `--add-dir` config | `mcpServers` param (`{name,type:"http",url,headers:[]}`) | PARITY at shape level (verified). Phase-1 acceptance: bridge `tools/list`+`tools/call` end-to-end |
|
|
208
|
-
| Skills | `--disable-slash-commands`; bridge owns skills | Unknown slash behavior; `available_commands_update` exists | PARITY. Keep our bridge; probe F.7 |
|
|
209
|
-
| G1 digest, G10 system prompt | Provider-side prompt assembly | Same (we compose the prompt either way) | PARITY. `embeddedContext` is a later enhancement |
|
|
210
|
-
| Diagnostics | `/agy doctor`: snapshot, lifecycle, recycle stats | Nothing equivalent | PARITY work: rebuild on ACP events (section 10) |
|
|
211
|
-
| Auth | Piggybacks `agy` CLI login state | First-class: 4 methods, `authenticate`, `logout`, settings.json | IMPROVEMENT. One-time re-login cost |
|
|
212
|
-
| One-shot delegation (AskAntigravity) | `agy -p` + snapshot-diff + `/proc` fd-scan | `session/new` + `prompt`, real ids | IMPROVEMENT. Deletes discovery.ts |
|
|
213
|
-
| ToS exposure | Undocumented CLI driving | Sanctioned Google client channel | IMPROVEMENT |
|
|
214
|
-
|
|
215
|
-
## 5. Improvements in detail
|
|
216
|
-
|
|
217
|
-
1. **Permission flow.** Today any agy `run_command` executes unreviewed; the
|
|
218
|
-
config comment says so in plain words. ACP makes approval a protocol
|
|
219
|
-
primitive (`session/request_permission`, verified live). Under the single
|
|
220
|
-
`auto` policy (9.3) adoption is parity; the primitive is in place for
|
|
221
|
-
whoever wants to gate later.
|
|
222
|
-
2. **Thought text.** `agent_thought_chunk` delivers the model's actual
|
|
223
|
-
thinking text. Today pi renders `[thinking]` labels and token counts only.
|
|
224
|
-
Provider change is additive: extend the `thought` activity with an optional
|
|
225
|
-
`delta` field (9.2).
|
|
226
|
-
3. **Images.** `promptCapabilities.image` lets us forward pi image blocks as
|
|
227
|
-
ACP image content instead of dropping them in `extractUserPrompt`.
|
|
228
|
-
Community reports say the `agy` CLI itself had broken image upload, so the
|
|
229
|
-
live probe (A.4) verifies end-to-end delivery before we claim this.
|
|
230
|
-
4. **Graceful cancel.** `session/cancel` converts to a clean
|
|
231
|
-
`stopReason: cancelled` prompt response. Today abort kills the process
|
|
232
|
-
group and orphans the turn. Maps onto pi's `aborted` stop reason.
|
|
233
|
-
5. **Server-side sessions.** `session/load` restores a conversation after a
|
|
234
|
-
pi restart without our store being the source of truth, and
|
|
235
|
-
`session/list` / `session/resume` make `/agy conversations`-style tooling
|
|
236
|
-
possible later. Sessions outlive the process; no recycle on drift.
|
|
237
|
-
6. **Protocol stability.** `initialize` negotiates `protocolVersion`. Unknown
|
|
238
|
-
fields degrade instead of silently misparsing (compare: the 1.3.2 sqlite
|
|
239
|
-
incident, issue #1).
|
|
240
|
-
7. **Sanctioned channel.** Section 2.6. Risk of account action and of silent
|
|
241
|
-
dialect drift both drop.
|
|
242
|
-
8. **One-shot cleanup.** `discovery.ts` exists only because `agy -p` never
|
|
243
|
-
prints its conversation id. ACP returns real session ids. The
|
|
244
|
-
snapshot-diff + `/proc` fd-scan machinery and its ambiguity heuristics get
|
|
245
|
-
deleted.
|
|
246
|
-
9. **Enterprise auth.** `oauth-business` / `agent-platform` bring VPC-SC and
|
|
247
|
-
data-residency posture the CLI path never exposed to us.
|
|
248
|
-
10. **Deferred, deliberately.** `session/fork` (future multi-branch feature),
|
|
249
|
-
`session/close` / `session/delete` (candidates for a later
|
|
250
|
-
`/agy conversations` cleanup command), `terminal/*` and client-side `fs/*`
|
|
251
|
-
delegation declined: agy keeps executing its own commands and file ops as
|
|
252
|
-
today (parity), and answering them would put execution inside our process
|
|
253
|
-
for no parity gain; our terminal and fs client capabilities stay false.
|
|
254
|
-
`nes/*` IDE-edit extension (ignore), `audio` prompts (phase 2, optional).
|
|
255
|
-
|
|
256
|
-
## 6. Parity contract (no-regression checklist)
|
|
257
|
-
|
|
258
|
-
Every box must be `[x]` on the ACP engine before phase 4 flips the default.
|
|
259
|
-
Tested with the parity suite (section 11) and `scripts/parity-live.mjs`
|
|
260
|
-
(live, both engines: 14/14, 2026-09-03).
|
|
261
|
-
|
|
262
|
-
- [x] Text streams token-adjacent to streaming (no full-text re-sends) — live
|
|
263
|
-
both engines, delta stream + cumulative-resend guard held
|
|
264
|
-
- [x] Multi-turn conversation continuity via `session/load` or our store —
|
|
265
|
-
live: ACP `session/load` (history suppressed, clean reply), streaming
|
|
266
|
-
`--conversation` resume; the provider's session store supplies the id
|
|
267
|
-
- [x] Turn serialization: two concurrent streamSimple calls never interleave
|
|
268
|
-
— live both engines (queue releases only on settle) + driver tests
|
|
269
|
-
- [x] Bridge tool round-trip (G9) works: bridge MCP `tools/call` parks, pi
|
|
270
|
-
executes, `toolResult` resumes the same agy turn — live both engines
|
|
271
|
-
through the real bridge server; the pi-side park/resume is engine-
|
|
272
|
-
independent (proven live on stream-json; the ACP parity run answers
|
|
273
|
-
deps directly to isolate the agy-side HTTP client)
|
|
274
|
-
- [x] Idle timer suspends while a G9 park is open, resumes on `kickIdle` —
|
|
275
|
-
fake-server tests (park/kickIdle remaining-budget deadline)
|
|
276
|
-
- [x] Overall turn timeout (10m) and inactivity timeout (5m) still fire and
|
|
277
|
-
fail the turn visibly — driver tests (deadline fires with remaining
|
|
278
|
-
budget after resume); inactivity shares the timer machinery
|
|
279
|
-
- [x] Abort: pi user abort produces `aborted`, the server process survives,
|
|
280
|
-
the next turn on the session works — live both engines (aborted=true,
|
|
281
|
-
recovery turn OK). "Process survives" holds on NEITHER engine and is
|
|
282
|
-
the documented Gate D behavior: streaming kills the child; RC01 has no
|
|
283
|
-
cancel, ACP tears down after the -32601 probe and reloads next turn
|
|
284
|
-
- [x] pi session restart resumes the right conversation (engine-tagged) —
|
|
285
|
-
engine-scoped key tests + live `session/load`
|
|
286
|
-
- [x] Engine rollback preserves the other engine's conversation bindings
|
|
287
|
-
(engine-scoped keys, 9.4) — sessions tests (per-entry engine field
|
|
288
|
-
rejected precisely because set() would erase the streaming binding)
|
|
289
|
-
- [x] Model catalog: same `antigravity/*` model ids and effort tiers resolve
|
|
290
|
-
— shared provider catalog, engine-independent by construction
|
|
291
|
-
- [x] Model/effort switch takes effect (gate A mechanism) — live: ACP
|
|
292
|
-
`set_config_option` on a LOADED session; streaming recycle+resume
|
|
293
|
-
- [x] G1 digest and G10 system prompt reach the prompt identically — shared
|
|
294
|
-
prompt assembly in the provider; the driver receives the final prompt
|
|
295
|
-
- [x] Skills `activate_skill` answered by the bridge as today — bridge
|
|
296
|
-
server dep, same server serves both engines (ACP transport live)
|
|
297
|
-
- [x] Usage counters: present (mapped) or documented-absent (zero-usage),
|
|
298
|
-
per gate B — live: streaming mapped, ACP absent (Gate B row in the
|
|
299
|
-
parity matrix)
|
|
300
|
-
- [x] `/agy doctor` shows connection state, session id, prompt/session stats,
|
|
301
|
-
lifecycle log — implemented engine-aware (phase 1); re-verify in pi
|
|
302
|
-
before the phase 4 default flip
|
|
303
|
-
- [x] Error paths: spawn failure, auth failure, protocol error all surface as
|
|
304
|
-
visible turn errors, never as silent empty messages — fake tests
|
|
305
|
-
(auth-required, load-fails) + live: a bad-shape registration surfaced
|
|
306
|
-
as a visible `ACP session failed: Invalid params` turn error in the
|
|
307
|
-
first parity attempt, exactly as designed
|
|
308
|
-
- [x] `ask-tool` one-shot returns text, duration, abort/timeout states, and a
|
|
309
|
-
resumable session id — unchanged `agy -p` path (phase-2 probe
|
|
310
|
-
decides whether it moves to ACP)
|
|
311
|
-
- [x] Overall-turn timer pauses while any round-trip is parked; a slow human
|
|
312
|
-
permission decision cannot kill the turn — fake tests (park/kickIdle
|
|
313
|
-
remaining budget)
|
|
314
|
-
- [x] Cumulative-resend defensive guard on message chunks (port of
|
|
315
|
-
`isCumulativeResend`), with a fake-server test. Note: provably inert
|
|
316
|
-
on live RC01 (run-5 stress showed pure mid-token deltas); the fake
|
|
317
|
-
server is the only surface that can exercise it — confirmed inert
|
|
318
|
-
again in the live parity run
|
|
319
|
-
|
|
320
|
-
## 7. Regression risks and mitigations
|
|
321
|
-
|
|
322
|
-
| Risk | Impact | Mitigation |
|
|
323
|
-
| --- | --- | --- |
|
|
324
|
-
| Usage tokens absent (CONFIRMED, Gate B) | Cost/token display zeros on ACP | ACCEPTED 2026-09-07 (user decision): Gate B no longer blocks the default flip - zero-usage is documented behavior on ACP. Both engines are permanently maintained; no deletion (standing decision), so zero-usage is opt-in per user forever (review 4, finding 2, as amended) |
|
|
325
|
-
| ~~No model/effort switch per session~~ RESOLVED: Gate A PASS | — | `session/set_config_option` verified live; per-session switching, no recycle |
|
|
326
|
-
| Slash commands expanded server-side | Could double-expand with our prompt assembly | Probe F.7. If present: keep our prefixes out of command-looking lines, or ignore server command list |
|
|
327
|
-
| `request_permission` with no pi-side permission UI | Cannot render a native dialog | Single `auto` policy (parity with `skipPermissions: true`); per-tool gating for pi tools belongs to the tools/extensions and is preserved end-to-end by G9 (9.3). Never hang |
|
|
328
|
-
| Human decision latency on parked G9 tool round-trips exceeds the 10m overall-turn cap | Turn killed mid-wait | `AcpDriver` pauses the overall timer while parked, re-armed with REMAINING budget; every park carries its own timeout (9.3) |
|
|
329
|
-
| Binary size (1.5 GB + 117 MB) | Disk + update churn | Pinned install layout (section 12), registry pin by build id |
|
|
330
|
-
| aarch64 TCMalloc startup failure (forum report, Chromebook) | arch-specific | x86_64 unaffected; gate install per-arch, link the forum issue in README |
|
|
331
|
-
| Separate auth state from `agy` CLI | First-run auth friction | `/agy auth-manual` prints exact instructions; `gemini-api-key` path works headless via `GEMINI_API_KEY`. The agent never writes credentials |
|
|
332
|
-
| Thought text changes rendering volume | Noisy transcript | Route through the existing thinking block pipeline, close-on-switch unchanged; no new block types |
|
|
333
|
-
| Two engines drift on behavior | Confusing support surface | Shared provider layer + shared parity suite run against both engines in CI |
|
|
334
|
-
|
|
335
|
-
## 8. Phase 0: probes and decision gates
|
|
336
|
-
|
|
337
|
-
One authenticated live session answers every UNKNOWN. No product code in this
|
|
338
|
-
phase. Deliverable: findings appended to this doc as section 8.1 (or
|
|
339
|
-
`docs/ACP-PROBE-NOTES.md`), and each gate marked PASS / FALLBACK.
|
|
340
|
-
|
|
341
|
-
Probe scripts (JSON-RPC over stdio, one object per line):
|
|
342
|
-
|
|
343
|
-
```jsonc
|
|
344
|
-
// P1 handshake with MINIMAL client capabilities (our phase-1 posture)
|
|
345
|
-
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{"fs":{"readTextFile":false,"writeTextFile":false},"terminal":false}}}
|
|
346
|
-
|
|
347
|
-
// P2 auth (pick one; api-key path is headless)
|
|
348
|
-
// export GEMINI_API_KEY=... first
|
|
349
|
-
{"jsonrpc":"2.0","id":1,"method":"authenticate","params":{"method":"gemini-api-key"}}
|
|
350
|
-
|
|
351
|
-
// P3 session + bridge registration (exact mcpServers param shape is itself a probe item)
|
|
352
|
-
{"jsonrpc":"2.0","id":2,"method":"session/new","params":{"cwd":"/abs/cwd","mcpServers":[{"name":"pi-bridge","type":"http","url":"http://127.0.0.1:<port><path>","headers":[]}]}}
|
|
353
|
-
|
|
354
|
-
// P4 model/effort switch attempts, in order until one works
|
|
355
|
-
{"jsonrpc":"2.0","id":3,"method":"session/set_config_option","params":{"sessionId":"<sid>","configOptionId":"model","value":"<slug>"}}
|
|
356
|
-
{"jsonrpc":"2.0","id":4,"method":"session/set_config_option","params":{"sessionId":"<sid>","configOptionId":"effort","value":"high"}}
|
|
357
|
-
{"jsonrpc":"2.0","id":5,"method":"session/set_mode","params":{"sessionId":"<sid>","modeId":"<id>"}}
|
|
358
|
-
|
|
359
|
-
// P5 prompt: stream a simple prompt; capture every session/update verbatim
|
|
360
|
-
{"jsonrpc":"2.0","id":6,"method":"session/prompt","params":{"sessionId":"<sid>","prompt":[{"type":"text","text":"Say hello and list the files in this directory."}]}}
|
|
361
|
-
|
|
362
|
-
// P6 mid-stream cancel: send during P5, observe prompt response stopReason
|
|
363
|
-
{"jsonrpc":"2.0","id":7,"method":"session/cancel","params":{"sessionId":"<sid>"}}
|
|
364
|
-
|
|
365
|
-
// P7 image prompt (small png data URL), verify the model actually sees it
|
|
366
|
-
{"jsonrpc":"2.0","id":8,"method":"session/prompt","params":{"sessionId":"<sid>","prompt":[{"type":"image","data":"<base64>","mimeType":"image/png"},{"type":"text","text":"What does this image show?"}]}}
|
|
367
|
-
|
|
368
|
-
// P8 session lifecycle: list, resume, load across server restart
|
|
369
|
-
{"jsonrpc":"2.0","id":9,"method":"session/list"}
|
|
370
|
-
{"jsonrpc":"2.0","id":10,"method":"session/resume","params":{"sessionId":"<sid>","cwd":"/abs/cwd"}}
|
|
371
|
-
|
|
372
|
-
// P9 tool exercise: prompt that forces an edit + a command run; capture
|
|
373
|
-
// tool_call / tool_call_update shapes and any session/request_permission
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
As executed, live param corrections were applied against these planned
|
|
377
|
-
scripts: `methodId` (not `method`), `configId` (not `configOptionId`), and
|
|
378
|
-
mcpServers http entries require `headers: []` (a LIST). See 8.1 and the
|
|
379
|
-
reference doc.
|
|
380
|
-
|
|
381
|
-
Capability posture, fixed for phases 1-3 and for every probe: `fs` false,
|
|
382
|
-
`terminal` false in the initialize client capabilities. Rationale (corrected
|
|
383
|
-
during the skeptical re-check of the peer review): parity, not philosophy.
|
|
384
|
-
agy keeps executing its own tools exactly as it does today; answering `fs/*`
|
|
385
|
-
or `terminal/*` would put file and process execution inside our process (new
|
|
386
|
-
machinery to build, secure, and hold at parity with agy's native behavior)
|
|
387
|
-
for no phase-1 gain. Diff-render and the permission surface stay meaningful.
|
|
388
|
-
This is a decision, not a default; revisit only as a phase 3+ enhancement
|
|
389
|
-
with its own design pass.
|
|
390
|
-
|
|
391
|
-
Concurrency note: the driver design is one active turn per connection (the
|
|
392
|
-
`#active` singleton). No probe exercises a second concurrent session while a
|
|
393
|
-
permission request is pending. Unverified by design, not by omission.
|
|
394
|
-
|
|
395
|
-
What to record for each gate:
|
|
396
|
-
|
|
397
|
-
| Gate | Question | PASS means | FALLBACK (still parity) |
|
|
398
|
-
| --- | --- | --- | --- |
|
|
399
|
-
| A | Model + effort switch per session? | `set_config_option` (or equivalent) switches both; next prompt uses them | NONE viable: the ACP binary takes no model flags, so respawn-per-switch cannot carry a model; a settings.json rewrite per switch is the only theoretical path and is rejected (unproven, racy). Gate A FAIL blocks the phase 4 default flip; ACP stays opt-in; the gap goes upstream |
|
|
400
|
-
| B | Usage anywhere? | Any update or `_meta` carries token counts | Zero-usage documented; README notes it |
|
|
401
|
-
| C | `tool_call` content richness | rawInput/output/locations enough to retire WrapperReplay + native-tools | Keep current replay machinery unchanged |
|
|
402
|
-
| D | Cancel latency + state | `stopReason: cancelled` within ~2s; session reusable after | Keep kill semantics on streaming; on ACP keep kill as escalation path |
|
|
403
|
-
| E | Startup cost | Cold start < 5s, steady RSS sane for a long-lived process | Spawn per turn-group only (like the streaming recycle cadence) |
|
|
404
|
-
| F | MCP `mcpServers` registration | Bridge `tools/list` visible to the agent mid-turn | Keep bridge wired some other protocol-sanctioned way; if none, G9 parking breaks and phase 1 is BLOCKED |
|
|
405
|
-
| F.7 | Slash behavior | Commands not auto-expanded against our prompt text | Prefix-safe prompt assembly unchanged |
|
|
406
|
-
|
|
407
|
-
Also verify in P5 whether permission requests arrive at all with `auto`
|
|
408
|
-
capabilities off, and whether `fs/write_text_file` requests appear for edits
|
|
409
|
-
(they should NOT, with our fs capabilities false; if they do, we answer them
|
|
410
|
-
with real local writes, same trust domain).
|
|
411
|
-
|
|
412
|
-
### 8.1 Phase 0 findings (COMPLETE, 2026-09-03)
|
|
413
|
-
|
|
414
|
-
Auth completed live: oauth-personal via the BROWSER-capture trick plus an
|
|
415
|
-
`ssh -L` loopback tunnel (the server never surfaces the URL headless; full
|
|
416
|
-
flow documented in [ACP-PROTOCOL-REFERENCE.md](./ACP-PROTOCOL-REFERENCE.md)).
|
|
417
|
-
Run 5 (authenticated, P1-P6) and run 6 (post-restart: load, tools, image,
|
|
418
|
-
Gate F) complete. Raw traffic: `probe-logs/acp-traffic-run5.jsonl` (600
|
|
419
|
-
JSONL lines) and `acp-traffic-run6-restart-load-tools.jsonl` (28 lines);
|
|
420
|
-
conversation store snapshot + schema: `probe-logs/acp-server-conversations/`.
|
|
421
|
-
|
|
422
|
-
| Gate | Verdict | Evidence |
|
|
423
|
-
| --- | --- | --- |
|
|
424
|
-
| A: model/effort switch | **PASS (live)** | `session/set_config_option` `{configId:"model", value:"gemini-3.8-flash-low"}` changed `currentValue`. Effort baked into full slugs; full catalog + default (`gemini-3.7-flash-high`) ships in `session/new` — the `agy models` CLI is not needed on the ACP engine |
|
|
425
|
-
| B: usage | **ABSENT on RC01** | zero token fields in every payload across both runs, including tool flows. Accept zero-usage (existing documented fallback); re-check per build |
|
|
426
|
-
| C: tool_call content | **PASS** | `tool_call`/`tool_call_update` carry kind, status lifecycle, `content` with `{type:"diff", path, newText}` (edits arrive AS DIFFS), `locations`, `rawInput`, optional `rawOutput`. Enough to retire wrapper-replay rendering in phase 3 |
|
|
427
|
-
| D: cancel | **FAIL on RC01** | `session/cancel` → `-32601 Method not found` (verified). Abort fallback **kill + `session/load` VERIFIED WORKING** (run 6): session restored with full history after process death |
|
|
428
|
-
| E: startup cost | **PASS** | initialize ~5-6 s cold (three runs); steady RSS ~327 MB (5 min mixed load) |
|
|
429
|
-
| F: bridge via mcpServers | **PASS (shape)** | `{name, type:"http", url, headers:[]}` accepted; dead URL tolerated at creation (lazy connect). Phase-1 TODO: real bridge `tools/list`+`tools/call` end-to-end (G9) |
|
|
430
|
-
|
|
431
|
-
Additional live-verified facts (details in the reference doc): token
|
|
432
|
-
persistence across restart PASS; `session/load` replays history as FULL-TEXT
|
|
433
|
-
chunks (driver must treat as replay, not live); config does NOT persist
|
|
434
|
-
across restart (driver re-applies model/effort/mode after every restart);
|
|
435
|
-
`session/request_permission` flow verified (options `allow`/`deny`,
|
|
436
|
-
kinds `allow_once`/`reject_once`; answer `{outcome:{outcome:"selected",
|
|
437
|
-
optionId}}`); image prompts PASS end-to-end; `set_mode` and per-session
|
|
438
|
-
`session/close` work; approved tool call may be superseded by another
|
|
439
|
-
toolCallId (track effects, not ids).
|
|
440
|
-
|
|
441
|
-
Schema corrections captured live (all in the reference doc): `authenticate`
|
|
442
|
-
takes `methodId` (not `method`); `set_config_option` takes `configId` (not
|
|
443
|
-
`configOptionId`); `settings.json` is read at server STARTUP only; -32602
|
|
444
|
-
error bodies carry `data.errors[].loc` field paths (use as correction
|
|
445
|
-
oracle). Streaming is pure-delta on live prompts (mid-token chunk splits; no
|
|
446
|
-
cumulative resends). Modes `default`/`auto_edit`/`yolo` map to our
|
|
447
|
-
`mode`/`skipPermissions`. The ACP conversation store is per-session SQLite
|
|
448
|
-
with opaque `steps.step_payload` blobs — same two-phase-write family as
|
|
449
|
-
legacy issue #1; never poll these DBs (re-validated decision).
|
|
450
|
-
|
|
451
|
-
Probe list CLOSED. Phase 0 go/no-go: GO for phase 1, with Gate D's kill+
|
|
452
|
-
reload abort path and the Gate F bridge end-to-end check as phase-1
|
|
453
|
-
acceptance items.
|
|
454
|
-
|
|
455
|
-
## 9. Target architecture
|
|
456
|
-
|
|
457
|
-
### 9.1 New modules
|
|
458
|
-
|
|
459
|
-
```
|
|
460
|
-
src/acp/jsonrpc.ts newline-delimited JSON-RPC 2.0 framing: request/response
|
|
461
|
-
correlation map, concurrent requests, error responses,
|
|
462
|
-
notification + server-request dispatch, malformed-line
|
|
463
|
-
tolerance. Pure transport, no agy knowledge.
|
|
464
|
-
src/acp/connection.ts process lifecycle: spawn AGY_ACP_BIN, initialize
|
|
465
|
-
handshake, authenticate detection (-32000), session/new
|
|
466
|
-
/ load / prompt / cancel / set_config_option, client-side
|
|
467
|
-
method handlers (request_permission policy, fs, terminal),
|
|
468
|
-
outbound event queue.
|
|
469
|
-
src/acp/driver.ts AcpDriver: implements the StreamDriver surface (section 9.2)
|
|
470
|
-
so provider.ts keeps working unchanged. State machine,
|
|
471
|
-
timers, parks, snapshot, close.
|
|
472
|
-
src/acp/events.ts session/update to DriverActivity mapping + stopReason
|
|
473
|
-
mapping. Pure functions, unit-tested against captured
|
|
474
|
-
probe transcripts.
|
|
475
|
-
scripts/smoke-acp.mjs live smoke, gated by AGY_ACP_LIVE=1 (spends quota),
|
|
476
|
-
mirrors smoke-stream-json.mjs.
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### 9.2 Driver contract (unchanged surface, additive only)
|
|
480
|
-
|
|
481
|
-
`AcpDriver` matches the existing `StreamDriver` public surface: `state`,
|
|
482
|
-
`activeHandle`, `run()`, `reentry()`, `kickIdle()`, `set onTurnEnd()`,
|
|
483
|
-
`snapshot()`, `close()`. `DriverActivity` gains one additive variant; the
|
|
484
|
-
streaming engine never emits it:
|
|
485
|
-
|
|
486
|
-
```ts
|
|
487
|
-
// stream-events/driver today: { type: "thought"; tokens: number }
|
|
488
|
-
// ACP addition:
|
|
489
|
-
| { type: "thought"; tokens?: number; delta?: string }
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
`provider.ts` change: when `delta` is present call `appendThinking`, else keep
|
|
493
|
-
the current token-count behavior. One `if`, additive, streaming untouched.
|
|
494
|
-
|
|
495
|
-
Interface extraction (review 2, finding 7): `provider.ts` imports the
|
|
496
|
-
concrete `StreamDriver` class today; without a neutral type the two engine
|
|
497
|
-
wirings would each drag the other's module in. Phase 1 extracts a
|
|
498
|
-
`TurnDriver` interface into a neutral module
|
|
499
|
-
(`src/driver-types.ts`); both drivers implement it; `provider.ts` and
|
|
500
|
-
`ToolRoundTrips` depend on the interface only. `/agy engine` changes require
|
|
501
|
-
a pi restart (driver wiring happens at extension load); a live engine router
|
|
502
|
-
is explicitly deferred as speculative.
|
|
503
|
-
|
|
504
|
-
Teardown contract (review 3, finding 1 — the Gate D kill+reload path needs
|
|
505
|
-
an explicit answer for in-flight JSON-RPC state): when the connection dies
|
|
506
|
-
or is killed, `AcpConnection.abortAll()` rejects every outstanding
|
|
507
|
-
correlation-map entry (the pending `session/prompt` request, any unanswered
|
|
508
|
-
client-side requests), the driver settles the turn outcome as
|
|
509
|
-
`ERROR`/`aborted` (never left pending), and `onTurnEnd` fires so the
|
|
510
|
-
provider's `roundTrips.failAll()` fails parked round-trips exactly as the
|
|
511
|
-
streaming driver's `failTurn` path does. Nothing is ever written to a dead
|
|
512
|
-
socket; no promise survives the kill. Mirrors `ToolRoundTrips.failAll()`.
|
|
513
|
-
|
|
514
|
-
Event mapping (`src/acp/events.ts`):
|
|
515
|
-
|
|
516
|
-
| ACP | DriverActivity | pi mapping (provider.ts, existing) |
|
|
517
|
-
| --- | --- | --- |
|
|
518
|
-
| `agent_message_chunk` | `{type:"text", delta}` | text block deltas |
|
|
519
|
-
| `agent_thought_chunk` | `{type:"thought", delta}` | thinking block deltas |
|
|
520
|
-
| `tool_call` (first) | `{type:"tool_start", name, args}` | buffered; render on completion |
|
|
521
|
-
| `tool_call_update` completed | `{type:"tool_done", name, args, output}` | thinking label / native re-exec / wrapper (gate C) |
|
|
522
|
-
| `tool_call_update` failed | `{type:"tool_error", name, message}` | thinking label |
|
|
523
|
-
| `plan` | (phase 2+) thinking label `[agy plan]` | no pi plan block exists yet |
|
|
524
|
-
| `available_commands_update` | snapshot field only | `/agy doctor` |
|
|
525
|
-
| usage (if found, gate B) | `{type:"usage", usage}` | `toPiUsage` |
|
|
526
|
-
| prompt response `end_turn` | TurnOutcome OK | `stopReason: "stop"` |
|
|
527
|
-
| `cancelled` | TurnOutcome aborted | `stopReason: "aborted"` |
|
|
528
|
-
| `refusal` / `max_turn_requests` / `max_tokens` | TurnOutcome ERROR / OK+note | `error` / `stop` + `errorMessage` |
|
|
529
|
-
| `user_message_chunk` (during `session/load` only) | suppressed (history replay) | never emitted to pi as live text |
|
|
530
|
-
|
|
531
|
-
Defensive guard ported from the streaming engine: if an `agent_message_chunk`
|
|
532
|
-
repeats the full accumulated text instead of a delta, detect and slice (the
|
|
533
|
-
`isCumulativeResend` lesson; same agy binary lineage, same quirk class).
|
|
534
|
-
Guard plus test ship in phase 1. Honest labeling: the ACP spec defines chunks
|
|
535
|
-
as deltas, so on a compliant server the guard stays inert; it earns its ten
|
|
536
|
-
lines because this exact failure mode was observed in the wild on the same
|
|
537
|
-
backend's private protocol, and its steady-state cost is one prefix
|
|
538
|
-
comparison per chunk.
|
|
539
|
-
|
|
540
|
-
Load-replay rules (run 6, verified): `session/load` replays the full
|
|
541
|
-
conversation as `user_message_chunk`/`agent_message_chunk` PAIRS carrying
|
|
542
|
-
FULL TEXT, not the original deltas. `AcpDriver` marks replay chunks as
|
|
543
|
-
history and swallows them; none reach pi as live generation. Two more
|
|
544
|
-
restart rules: config does NOT persist across restart (model/effort/mode are
|
|
545
|
-
re-applied via `set_config_option` after every restart/load), and
|
|
546
|
-
`session/load` takes the same `mcpServers` param as `session/new` — the
|
|
547
|
-
bridge registration is passed on both.
|
|
548
|
-
|
|
549
|
-
### 9.3 Permission policy (simplified per decision 2026-09-03)
|
|
550
|
-
|
|
551
|
-
pi has no native permission-gate concept; extensions that want gating
|
|
552
|
-
implement it inside their own tools. G9 preserves that end-to-end: a pi tool
|
|
553
|
-
called by agy executes in pi's loop, where the tool's own gating runs. The
|
|
554
|
-
bridge-side `bridge` policy (routing `request_permission` through
|
|
555
|
-
`ask_user_question` with a third round-trip kind and a decision cache) was
|
|
556
|
-
REJECTED by decision: it built permission UX pi does not have, for agy-native
|
|
557
|
-
tools, at real complexity cost. The full design lives in review-3 history if
|
|
558
|
-
upstream ever ships allow-always kinds and the calculus changes.
|
|
559
|
-
|
|
560
|
-
One policy ships:
|
|
561
|
-
|
|
562
|
-
- `auto`: answer `session/request_permission` in-connection with the allow
|
|
563
|
-
option. Byte-for-byte parity with today's `skipPermissions: true`. No
|
|
564
|
-
round-trip, no provider involvement, no third kind; the once-only options
|
|
565
|
-
quirk (run 6) is irrelevant under auto. Hard rule unchanged: the handler
|
|
566
|
-
never hangs and never blocks the `session/prompt` response path.
|
|
567
|
-
|
|
568
|
-
Consequence: `provider.ts` is truly UNCHANGED by adoption (its only additive
|
|
569
|
-
line is the thought-delta `if`). Gate D teardown (9.2) still applies: on
|
|
570
|
-
connection death the unanswered permission request dies with the socket and
|
|
571
|
-
`abortAll()` settles everything.
|
|
572
|
-
|
|
573
|
-
Timer interaction (reviews 1-2, design retained; scope narrowed by the 9.3
|
|
574
|
-
decision to G9 tool parks): the overall-turn timer is armed once per turn and
|
|
575
|
-
only the idle timer pauses while a round-trip is parked. A human answer
|
|
576
|
-
through a parked pi tool (e.g. `ask_user_question`) can legitimately outrun
|
|
577
|
-
10 minutes. `AcpDriver` pauses the overall timer while any round-trip is
|
|
578
|
-
parked and, on settle, re-arms it with the REMAINING budget (`deadline -
|
|
579
|
-
now`), never a fresh cap: the overall timer is a turn DEADLINE, not an
|
|
580
|
-
inactivity guard. Every park carries its own timeout (`BRIDGE_TIMEOUT_MS`),
|
|
581
|
-
so a paused deadline cannot hang forever. Driver-local (AcpDriver only);
|
|
582
|
-
streaming behavior untouched; ships in phase 1.
|
|
583
|
-
|
|
584
|
-
### 9.4 Sessions schema (engine-scoped keys)
|
|
585
|
-
|
|
586
|
-
The first design (a per-entry `engine` field) was rejected in review 2:
|
|
587
|
-
`set()` overwrites the single `sid:<pi-session>` key, so one ACP turn ERASES
|
|
588
|
-
the streaming conversation binding, and a rollback loses continuity, breaking
|
|
589
|
-
the section 13 guarantee. Engines scope at the KEY level instead:
|
|
590
|
-
|
|
591
|
-
```jsonc
|
|
592
|
-
// ~/.pi/agent/antigravity-bridge/sessions.json
|
|
593
|
-
{
|
|
594
|
-
"sid:<pi-session>": { "conversationId": "<streaming id>", "lastStepIdx": -1, "lastMessageCount": 42 },
|
|
595
|
-
"sid:<pi-session>@acp": { "conversationId": "<ACP sessionId>", "lastStepIdx": -1, "lastMessageCount": 42 }
|
|
596
|
-
}
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
- Un-suffixed keys belong to the streaming engine, byte-compatible with every
|
|
600
|
-
persisted store; ACP keys carry an `@acp` suffix appended by
|
|
601
|
-
`sessionKey()` when `config.engine === "acp"`.
|
|
602
|
-
- Engines never touch each other's keys: rollback keeps both continuations,
|
|
603
|
-
`narrowStoreMap` needs no change (keys pass through untouched), and no
|
|
604
|
-
migration runs.
|
|
605
|
-
- Under ACP the stored id is the ACP sessionId; `session/load` is attempted
|
|
606
|
-
first on resume, our store only remembers which id to load.
|
|
607
|
-
|
|
608
|
-
### 9.5 Config schema
|
|
609
|
-
|
|
610
|
-
```jsonc
|
|
611
|
-
// ~/.pi/agent/antigravity-bridge/config.json (additive)
|
|
612
|
-
{
|
|
613
|
-
"engine": "stream-json", // "stream-json" | "acp"; default stream-json
|
|
614
|
-
"acp": {
|
|
615
|
-
"bin": "", // path to agy_acp_server.par; empty = resolve
|
|
616
|
-
"permissions": "auto" // auto-approve request_permission; single policy (9.3)
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
- Env: `AGY_ENGINE`, `AGY_ACP_BIN`, `AGY_ACP_PERMISSIONS` (file < env, the
|
|
622
|
-
documented precedence pattern).
|
|
623
|
-
- History note: an `engine` key existed before 1.3.2 (sqlite engine) and was
|
|
624
|
-
removed; stale values in old config files are already dropped by narrowing.
|
|
625
|
-
Values narrow to `"stream-json" | "acp"`, anything else falls back to the
|
|
626
|
-
default. The sqlite engine is not coming back.
|
|
627
|
-
- Binary resolution order: `AGY_ACP_BIN` > `acp.bin` > `agy_acp_server.par`
|
|
628
|
-
on PATH > install layout default (section 12). Resolution failure is a
|
|
629
|
-
visible turn error naming what was tried.
|
|
630
|
-
|
|
631
|
-
## 10. Phase plan
|
|
632
|
-
|
|
633
|
-
### Phase 0: probes, gates, install, auth (no product code) — ✅ COMPLETE (2026-09-03)
|
|
634
|
-
|
|
635
|
-
- [x] Run probes P1-P9 (section 8). Gate verdicts recorded in 8.1; captured
|
|
636
|
-
protocol in ACP-PROTOCOL-REFERENCE.md; raw traffic in `probe-logs/`.
|
|
637
|
-
- [x] Install layout + pin (section 12): binary at
|
|
638
|
-
`~/.local/opt/agy-acp/<build>/` + `current` symlink + zip.sha256.
|
|
639
|
-
- [x] Auth onboarded: oauth-personal (token persisted, survives restart —
|
|
640
|
-
verified run 6).
|
|
641
|
-
- [x] Deliverable: gates marked — A PASS, B ABSENT (managed), C PASS,
|
|
642
|
-
D FAIL + fallback VERIFIED, E PASS, F PASS-shape. GO for phase 1.
|
|
643
|
-
|
|
644
|
-
### Phase 1: ACP transport engine, parity only — 🔨 BUILT (2026-09-03), acceptance open
|
|
645
|
-
|
|
646
|
-
Files: new `src/acp/*`, `src/config.ts` (engine + acp block), `src/sessions.ts`
|
|
647
|
-
(engine tag → shipped as engine-scoped KEYS, see 9.4), `extensions/index.ts`
|
|
648
|
-
(engine selection + doctor additions), `src/provider.ts` (driver injection
|
|
649
|
-
point; `createStreamSimple` already takes the driver as a dep; no other
|
|
650
|
-
provider change).
|
|
651
|
-
|
|
652
|
-
- [x] `jsonrpc.ts` + `connection.ts` + `events.ts` + `driver.ts` as specified
|
|
653
|
-
(+ `TurnDriver` extraction to `src/driver-types.ts`).
|
|
654
|
-
- [x] `extractUserPrompt` unchanged (text only in phase 1; images in phase 2).
|
|
655
|
-
- [x] `mcpServers` registration of the bridge server at `session/new` AND
|
|
656
|
-
`session/load` (run 6: load takes the same param; resumed sessions must
|
|
657
|
-
keep bridge access). REGISTERED — live end-to-end still pending, see
|
|
658
|
-
acceptance below.
|
|
659
|
-
- [x] Permission policy locked to `auto` (single policy; no bridge policy, see
|
|
660
|
-
9.3).
|
|
661
|
-
- [x] `session/cancel` wired to pi abort and `session/close` sent on shutdown
|
|
662
|
-
(pulled up from phase 2 by review 2, finding 6: abort must not kill the
|
|
663
|
-
server process, and shutdown should not leak session state server-side).
|
|
664
|
-
RC01 has no cancel: probe-once → -32601 → teardown+kill+reload, probed
|
|
665
|
-
state shown in doctor.
|
|
666
|
-
- [x] Overall-turn timer pause while parked, REMAINING-budget semantics
|
|
667
|
-
(9.3), covered by tests (park/kickIdle deadline test).
|
|
668
|
-
- [x] Fake-server suites: jsonrpc framing (incl. partial-line buffer), events
|
|
669
|
-
mapping, driver flows (happy, load-replay suppression, permission auto,
|
|
670
|
-
Gate D abort, auth error), engine config narrowing — suite green.
|
|
671
|
-
- [x] `/agy engine acp|stream-json` command + `/agy doctor` shows engine,
|
|
672
|
-
server version, session counts, cancel support.
|
|
673
|
-
- [x] Live smoke through the full stack (`scripts/smoke-acp.mjs`, quota-
|
|
674
|
-
gated): PASS.
|
|
675
|
-
- [x] Round-5 implementation review (agy): P0 framing buffer + 3 P1 + 3 P2
|
|
676
|
-
all fixed.
|
|
677
|
-
|
|
678
|
-
Open acceptance (blocking "phase 1 done"):
|
|
679
|
-
|
|
680
|
-
- [x] Bridge `tools/list` + `tools/call` end-to-end on the ACP engine (Gate F
|
|
681
|
-
live) — VERIFIED 2026-09-03, `scripts/smoke-acp-bridge.mjs`, 3/3 runs:
|
|
682
|
-
real server accepted the registration, listed the bridge catalog, called
|
|
683
|
-
`bridge_echo`, and finished its turn with the result (`ECHO:BRIDGE-E2E-777`).
|
|
684
|
-
The check also found and fixed a real defect: the bridge 403s any request
|
|
685
|
-
without the `x-bridge-token` shared secret, but the ACP registration sent
|
|
686
|
-
`headers: []`. Fix: `McpServerHandle` now exposes `token` (and
|
|
687
|
-
`TOKEN_HEADER` is exported); the extension builds the registration headers
|
|
688
|
-
from the handle. Known cosmetic gap (phase 2): `tool_done.output` carries
|
|
689
|
-
agy's tool title ("Bridge echo call"), not the result content — the model
|
|
690
|
-
DID receive the result; only the activity display lacks it. The pi-side G9
|
|
691
|
-
park/resume is engine-independent (proven live on stream-json); the smoke
|
|
692
|
-
answers deps directly to isolate the agy-side HTTP client, the only part
|
|
693
|
-
no fake server could stand in for.
|
|
694
|
-
- [x] §6 parity checklist executed LIVE on both engines — 2026-09-03,
|
|
695
|
-
`scripts/parity-live.mjs`, 14/14 (7 scenarios × 2 engines). The run
|
|
696
|
-
caught a REAL driver bug: a killed connection's late exit (RC01's
|
|
697
|
-
signal handler intercepts SIGTERM and outlives its replacement)
|
|
698
|
-
clobbered `#conn` and failed the recovery turn with the old stderr.
|
|
699
|
-
Fixed: exit handling is connection-scoped (`stale-connection-exited`
|
|
700
|
-
logged and ignored); regression test reproduces the race
|
|
701
|
-
deterministically via `ACP_FAKE_SLOW_DEATH_MS`.
|
|
702
|
-
- [x] README / DEVELOPMENT / CHANGELOG updates — README (two engines,
|
|
703
|
-
`/agy engine`, `/agy acp-auth`, `AGY_ENGINE`/`AGY_ACP_BIN`, ToS
|
|
704
|
-
wording covers both official binaries), DEVELOPMENT (ACP suites +
|
|
705
|
-
3 live scripts), CHANGELOG `[Unreleased]` (engine, token fix,
|
|
706
|
-
stale-exit fix, RC01 limitations).
|
|
707
|
-
|
|
708
|
-
Acceptance gate: every section 6 box `[x]` on the ACP engine, or explicitly
|
|
709
|
-
marked with its gate fallback.
|
|
710
|
-
|
|
711
|
-
### Phase 2: protocol-native wins — ✅ COMPLETE (2026-09-03)
|
|
712
|
-
|
|
713
|
-
Probe evidence: `probe-logs/acp-phase2-traffic.jsonl` + shapes recorded in
|
|
714
|
-
ACP-PROTOCOL-REFERENCE.md "Phase-2 probe findings".
|
|
715
|
-
|
|
716
|
-
- ~~`permissions: "bridge"` policy~~: REMOVED by decision 2026-09-03 (pi has no
|
|
717
|
-
native permission concept; per-tool gating belongs to the tools themselves
|
|
718
|
-
and is preserved by G9; see 9.3).
|
|
719
|
-
- [x] Plan-mode equivalence probe: ACP modes are permission modes only
|
|
720
|
-
(default/auto_edit/yolo) — NO review-only mode exists. The server's
|
|
721
|
-
`/plan` command is intercepted server-side (F.7) and WRITES the plan
|
|
722
|
-
artifact under auto policy. Verdict: plan delegations keep
|
|
723
|
-
`agy -p --mode plan` (the committed exception); do not route mode:plan
|
|
724
|
-
through ACP.
|
|
725
|
-
- [x] Image prompt blocks forwarded from pi content — driver `images`
|
|
726
|
-
param, `connection.prompt` builds typed blocks ahead of the text,
|
|
727
|
-
provider extracts image blocks from the user message, models advertise
|
|
728
|
-
`input: ["text","image"]` on the ACP engine only (engine read at load;
|
|
729
|
-
engine switches require a restart). Verified live: 64x64 two-tone PNG
|
|
730
|
-
through the full driver stack (`scripts/smoke-acp-image.mjs`) and in the
|
|
731
|
-
probe.
|
|
732
|
-
- [x] Thought text deltas through the thinking pipeline — already wired in
|
|
733
|
-
phase 1 (provider renders `thought` deltas into the thinking block);
|
|
734
|
-
probe finding: chunks are SPARSE on RC01 (a step-by-step prompt produced
|
|
735
|
-
zero; reasoning ships as plain message text). No further work justified.
|
|
736
|
-
- [x] `session/cancel` parity — landed in phase 1 (Gate D fallback,
|
|
737
|
-
abort-recover live on both engines).
|
|
738
|
-
- [x] Model/effort switching via the gate A mechanism — PASS (live,
|
|
739
|
-
including on a loaded session; parity scenario).
|
|
740
|
-
- [x] Tool-frame display fixes (found by the probe, shipped with this
|
|
741
|
-
phase): `tool_call_update` output prefers `content[]` text over the
|
|
742
|
-
display-title `rawOutput`; MCP args unwrap the `arguments` envelope;
|
|
743
|
-
tool name prefers `_meta.mcp.tool` over the "<server>_<tool>" title.
|
|
744
|
-
- [x] "Plan updates rendered as thinking labels" — OBSERVED-ABSENT on
|
|
745
|
-
RC01: no `plan` sessionUpdate type exists; artifacts arrive as ordinary
|
|
746
|
-
edit tool_calls (already rendered as cards). Item closed as not
|
|
747
|
-
applicable, not deferred.
|
|
748
|
-
- Acceptance: no parity regression (14/14 re-run after the mapping
|
|
749
|
-
changes); cancel probe done (phase 1); image probe end-to-end (probe +
|
|
750
|
-
live smoke).
|
|
751
|
-
|
|
752
|
-
### Phase 3: consolidation (immediate priority, opt-in only)
|
|
753
|
-
|
|
754
|
-
Hard rule: Keep both engines in the extension. Default engine remains `stream-json`. All items below are non-breaking opt-in enhancements for the ACP engine that do NOT alter default behavior or touch streaming paths.
|
|
755
|
-
|
|
756
|
-
Queue:
|
|
757
|
-
1. [x] Gate C evaluation: `native-tools.ts` + `WrapperReplay` retired on the ACP engine (retained for the streaming (`stream-json`) engine). ACP turns emit thinking labels for tool executions without parking turns for synthetic re-execution or wrapper cards; bridge MCP tools (`bridge_call`) continue parking natively. Verified: live parity 14/14 held.
|
|
758
|
-
2. [x] Retire `diff-render.ts` (git path) on the ACP engine — DONE 2026-09-04. The phase-2 probe proved ACP surfaces edit diffs natively (`tool_call` `content[]` `{type:"diff", path, oldText?, newText}`), which is richer AND cheaper than the git-sourced path: implemented as (a) `events.ts` extracts the first diff entry into the `tool_done` activity (`AcpEditDiff`); (b) `provider.ts` renders it on ACP turns via the new `formatInlineDiff` (in-memory `generateDiffString`, same line-numbered format, ZERO git subprocesses) instead of `TurnDiffContext.diffEdit`; (c) `diff-render.ts` git machinery remains solely for the `stream-json` engine. Tests: diff extraction (with/without `oldText`), ACP thinking-stream rendering (`+2 B` line-numbered), label-only fallback, no parking, streaming path unchanged. Verified: 165/165 vitest, tsc clean, live parity 14/14.
|
|
759
|
-
3. [x] `/agy doctor` diagnostics expansion — DONE 2026-09-04. The ACP
|
|
760
|
-
snapshot now carries `reconnects` (connections beyond the first =
|
|
761
|
-
Gate D kills + stale-exit replacements) and the handshake `agentInfo`
|
|
762
|
-
name/title; `/agy doctor` surfaces both (reconnects in the stats line,
|
|
763
|
-
agent title next to the server version). Regression test pins
|
|
764
|
-
`reconnects = 1` on the stale-exit flow.
|
|
765
|
-
4. [x] G1 digest via `embeddedContext` resource blocks — DONE 2026-09-04
|
|
766
|
-
(the optional enhancement, adopted as the ACP delivery path). On the
|
|
767
|
-
ACP engine the digest ships as a native `{type:"resource"}` block in
|
|
768
|
-
the prompt array (`connection.prompt` builds images → resource →
|
|
769
|
-
text) instead of inline prompt text; `stream-json` keeps the inline
|
|
770
|
-
default. Verified live: a resource block with a secret word was read
|
|
771
|
-
and answered correctly by RC01 (`promptCapabilities.embeddedContext`
|
|
772
|
-
is functional, not just advertised).
|
|
773
|
-
|
|
774
|
-
Acceptance: parity suite remains 14/14, doctor parity, no breakage to stream-json default.
|
|
775
|
-
|
|
776
|
-
Status: 🚧 Phase 3 remaining items are COMPLETE (2026-09-04): 168/168 tests,
|
|
777
|
-
tsc clean, live parity 14/14, embeddedContext verified live (resource block
|
|
778
|
-
with a secret word answered correctly). Phase-3 acceptance: nothing deletes
|
|
779
|
-
in phase 3 — the streaming modules stay (permanently, see the standing
|
|
780
|
-
decision at the top and Phase 4).
|
|
781
|
-
|
|
782
|
-
### Phase 4: default flip (deferred)
|
|
783
|
-
|
|
784
|
-
All items below are deferred until a full soak cycle of both engines has completed and upstream conditions are met:
|
|
785
|
-
|
|
786
|
-
1. AskAntigravity migration to ACP one-shot (migrating while `stream-json` is default breaks streaming-only users who haven't onboarded ACP auth; streaming conversation ids cannot resume under ACP). `mode: "plan"` delegations keep the `agy -p --mode plan` path (committed exception).
|
|
787
|
-
2. Delete `src/discovery.ts` (`/proc` fd-scan) once AskAntigravity migration completes.
|
|
788
|
-
3. Default flip: `config.engine` default becomes `"acp"` after one full release soak cycle with both engines shipping. Gate A PASS is verified. Gate B is NOT a precondition (lifted as a blocker 2026-09-07); the soft items in section 17 ship in the same release.
|
|
789
|
-
4. Upstream Gate B resolution (optional, informational): Google ships usage counters in ACP payloads. The `/agy doctor` watch reports it when it happens. Mapping it in is a small additive job; the streaming engine stays regardless.
|
|
790
|
-
|
|
791
|
-
NO deletion phase: the streaming engine is a permanently maintained peer (standing user decision, 2026-09-07). The old phase-4 "streaming deletion" item is void.
|
|
792
|
-
|
|
793
|
-
Acceptance: the default-flip release ships with the parity suite as acceptance evidence.
|
|
794
|
-
|
|
795
|
-
## 11. Test strategy
|
|
796
|
-
|
|
797
|
-
- **Framing** (`jsonrpc.ts`): correlation, concurrency, error responses,
|
|
798
|
-
notifications vs requests, malformed lines, backpressure. Pure unit tests.
|
|
799
|
-
- **Mapping** (`events.ts`): every session/update variant from captured probe
|
|
800
|
-
transcripts to DriverActivity; stopReason table; unknown-variant tolerance
|
|
801
|
-
(the `parseAgyLine` lesson, re-applied).
|
|
802
|
-
- **Driver** (`driver.ts`): scripted fake ACP server (a tiny stdio JSON-RPC
|
|
803
|
-
node script under `tests/helpers/`) covering: handshake, session/new fail
|
|
804
|
-
auth, streaming prompt, park suspends idle timer, kickIdle rearm, cancel
|
|
805
|
-
mid-stream, connection death mid-turn, recycle fallback path.
|
|
806
|
-
- **Provider**: the existing `provider-streaming` / `provider-digest` /
|
|
807
|
-
`provider-sysprompt` suites run against both engines via the shared driver
|
|
808
|
-
contract. New case: thought delta path.
|
|
809
|
-
- **Sessions**: engine-tag matching, streaming-file compatibility (no tag),
|
|
810
|
-
cross-engine miss starts fresh.
|
|
811
|
-
- **Config**: narrowing of stale/garbage `engine` values, env precedence.
|
|
812
|
-
- **Parity suite**: the section 6 checklist encoded as an integration run
|
|
813
|
-
against the fake server for both engines; live parity runs stay
|
|
814
|
-
`AGY_ACP_LIVE=1` gated (quota).
|
|
815
|
-
|
|
816
|
-
## 12. Binary management, pinning, auth onboarding
|
|
817
|
-
|
|
818
|
-
Install layout:
|
|
819
|
-
|
|
820
|
-
```
|
|
821
|
-
~/.local/opt/agy-acp/<build>/
|
|
822
|
-
agy_acp_server.par
|
|
823
|
-
localharness_external
|
|
824
|
-
~/.local/opt/agy-acp/current -> <build> # symlink; AGY_ACP_BIN default
|
|
825
|
-
```
|
|
826
|
-
|
|
827
|
-
- Pin by build-stamped registry URL (`...20260818_01_RC01-...zip`), not by
|
|
828
|
-
the moving registry index. The registry updates hourly; a float could
|
|
829
|
-
change the engine under a running install mid-release.
|
|
830
|
-
- The registry publishes no checksums. Record the zip SHA-256 at install time
|
|
831
|
-
in the install dir for drift detection. Propose an upstream checksum
|
|
832
|
-
request (issue) once we depend on this.
|
|
833
|
-
- `--uid=` from the linux registry entry: the server ran without it here.
|
|
834
|
-
Treat as a launcher artifact; revisit if a future build refuses to start.
|
|
835
|
-
- Auth onboarding: `/agy auth-manual` prints the four methods with exact
|
|
836
|
-
`settings.json` shapes (source: official Zed docs, section 2.3). Headless
|
|
837
|
-
path: `GEMINI_API_KEY` + `auth.type: "gemini-api-key"`. The agent NEVER
|
|
838
|
-
writes or reads credentials; it prints instructions and verifies by
|
|
839
|
-
re-running `session/new` until the error clears.
|
|
840
|
-
|
|
841
|
-
## 13. Rollback
|
|
842
|
-
|
|
843
|
-
At any phase: `AGY_ENGINE=stream-json` (or `/agy engine stream-json`) returns
|
|
844
|
-
to the streaming engine. Sessions are keyed per engine (9.4), so the streaming
|
|
845
|
-
engine resumes its own conversations untouched. The streaming engine is only deleted in
|
|
846
|
-
phase 4, one release after the flip, so rollback stays possible throughout.
|
|
847
|
-
|
|
848
|
-
## 14. Documentation updates
|
|
849
|
-
|
|
850
|
-
| Doc | Change | Phase |
|
|
851
|
-
| --- | --- | --- |
|
|
852
|
-
| `README.md` | engine section, binary install, auth, arch note | 1, 4 |
|
|
853
|
-
| `docs/ARCHITECTURE.md` | ACP engine section alongside stream-json | 1 |
|
|
854
|
-
| `docs/DEVELOPMENT.md` | smoke-acp, fake server, probe workflow | 1 |
|
|
855
|
-
| `docs/ACP-ADOPTION-PLAN.md` | this file; gate results appended | 0 |
|
|
856
|
-
| `docs/PI-BRIDGE-GAPS.md` | G1 note: per-tool gating stays extension-owned; G9 preserves it under ACP | 1 |
|
|
857
|
-
| `CHANGELOG.md` | per phase, house style | each |
|
|
858
|
-
|
|
859
|
-
## 15. Risk register
|
|
860
|
-
|
|
861
|
-
| # | Risk | L | I | Response |
|
|
862
|
-
| --- | --- | --- | --- | --- |
|
|
863
|
-
| R1 | Gate A fails (no model switch) | M | H | default flip blocked; ACP stays opt-in; escalate upstream. No ship-anyway: model switching is not optional |
|
|
864
|
-
| R2 | Gate F fails (bridge not registrable) | L | H | BLOCKS phase 1; escalate upstream, keep streaming |
|
|
865
|
-
| R3 | Usage absent (CONFIRMED, Gate B) | H | M | zero-usage documented on ACP; stream-json retained as secondary engine; phase-4 deletion conditioned on Gate B lift (review 4) |
|
|
866
|
-
| R4 | Binary churn (hourly registry, RC builds) | M | M | pin by build id, record sha256 |
|
|
867
|
-
| R5 | Server rejects second simultaneous session | L | M | one session per connection (today's model), N connections instead |
|
|
868
|
-
| R6 | Thought text floods transcript | M | L | thinking pipeline unchanged, same close-on-switch |
|
|
869
|
-
| R7 | ToS posture shifts again | L | H | official channel is Google's own; monitor registry + FAQ |
|
|
870
|
-
| R8 | aarch64 breakage | L | L | per-arch gating |
|
|
871
|
-
| R9 | ~~`bridge` permission throughput~~ removed with the bridge policy (9.3) | - | - | n/a |
|
|
872
|
-
|
|
873
|
-
## 16. Open questions
|
|
874
|
-
|
|
875
|
-
CLOSED 2026-09-03 — every item was answered by the Phase 0 probes (section
|
|
876
|
-
8.1, [ACP-PROTOCOL-REFERENCE.md](./ACP-PROTOCOL-REFERENCE.md)). Notable
|
|
877
|
-
answers: model catalog ships in `session/new` (CLI catalog unnecessary on
|
|
878
|
-
ACP); edits surface as diffs inside `tool_call` content even with fs
|
|
879
|
-
capabilities off; no usage fields anywhere; available_commands_update carries
|
|
880
|
-
`plan` and `logout`; cold start ~5-6 s, steady RSS ~327 MB.
|
|
881
|
-
|
|
882
|
-
## 17. Default-flip readiness (phase 4) — analysis as of 2026-09-07
|
|
883
|
-
|
|
884
|
-
Standing analysis so nobody re-derives it: what blocks flipping the default
|
|
885
|
-
engine from stream-json to ACP. Re-verify only the dated facts (Gate B
|
|
886
|
-
status via `/agy doctor`); the structural conclusions hold.
|
|
887
|
-
|
|
888
|
-
**Verdict: nothing blocks the flip. Gate B was REMOVED as a blocker on
|
|
889
|
-
2026-09-07 (user decision: token usage does not matter for the extension's
|
|
890
|
-
purpose - agy runs on subscription quota, cost stays zero either way).
|
|
891
|
-
Zero-usage on ACP is accepted as documented behavior. Remaining before the
|
|
892
|
-
flip: the four soft items below, shipped in the same release.**
|
|
893
|
-
|
|
894
|
-
Already green:
|
|
895
|
-
|
|
896
|
-
- Parity contract (section 6) is ALL `[x]`, live-verified on both engines
|
|
897
|
-
(parity suite 14/14).
|
|
898
|
-
- Everything shipped since 1.4.9 is engine-aware: bridge registration is
|
|
899
|
-
ACP-native (`session/new` mcpServers) AND stream-json-native
|
|
900
|
-
(`~/.gemini/config/mcp_config.json`); tool-result images ride both engines
|
|
901
|
-
(probe-verified on each); the approval gate's ACP hook firing is the
|
|
902
|
-
LIVE-verified side (stream-json is docs-attested only), so the flip does
|
|
903
|
-
not weaken it.
|
|
904
|
-
- Rollback is one config flip; sessions are engine-scoped so bindings never
|
|
905
|
-
cross.
|
|
906
|
-
|
|
907
|
-
Former blocker — Gate B, LIFTED 2026-09-07:
|
|
908
|
-
|
|
909
|
-
- RC01 sends no usage/token fields in ANY payload, so ACP shows zero
|
|
910
|
-
tokens. This used to block the default flip; the user lifted it: agy
|
|
911
|
-
runs on subscription quota and cost is zero regardless, so the display
|
|
912
|
-
gap is cosmetic for this extension. Zero-usage on ACP is documented
|
|
913
|
-
behavior.
|
|
914
|
-
- Both engines are PERMANENTLY maintained (standing user decision
|
|
915
|
-
2026-09-07): no deletion phase exists, regardless of Gate B. stream-json
|
|
916
|
-
is the supported fallback/secondary forever; zero-usage is opt-in per
|
|
917
|
-
user by choosing the engine.
|
|
918
|
-
- The `/agy doctor` Gate B watch stays armed as INFORMATIONAL: it prints
|
|
919
|
-
"acp tokens: AVAILABLE" if upstream ever ships usage, at which point the
|
|
920
|
-
mapping is a small additive job.
|
|
921
|
-
|
|
922
|
-
Soft items to ship alongside the flip (not blockers):
|
|
923
|
-
|
|
924
|
-
1. Clean-machine first-run: ACP as DEFAULT means fresh installs hit the
|
|
925
|
-
self-setup path (binary install + auth bootstrap) immediately. Self-heal
|
|
926
|
-
exists; never tested as the first-run experience. Test once on a clean
|
|
927
|
-
env.
|
|
928
|
-
2. User-visible abort change: Esc on ACP = kill + reconnect + reload (RC01
|
|
929
|
-
has no `session/cancel`). Document in README and `/agy status`.
|
|
930
|
-
3. Pull soak evidence from the daily logs (warn rates per engine, 1.4.9+)
|
|
931
|
-
and attach to this section.
|
|
932
|
-
4. Note that `AskAntigravity` stays on `agy -p` regardless (phase 4+).
|
|
933
|
-
|
|
934
|
-
Mechanics of the flip (minutes): default in `src/config.ts` + the
|
|
935
|
-
`acp-config` test default + README engine table + AGENTS.md + beta wording.
|
|
936
|
-
`AGY_ENGINE` env override keeps an escape hatch either way.
|
|
937
|
-
|
|
938
|
-
Recommendation on record: Gate B is no longer a condition. Remaining
|
|
939
|
-
pre-flip work is the soft items above; the flip itself is a small,
|
|
940
|
-
mechanical change whenever the soak cycle is judged complete.
|