@estebanforge/pi-antigravity-bridge 1.3.0 → 1.3.2
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 +19 -0
- package/README.md +17 -41
- package/docs/ANTIGRAVITY-INTEGRATIONS.md +2 -0
- package/docs/ARCHITECTURE.md +38 -25
- package/docs/DEVELOPMENT.md +16 -22
- package/docs/PI-BRIDGE-GAPS.md +65 -82
- package/extensions/index.ts +2 -5
- package/package.json +2 -4
- package/src/config.ts +0 -13
- package/src/provider.ts +9 -181
- package/src/poller.ts +0 -202
- package/src/protobuf.ts +0 -184
- package/src/runner.ts +0 -390
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.2] - 2026-09-01
|
|
6
|
+
|
|
7
|
+
### Removed
|
|
8
|
+
|
|
9
|
+
- The `legacy-sqlite` fallback engine: `src/runner.ts`, `src/poller.ts`, `src/protobuf.ts`, the `run-agy` and `decode-db` scripts, and the `engine` config key / `AGY_ENGINE` env var. agy 1.1.18 changed step-row storage to a two-phase write (a placeholder row first, grown in place later); the polling engine read each row once as an empty placeholder and never re-read it, so turns completed with the full reply in the database and zero text in pi (issue #1). The engine decoded an undocumented storage format, so every agy storage change risked repeating that failure silently. The stream-json engine shares none of that code path; verified live against agy 1.1.18-era storage (1.1.23 installed). A stale `engine` value in an existing `config.json` is ignored.
|
|
10
|
+
Reported by @imatimba in #1. Thanks for the exact repro and the root-cause analysis; the report drove this removal.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `scripts/test-provider.ts` wires the stream-json driver explicitly (it exercised the legacy path implicitly before).
|
|
15
|
+
- `tests/provider-streaming.test.ts` covers effort mapping against a fake driver. The legacy event-mapping tests died with the engine; stream-json event coverage lives in `tests/stream-roundtrip.test.ts`.
|
|
16
|
+
|
|
17
|
+
## [1.3.1] - 2026-08-31
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Docs-only release. README and package description now describe the 1.3.0 reality: `stream-json` engine as default, no-patch tool bridge, `/agy doctor` + `/agy patch-cleanup`, live token usage. The 1.3.0 tarball shipped the pre-rewrite README, so npm and the pi.dev package gallery still showed the patch-era docs; this republish refreshes the registry metadata.
|
|
22
|
+
|
|
23
|
+
|
|
5
24
|
## [1.3.0] - 2026-08-31
|
|
6
25
|
|
|
7
26
|
### Added
|
package/README.md
CHANGED
|
@@ -8,25 +8,25 @@ If you also have [`@estebanforge/pi-ask-antigravity`](https://github.com/Esteban
|
|
|
8
8
|
|
|
9
9
|
## What it does
|
|
10
10
|
|
|
11
|
-
You pick a Gemini model in pi's `/model` picker. pi routes each turn through this provider.
|
|
11
|
+
You pick a Gemini model in pi's `/model` picker. pi routes each turn through this provider. A single persistent `agy` process runs in your workspace; pi feeds it each turn, parses its stream-json events, and streams the agent text back into pi token by token. Token usage is live.
|
|
12
12
|
|
|
13
13
|
Multi-turn works. The provider binds a pi session to an agy conversation id (persisted under `~/.pi/agent/antigravity-bridge/sessions.json`) and resumes it on the next turn via `--conversation <id>`. agy keeps its own history, so only the latest user message is sent each turn.
|
|
14
14
|
|
|
15
15
|
## What it cannot do
|
|
16
16
|
|
|
17
|
-
agy runs its own closed tool loop (`read_file`, `write_file`, `edit_file`, `run_command`) against `--add-dir`.
|
|
17
|
+
agy runs its own closed tool loop (`read_file`, `write_file`, `edit_file`, `run_command`) against `--add-dir`. Its read-only steps (`view_file`, `list_dir`, `grep_search`, `find_by_name`) re-run as real pi builtins (`read`, `ls`, `grep`, `find`) so their cards render natively; mutating steps never execute in pi - they replay through a display-only `antigravity` wrapper tool. What used to be a hard wall for pi's other tools is bridgeable; see [MCP tool bridge](#mcp-tool-bridge-agy-uses-pis-tools) below.
|
|
18
18
|
|
|
19
19
|
Residual limits (with or without the bridge):
|
|
20
20
|
|
|
21
21
|
- agy's own edits still land directly on disk; pi's inline diff review does not engage for them.
|
|
22
22
|
- agy commands run without per-action approval, same as every other tool in pi. See [Permissions](#permissions) below.
|
|
23
|
-
- No
|
|
23
|
+
- No cost accounting: cost stays zero because agy runs on your subscription quota. Token usage is live.
|
|
24
24
|
|
|
25
25
|
## MCP tool bridge (agy uses pi's tools)
|
|
26
26
|
|
|
27
27
|
While agy is the active model it normally cannot see pi's universe of extensions: agentmemory, codegraph, web search, slack/asana, the `Ask*` delegations, and any other installed pi tool. This extension optionally bridges that gap.
|
|
28
28
|
|
|
29
|
-
The bridge starts a localhost MCP server inside pi's process. `tools/list` returns pi's registered tools (built-in file/shell tools and `AskAntigravity` are filtered out), and `tools/call`
|
|
29
|
+
The bridge starts a localhost MCP server inside pi's process. `tools/list` returns pi's registered tools (built-in file/shell tools and `AskAntigravity` are filtered out), and a `tools/call` routes into pi's own tool loop via the round-trip described below. agy discovers the server through a per-invocation config: the bridge writes `.agents/mcp_config.json` into a bridge-controlled dir (`~/.pi/agent/antigravity-bridge/agy-mcp-<pid>/`) and the provider passes that dir as an extra `--add-dir` when it spawns agy. The user's global agy config (`~/.gemini/config/mcp_config.json`) is never touched, so standalone agy outside pi is unaffected.
|
|
30
30
|
|
|
31
31
|
**No patch required.** Bridge calls park in the provider's round-trip store; the provider ends the pi assistant message with a `toolUse` stop reason for the real pi tool, pi executes it in its own loop (native cards, permissions, hooks), and the toolResult completes the parked MCP response on the next stream call. This is the same mechanism tianzuo/pi-antigravity uses; upstream pi APIs only.
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ The bridge starts a localhost MCP server inside pi's process. `tools/list` retur
|
|
|
36
36
|
|
|
37
37
|
**Security.** The MCP server binds to `127.0.0.1` only and requires a per-session shared-secret header (`x-bridge-token`) that agy sends from the bridge config; browsers cannot set custom headers on a simple cross-origin POST, so this blocks web CSRF against the loopback server. Request bodies are size-capped. This is intended for single-user developer machines: any local process running as the same user can read the token from the per-pid config and call the exposed tools, so do not run it on a shared host where you do not trust other same-user processes.
|
|
38
38
|
|
|
39
|
-
### Native cards, wrapper replay, and skills
|
|
39
|
+
### Native cards, wrapper replay, and skills
|
|
40
40
|
|
|
41
41
|
Read-only agy steps (view_file, list_dir, grep_search, find_by_name) re-run as
|
|
42
42
|
real pi builtins (`read`, `ls`, `grep`, `find`) when those builtins are active,
|
|
@@ -48,35 +48,12 @@ anything with side effects.
|
|
|
48
48
|
|
|
49
49
|
When the bridge is on, agy also gets one `activate_skill` tool whose enum is
|
|
50
50
|
your pi Agent Skills catalog; calling it returns the SKILL.md body. The bridge
|
|
51
|
-
answers it directly, no pi round-trip. `/agy doctor` prints
|
|
52
|
-
|
|
53
|
-
tokens.
|
|
51
|
+
answers it directly, no pi round-trip. `/agy doctor` prints driver counters,
|
|
52
|
+
bridge port, and the last lifecycle events without spending tokens.
|
|
54
53
|
|
|
55
54
|
## Install
|
|
56
55
|
|
|
57
|
-
>
|
|
58
|
-
> the running pi lacks `pi.invokeTool()`, it **asks you once** whether to edit
|
|
59
|
-
> files inside your globally-installed `@earendil-works/pi-coding-agent/dist/`
|
|
60
|
-
> (adding one method) to enable the MCP tool bridge. This is, for now, the only
|
|
61
|
-
> way agy can use Pi internal tooling.
|
|
62
|
-
>
|
|
63
|
-
> - **Yes** → applies the patch (reversible via `/agy patch restore`) and tells
|
|
64
|
-
> you to restart pi. The bridge starts on the next launch.
|
|
65
|
-
>
|
|
66
|
-
> - **No** → it remembers your choice and stays silent; it won't ask again until
|
|
67
|
-
> you run `/agy patch apply`. The provider and AskAntigravity tool keep working;
|
|
68
|
-
> only the MCP tool bridge stays off.
|
|
69
|
-
>
|
|
70
|
-
> - The apply is **idempotent & safe** (only what's missing; aborts cleanly if a
|
|
71
|
-
> pi update moved the code), **backed up** (under
|
|
72
|
-
> `~/.pi/agent/antigravity-bridge/pi-patch-backup/`), and **self-healing** (a
|
|
73
|
-
> `pi` reinstall/update wipes `dist/`; re-applied on the next start).
|
|
74
|
-
>
|
|
75
|
-
> The patch only takes effect after a **full `pi` restart** (quit + relaunch) —
|
|
76
|
-
> `/reload` is **not** enough, because pi caches its compiled core for the
|
|
77
|
-
> process.
|
|
78
|
-
>
|
|
79
|
-
> Details for the patch can be found in [docs/PI-INVOKETOOL-PATCH.md](docs/PI-INVOKETOOL-PATCH.md).
|
|
56
|
+
> **No patch required.** The bridge runs on pi's public APIs only; the extension never edits your pi install. If an older version of this extension patched your pi (adding `pi.invokeTool()`), the leftover is inert and a pi update removes it. The extension detects it once and offers `/agy patch-cleanup` to restore the original files from the backup immediately.
|
|
80
57
|
|
|
81
58
|
Install with pi's package manager:
|
|
82
59
|
|
|
@@ -86,8 +63,6 @@ pi install npm:@estebanforge/pi-antigravity-bridge
|
|
|
86
63
|
|
|
87
64
|
Requires the **`agy` CLI** installed and authenticated. If you don't have it, follow Google's [official install guide](https://antigravity.google/docs/cli/install) for your platform, then run `agy` once to complete Google OAuth. The extension resolves `agy` on `$PATH`, or via the `AGY_BIN` environment variable.
|
|
88
65
|
|
|
89
|
-
Also requires Node 22.5 or newer (uses the built-in `node:sqlite`).
|
|
90
|
-
|
|
91
66
|
## Usage
|
|
92
67
|
|
|
93
68
|
Pick a model and talk to pi as usual:
|
|
@@ -108,17 +83,16 @@ Model ids are slugified from the `agy models` output (`Gemini 3.6 Flash (Medium)
|
|
|
108
83
|
|
|
109
84
|
If `agy models` fails at load (binary missing, auth not done, network stall), a fallback catalog still populates the picker so you get a clear runtime error instead of an empty list.
|
|
110
85
|
|
|
111
|
-
###
|
|
86
|
+
### Bridge surface
|
|
112
87
|
|
|
113
|
-
`config.json` selects the
|
|
88
|
+
`config.json` selects the bridge surface:
|
|
114
89
|
|
|
115
90
|
| Key | Values | Default |
|
|
116
91
|
| --- | --- | --- |
|
|
117
|
-
| `engine` | `stream-json` (persistent agy process, toolUse round-trips, live usage) or `legacy-sqlite` (spawn `agy -p`, poll its SQLite) | `stream-json` |
|
|
118
92
|
| `bridgeTools` | `none` (bridge off), `mcp` (pi-mcp-adapter tools), `all` (every non-builtin tool, incl. other `Ask*` delegations) | `mcp` |
|
|
119
93
|
| `digest` | `off` (stable prompts; agy's prompt cache hits) or `on` (inject a delta of pi-side context - compaction summaries, other-provider turns - into each agy prompt; the delta changes every turn, so agy re-bills the full context). Enable for mixed-provider sessions where agy must see pi-side context | `off` |
|
|
120
94
|
|
|
121
|
-
Env overrides: `
|
|
95
|
+
Env overrides: `AGY_BRIDGE_TOOLS`, `AGY_DIGEST`.
|
|
122
96
|
|
|
123
97
|
### The /agy command
|
|
124
98
|
|
|
@@ -127,12 +101,14 @@ Env overrides: `AGY_ENGINE`, `AGY_BRIDGE_TOOLS`, `AGY_DIGEST`. The `legacy-sqlit
|
|
|
127
101
|
```
|
|
128
102
|
/agy status, or open the mode/permissions/model/thinking picker (TUI)
|
|
129
103
|
/agy status print current mode, permissions, model + session counts
|
|
104
|
+
/agy doctor bridge state, driver counters, bridge port, last lifecycle events
|
|
130
105
|
/agy mode plan review-only: agy plans but writes nothing
|
|
131
106
|
/agy mode accept-edits agy applies edits directly (default)
|
|
132
107
|
/agy permissions on|off auto-approve / prompt for tool calls (see warning)
|
|
133
108
|
/agy model flash|pro|gemini default model alias for the AskAntigravity tool
|
|
134
109
|
/agy thinking low|medium|high default thinking tier for the AskAntigravity tool
|
|
135
|
-
/agy
|
|
110
|
+
/agy digest on|off inject pi-side context into agy prompts (default off; see table above)
|
|
111
|
+
/agy patch-cleanup restore the original pi files if an older version patched them
|
|
136
112
|
/agy clear drop all session bindings (force fresh conversations)
|
|
137
113
|
```
|
|
138
114
|
|
|
@@ -140,7 +116,7 @@ Env overrides: `AGY_ENGINE`, `AGY_BRIDGE_TOOLS`, `AGY_DIGEST`. The `legacy-sqlit
|
|
|
140
116
|
|
|
141
117
|
pi itself has no built-in approval gate. Unlike codex, claude, or agy running interactively, pi does not prompt you to confirm each tool action before it runs. That is the host environment this extension lives in.
|
|
142
118
|
|
|
143
|
-
Because agy
|
|
119
|
+
Because agy runs non-interactively under this provider (nothing can answer a `y/n` prompt), this extension passes `--dangerously-skip-permissions` by default. It is technically necessary: `accept-edits` auto-approves file edits but not shell commands, so a `run_command` would otherwise hang forever waiting for a prompt nothing can answer (upstream [google-antigravity/antigravity-cli#318](https://github.com/google-antigravity/antigravity-cli/issues/318)). The net effect is that agy executes commands the same way pi already executes your other tools: without per-action review.
|
|
144
120
|
|
|
145
121
|
If you want agy to execute nothing, use `/agy mode plan`. Do not combine `--sandbox` with skip-permissions ([#36](https://github.com/google-antigravity/antigravity-cli/issues/36)).
|
|
146
122
|
|
|
@@ -162,13 +138,13 @@ For isolation when running any agent that executes commands without a confirmati
|
|
|
162
138
|
|
|
163
139
|
## Development
|
|
164
140
|
|
|
165
|
-
Build, test, and debug instructions live in [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). For the internal architecture (
|
|
141
|
+
Build, test, and debug instructions live in [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). For the internal architecture (engines, bridge round-trips, conversation discovery) see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
166
142
|
|
|
167
143
|
## Terms of Service notice
|
|
168
144
|
|
|
169
145
|
Google's [Antigravity ToS](https://antigravity.google/terms) (Section 6) prohibits accessing the service "in connection with products not provided by us", and names as its example using tools like Hermes/OpenClaw with Antigravity OAuth. That targets reusing your credentials in a non-Google harness that calls Google's backend directly.
|
|
170
146
|
|
|
171
|
-
This extension does not do that. It spawns the official, unmodified `agy` binary as a subprocess; `agy` performs its own OAuth and makes its own calls to Google. This code never sees, extracts, or reuses your token, and never contacts Antigravity's backend. It only reads
|
|
147
|
+
This extension does not do that. It spawns the official, unmodified `agy` binary as a subprocess; `agy` performs its own OAuth and makes its own calls to Google. This code never sees, extracts, or reuses your token, and never contacts Antigravity's backend. It only reads what `agy` itself produces locally: its stream-json output. From Google's server-side view there is no signal that distinguishes "agy launched by pi" from "agy launched by a terminal, an IDE task runner, or cron": same signed binary, same authenticated calls.
|
|
172
148
|
|
|
173
149
|
Google's reported enforcement to date (the February 2026 suspensions) targeted token-reuse tools, not spawning the official CLI.
|
|
174
150
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Date: 2026-08-21. Sources: the official VSIX `Google.google-antigravity_1.0.0` (marketplace.visualstudio.com/items?itemName=Google.google-antigravity, unpacked at `~/Downloads/Google.google-antigravity_1.0.0`), Zed's external-agents registry cache (`~/Library/Application Support/Zed/external_agents/registry/registry.json`), the ACP release zip from `dl.google.com`, and the binaries installed on this machine. I verified everything below by direct inspection or live execution unless marked otherwise. Section 8 has the reproduction commands.
|
|
4
4
|
|
|
5
|
+
> **2026-08-31 (1.3.0) update:** the roadmap sections below predate 1.3.0 and assume the `pi.invokeTool` patch (`src/patcher.ts`, `docs/PI-INVOKETOOL-PATCH.md`) stays. 1.3.0 removed the patch entirely: the MCP tool bridge now runs no-patch via the provider's toolUse round-trip, and `AGY_ENGINE=stream-json` (persistent process) is the default turn engine. Treat every patch-dependent step in sections 9.x as needing rework against the round-trip path; the reverse-engineered protocol facts (sections 1-8) are unaffected.
|
|
6
|
+
|
|
5
7
|
## 0. Executive summary
|
|
6
8
|
|
|
7
9
|
Google ships two official mechanisms for driving Antigravity from an editor, plus one hidden one:
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -2,46 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
How the provider works internally. For build/test/debug workflow see [DEVELOPMENT.md](./DEVELOPMENT.md).
|
|
4
4
|
|
|
5
|
+
## Turn engine
|
|
6
|
+
|
|
7
|
+
The provider runs one turn engine: a long-lived `agy --input-format stream-json --output-format stream-json` process per provider. Turns are fed over stdin; agy emits NDJSON events on stdout; the driver parses them and streams text into pi token by token. Conversation binding comes from the `init` event, tool steps arrive as typed events (no protobuf decoding), and token usage is live.
|
|
8
|
+
|
|
9
|
+
Shared infrastructure: session binding (`sessions.json`), runtime config, the `AskAntigravity` tool, the MCP tool bridge surface, and the G1 context digest (off by default - see below).
|
|
10
|
+
|
|
5
11
|
## Module map
|
|
6
12
|
|
|
7
13
|
```
|
|
8
|
-
extensions/index.ts
|
|
9
|
-
src/provider.ts streamSimple: pi Context -> agy turn -> pi event stream
|
|
10
|
-
src/
|
|
11
|
-
src/
|
|
12
|
-
src/
|
|
13
|
-
src/
|
|
14
|
-
src/
|
|
15
|
-
src/
|
|
16
|
-
src/
|
|
14
|
+
extensions/index.ts pi extension entry: provider registration, model discovery, /agy command, lifecycle notices
|
|
15
|
+
src/provider.ts streamSimple: pi Context -> agy turn -> pi event stream; owns the G9 round-trip store and the G1 digest
|
|
16
|
+
src/driver.ts stream-json driver: persistent agy process, turn serialization, conversation binding, idle/abort timers
|
|
17
|
+
src/stream-events.ts agy NDJSON event parser (init / step_update / result) + usage mapping onto pi's Usage
|
|
18
|
+
src/native-tools.ts maps agy read-only tool steps to real pi builtins (read/ls/grep/find) for native re-execution
|
|
19
|
+
src/skills.ts activate_skill bridge: exposes the pi Agent Skills catalog to agy, answered by the bridge directly
|
|
20
|
+
src/patch-cleanup.ts detects a leftover invokeTool patch from pre-1.3.0 installs; /agy patch-cleanup restores the backup
|
|
21
|
+
src/discovery.ts conversation-id binding for the AskAntigravity one-shot tool (agy -p never prints its conversation id)
|
|
22
|
+
src/models.ts agy models -> pi Model projection (full catalog, per-model effort)
|
|
23
|
+
src/sessions.ts atomic JSON store: pi session -> agy conversation + watermark
|
|
24
|
+
src/config.ts persisted runtime config (bridgeTools, digest, mode, permissions, model/thinking defaults)
|
|
17
25
|
src/ask-tool.ts the AskAntigravity one-shot delegation tool (model/thinking defaults)
|
|
18
|
-
src/mcp-server.ts MCP tool bridge:
|
|
26
|
+
src/mcp-server.ts MCP tool bridge server: ferries tools/list + tools/call; calls park in the provider round-trip
|
|
19
27
|
src/diff-render.ts render agy's file edits as git diffs in pi's thinking stream
|
|
20
28
|
```
|
|
21
29
|
|
|
22
|
-
No generated protobuf code, no
|
|
30
|
+
No generated protobuf code, no SQLite dependency.
|
|
23
31
|
|
|
24
|
-
##
|
|
32
|
+
## Stream-json engine
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
### Process and events
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
The driver spawns `agy --input-format stream-json --output-format stream-json` once per provider and keeps it alive across turns (`/agy doctor` shows the reuse counter). A turn writes the prompt to stdin and reads NDJSON events until the terminal `result`:
|
|
29
37
|
|
|
30
|
-
|
|
|
38
|
+
| event | meaning |
|
|
31
39
|
| --- | --- |
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
40
|
+
| `init` | conversation binding (`conversation_id`); the driver remembers it and resumes later turns via `--conversation <id>` |
|
|
41
|
+
| `step_update` | `user_input` / `checkpoint` / `agent_response` / `tool` steps; agent text arrives as `text_delta` on live agy (1.1.13+), with `usage` attached |
|
|
42
|
+
| `result` | terminal; live builds report status `SUCCESS` (older builds `OK` - both accepted) |
|
|
43
|
+
|
|
44
|
+
Unknown event kinds parse as `{kind:"unknown"}` so a future agy release degrades instead of crashing the reader loop. Shapes were captured from live output and cross-checked against tianzuo/pi-antigravity `lib/events.ts` (MIT).
|
|
45
|
+
|
|
46
|
+
Usage maps onto pi's `Usage` (input/output/thinking/cache-read tokens); cost stays zero because agy runs on subscription quota.
|
|
47
|
+
|
|
48
|
+
### No-patch tool round-trip (G9)
|
|
36
49
|
|
|
37
|
-
|
|
50
|
+
The MCP bridge server executes no tools itself. A `tools/call` parks in the provider's round-trip store; the provider ends the current pi assistant message with a `toolUse` stop reason for the real pi tool; pi executes it in its own loop (native cards, permissions, hooks); the `toolResult` completes the parked MCP response on the next stream call. No pi patch, no privileged API.
|
|
38
51
|
|
|
39
|
-
|
|
52
|
+
Display follows the same split: agy read-only steps (`view_file`, `list_dir`, `grep_search`, `find_by_name`) re-run as real pi builtins via `native-tools.ts`, so their cards render with pi's own renderers. Mutating and agy-specialty steps replay through a display-only `antigravity` wrapper tool - recorded output only, nothing re-executes. The skills bridge exposes one `activate_skill` tool whose enum is the pi Agent Skills catalog; the bridge answers it directly, no round-trip.
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
### Context digest (G1)
|
|
42
55
|
|
|
43
|
-
|
|
56
|
+
By default the prompt agy receives is only the latest user message: agy keeps its own history. When `config.digest` is on (`AGY_DIGEST`, `/agy digest on`), the provider prepends a DELTA digest of pi-side context agy was not spawned for - compaction summaries, other-provider turns, pi-tool results. Off by default because the digest changes every turn and defeats agy's server-side prompt cache (~25-30k tokens re-billed per turn). Enable it for mixed-provider sessions where agy must see pi-side context; pure antigravity sessions gain nothing, and bridge round-trips deliver tool results through the bridge, not the digest.
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
### Removed: the legacy-sqlite engine (1.3.2)
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
The pre-1.3.0 engine (spawn `agy -p`, poll the SQLite conversation DB, decode protobuf step payloads) was removed in 1.3.2. agy 1.1.18 changed the step-row storage to a two-phase write (a metadata-only placeholder row that grows in place), which the polling decoder read once as an empty placeholder and never re-read: turns completed with the full reply in the database and zero text streamed to pi (issue #1, reported by @imatimba). The engine reverse-engineered an undocumented storage format, so every agy storage change risked repeating that silent failure. The stream-json engine shares none of that code path and is unaffected by storage-format changes. `AGY_ENGINE` and the `engine` config key are gone; a stale value in an existing `config.json` is ignored.
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -6,7 +6,7 @@ How to build, test, and debug this extension outside pi.
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install
|
|
9
|
-
npm test # unit tests (
|
|
9
|
+
npm test # unit tests via vitest (no agy spawn, no network)
|
|
10
10
|
npm run build # tsc --noEmit type check
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -14,22 +14,9 @@ The integration scripts below spawn a real `agy` process and need a logged-in ac
|
|
|
14
14
|
|
|
15
15
|
## Standalone scripts
|
|
16
16
|
|
|
17
|
-
These exercise the pipeline without pi. Useful for isolating where a bug lives (
|
|
17
|
+
These exercise the pipeline without pi. Useful for isolating where a bug lives (driver? provider? pi loader?).
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
# Decode any conversation DB and print agent text + tool calls.
|
|
21
|
-
# Accepts a UUID (resolved against ~/.gemini/antigravity-cli/conversations/)
|
|
22
|
-
# or an absolute path. Fastest way to check the protobuf decoder against
|
|
23
|
-
# real data. No agy spawn, no network.
|
|
24
|
-
npm run decode-db -- <uuid-or-path>
|
|
25
|
-
|
|
26
|
-
# Spawn agy and stream decoded events to stdout with timestamps. Proves the
|
|
27
|
-
# concurrent poll loop actually streams (events arrive during the run, not
|
|
28
|
-
# only at exit). Use this to reproduce a hang or a missing-event bug.
|
|
29
|
-
npm run run-agy -- "Say hello"
|
|
30
|
-
npm run run-agy -- --model "Gemini 3.6 Flash (Medium)" --mode plan "Review src/protobuf.ts"
|
|
31
|
-
npm run run-agy -- --conversation <uuid> "follow up" # resume a turn
|
|
32
|
-
|
|
33
20
|
# Drive the provider's streamSimple directly (no pi TUI) and assert the
|
|
34
21
|
# full event lifecycle: start -> text_start -> text_delta -> text_end ->
|
|
35
22
|
# done. The closest thing to a pi turn without pi.
|
|
@@ -42,23 +29,30 @@ npx tsx scripts/test-extension.ts
|
|
|
42
29
|
# Load the extension through pi's REAL loader and confirm the antigravity/*
|
|
43
30
|
# models register. This is the in-pi smoke test.
|
|
44
31
|
npm run smoke:pi
|
|
32
|
+
|
|
33
|
+
# Live smoke for the stream-json engine. OPT-IN: spends a little Antigravity
|
|
34
|
+
# quota. Proves the persistent process: init binds a conversation, text deltas
|
|
35
|
+
# arrive, the result settles, and a second turn reuses the process.
|
|
36
|
+
AGY_LIVE=1 node --experimental-strip-types scripts/smoke-stream-json.mjs
|
|
45
37
|
```
|
|
46
38
|
|
|
47
39
|
## Debugging a hang or "stuck" turn
|
|
48
40
|
|
|
49
41
|
Most "stuck" reports trace to one of:
|
|
50
42
|
|
|
51
|
-
1. **agy blocked on a permission prompt.** `accept-edits` auto-approves file edits but NOT shell commands. Any `run_command` prompts `y/n`, which hangs forever in non-interactive
|
|
52
|
-
2. **agy never started.** Check `AGY_BIN` is on PATH (or set explicitly). The
|
|
53
|
-
3. **Conversation id never bound.**
|
|
43
|
+
1. **agy blocked on a permission prompt.** `accept-edits` auto-approves file edits but NOT shell commands. Any `run_command` prompts `y/n`, which hangs forever in non-interactive mode. The provider passes `--dangerously-skip-permissions` by default to avoid this. If you turned it off (`/agy permissions off`), that is why. See the README Permissions section.
|
|
44
|
+
2. **agy never started.** Check `AGY_BIN` is on PATH (or set explicitly). The spawner swallows spawn ENOENT into the result's stderr, surfaced by the provider as an error event.
|
|
45
|
+
3. **Conversation id never bound.** On `stream-json` the `init` event carries the id, so a missing binding means the turn never produced a result event. `/agy doctor` prints the last lifecycle events.
|
|
54
46
|
4. **Print-mode environmental hang.** `pi -p` can hang with zero output in some containers (upstream [google-antigravity/antigravity-cli#318](https://github.com/google-antigravity/antigravity-cli/issues/318)). It affects built-in providers too, not this extension. Validate the turn with `scripts/test-provider.ts` instead.
|
|
55
47
|
|
|
56
48
|
## Regression tests worth knowing
|
|
57
49
|
|
|
58
|
-
- `tests/
|
|
59
|
-
- `tests/
|
|
60
|
-
- `tests/
|
|
50
|
+
- `tests/stream-roundtrip.test.ts` - the stream-json engine pieces: NDJSON parser, native re-exec mapping, and the no-patch toolUse round-trip store.
|
|
51
|
+
- `tests/provider-streaming.test.ts` - drives streamSimple with an injected fake driver (no agy) and asserts how pi's reasoning level maps onto the agy `--effort` tier (forward, clamp, omit).
|
|
52
|
+
- `tests/provider-digest.test.ts` - the G1 context digest builder: injects pi-side context without replaying agy's own history.
|
|
53
|
+
- `tests/patch-cleanup.test.ts` - legacy-patch detection and restore, real fs via tmpdirs, no mocks.
|
|
54
|
+
- `tests/mcp-server.test.ts` - the MCP tool bridge end-to-end against a real (port 0) server: capability gate, per-pid config lifecycle, shared-secret token gate, 1 MB body cap, protocol-version clamp. The provider owns the tool catalog and the round-trip; the server only ferries list/call.
|
|
61
55
|
|
|
62
56
|
## Module map
|
|
63
57
|
|
|
64
|
-
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the module map and the
|
|
58
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the module map and the engine internals (stream-json events, no-patch round-trip).
|
package/docs/PI-BRIDGE-GAPS.md
CHANGED
|
@@ -2,71 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
Status of the MCP tool bridge between agy (Antigravity CLI, used as pi's Gemini
|
|
4
4
|
provider) and pi's extension/builtin tools. This doc tracks **open gaps only**.
|
|
5
|
-
Shipped work lives in `CHANGELOG.md` (most recently:
|
|
6
|
-
|
|
7
|
-
are listed at the end under "Discarded
|
|
5
|
+
Shipped work lives in `CHANGELOG.md` (most recently, 1.3.0: the stream-json
|
|
6
|
+
engine and the no-patch toolUse round-trip that replaced `pi.invokeTool`).
|
|
7
|
+
Ideas that were weighed and rejected are listed at the end under "Discarded
|
|
8
|
+
ideas".
|
|
8
9
|
|
|
9
10
|
## What the bridge already does
|
|
10
11
|
|
|
11
|
-
agy -> bridge MCP server
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
agy -> bridge MCP server `tools/call` -> the call parks in the provider's
|
|
13
|
+
round-trip store -> the provider ends the pi assistant message with a
|
|
14
|
+
`toolUse` stop reason for the real pi tool -> pi executes it in its own loop
|
|
15
|
+
(native cards, permissions, hooks) -> the `toolResult` completes the parked
|
|
16
|
+
MCP response on the next stream call. No pi patch. Verified end-to-end with
|
|
17
|
+
`memory_search` and `ask_user_question`. The bridge exposes pi's extension
|
|
18
|
+
tools (builtins are filtered out since agy has native equivalents;
|
|
19
|
+
`AskAntigravity` is filtered to avoid recursion).
|
|
16
20
|
|
|
17
21
|
What this means in practice: agy can read/write files, use memory, navigate
|
|
18
22
|
code with codegraph, search the web, post to Slack, create Asana tasks, spawn
|
|
19
23
|
subagents, prompt the user with `ask_user_question`, and delegate to peer
|
|
20
24
|
reviewers (Claude, Codex, Antigravity), all by going through pi's installed
|
|
21
|
-
tooling instead of its own. Tools run in pi's process with pi's own
|
|
22
|
-
so a secret never crosses the bridge
|
|
23
|
-
|
|
24
|
-
pi-side context (compaction summaries,
|
|
25
|
-
|
|
25
|
+
tooling instead of its own. Tools run in pi's process with pi's own
|
|
26
|
+
credentials, so a secret never crosses the bridge, and a long call renders in
|
|
27
|
+
pi's native UI while it runs. agy's file edits surface as git-sourced diffs in
|
|
28
|
+
pi's thinking stream. A delta digest of pi-side context (compaction summaries,
|
|
29
|
+
other-provider turns) is available but OFF by default (`/agy digest on`): the
|
|
30
|
+
digest changes every turn and defeats agy's server-side prompt cache.
|
|
26
31
|
|
|
27
32
|
## Open gaps
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
Two gaps remain. Both now sit on the no-patch round-trip path, so closing them
|
|
35
|
+
means provider- or bridge-side work only; there is no pi dist patch to extend
|
|
36
|
+
anymore. Ordered by impact.
|
|
32
37
|
|
|
33
|
-
**Numbering note:** the G1/G2
|
|
34
|
-
open set, NOT the historical
|
|
35
|
-
G1 = conversation-history digest
|
|
36
|
-
(shipped
|
|
38
|
+
**Numbering note:** the G1/G2 labels below are this living doc's renumbered
|
|
39
|
+
open set, NOT the historical G-numbers. In the historical list (`CHANGELOG.md`
|
|
40
|
+
and the comments in `src/provider.ts`) G1 = conversation-history digest
|
|
41
|
+
(shipped 1.0.0, now opt-in via `config.digest`) and G9 = the no-patch toolUse
|
|
42
|
+
round-trip (shipped 1.3.0).
|
|
37
43
|
|
|
38
44
|
---
|
|
39
45
|
|
|
40
|
-
### G1.
|
|
41
|
-
|
|
42
|
-
**Status:** Open
|
|
43
|
-
**Objective:** Stop blocking on long tools (`web_research`, `librarian`,
|
|
44
|
-
`codegraph_explore` on big repos). Push partial output back to agy so pi's UI
|
|
45
|
-
shows live progress instead of a frozen spinner.
|
|
46
|
-
|
|
47
|
-
**Why:** Today the bridge blocks until the tool returns. The user has no signal
|
|
48
|
-
that work is happening. This is partly a pi-side gap (most long tools do not
|
|
49
|
-
emit progress) and partly a bridge-transport gap.
|
|
50
|
-
|
|
51
|
-
**Scope:**
|
|
52
|
-
- `docs/PI-INVOKETOOL-PATCH.md`: expose pi's progress bus.
|
|
53
|
-
- `src/mcp-server.ts`: switch from blocking `invokeTool` to a streaming RPC
|
|
54
|
-
using MCP `notifications/progress` (or a `pi_tool_progress` SSE channel).
|
|
55
|
-
- pi-side: audit long tools and add progress emission where missing.
|
|
56
|
-
|
|
57
|
-
**Acceptance criteria:**
|
|
58
|
-
- [ ] A tool that runs >1s emits at least one progress notification.
|
|
59
|
-
- [ ] pi's TUI spinner updates during the call, not only on completion.
|
|
60
|
-
- [ ] Result content is identical to the blocking path (no data loss).
|
|
61
|
-
- [ ] Fallback: if a tool does not emit progress, behavior matches today.
|
|
62
|
-
|
|
63
|
-
**Effort:** Large. Touches pi's progress bus and the MCP transport.
|
|
64
|
-
|
|
65
|
-
**Blocks:** None. **Blocked by:** None.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
### G2. Expose pi's UI primitives [MEDIUM-HIGH IMPACT]
|
|
46
|
+
### G1. Expose pi's UI primitives [MEDIUM-HIGH IMPACT]
|
|
70
47
|
|
|
71
48
|
**Status:** Open
|
|
72
49
|
**Objective:** Let agy drive pi's native UI: confirm dialogs, toasts,
|
|
@@ -80,7 +57,9 @@ notification toast (for "task started" / "save ok"), native file picker
|
|
|
80
57
|
for agy edits, that path is structurally closed (see G8 in `CHANGELOG.md`).
|
|
81
58
|
|
|
82
59
|
**Scope:**
|
|
83
|
-
-
|
|
60
|
+
- pi-side: confirm a public API surface for these primitives. The old plan of
|
|
61
|
+
patching `AgentSession.ui` into pi's dist is dead; the bridge no longer
|
|
62
|
+
patches pi.
|
|
84
63
|
- `src/mcp-server.ts`: wrappers for `pi_confirm`, `pi_notify`,
|
|
85
64
|
`pi_select_file`, `pi_select_directory`, `pi_set_status`.
|
|
86
65
|
|
|
@@ -91,29 +70,30 @@ for agy edits, that path is structurally closed (see G8 in `CHANGELOG.md`).
|
|
|
91
70
|
- [ ] `pi_set_status(text)` updates the footer; clears on empty string.
|
|
92
71
|
- [ ] Tests cover each primitive with a mocked `ui` seam.
|
|
93
72
|
|
|
94
|
-
**Effort:** Medium-large
|
|
73
|
+
**Effort:** Medium-large, gated on pi exposing the primitives without a patch.
|
|
95
74
|
|
|
96
|
-
**Blocks:** None. **Blocked by:**
|
|
75
|
+
**Blocks:** None. **Blocked by:** pi-side API availability.
|
|
97
76
|
|
|
98
77
|
---
|
|
99
78
|
|
|
100
|
-
###
|
|
79
|
+
### G2. Lifecycle event subscription [MEDIUM IMPACT]
|
|
101
80
|
|
|
102
81
|
**Status:** Open
|
|
103
82
|
**Objective:** Let a long-lived agy session observe pi events: `turn_start`,
|
|
104
83
|
`turn_end`, `tool_call`, `tool_result`, `compaction`.
|
|
105
84
|
|
|
106
85
|
**Why:** Today the bridge handles only `session_start` and `session_shutdown`.
|
|
107
|
-
|
|
108
|
-
"observer" tooling.
|
|
86
|
+
Event subscription would enable a class of "observer" tooling.
|
|
109
87
|
|
|
110
|
-
**Caveat:** agy is request-response per turn
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
file-watching
|
|
88
|
+
**Caveat:** agy is still request-response per turn, even though the
|
|
89
|
+
stream-json engine keeps one process alive across turns. Before building,
|
|
90
|
+
confirm there is a real consumer that can act on an async event stream;
|
|
91
|
+
otherwise this risks the same "no consumer" failure that sank file-watching
|
|
92
|
+
(see Discarded ideas).
|
|
114
93
|
|
|
115
94
|
**Scope:**
|
|
116
|
-
-
|
|
95
|
+
- Provider-side event tap (no pi patch): relay pi event callbacks into the
|
|
96
|
+
bridge.
|
|
117
97
|
- `src/mcp-server.ts`: `pi_subscribe(event)` returns a stream id; an SSE
|
|
118
98
|
channel pushes events.
|
|
119
99
|
|
|
@@ -124,12 +104,20 @@ file-watching (see Discarded ideas).
|
|
|
124
104
|
- [ ] At least three event types supported at close.
|
|
125
105
|
- [ ] No perf regression on the event hot path.
|
|
126
106
|
|
|
127
|
-
**Effort:** Large.
|
|
107
|
+
**Effort:** Large.
|
|
128
108
|
|
|
129
109
|
**Blocks:** None. **Blocked by:** Confirm a real event-driven consumer exists.
|
|
130
110
|
|
|
131
111
|
---
|
|
132
112
|
|
|
113
|
+
## Closed by 1.3.0 (moved out of the open set)
|
|
114
|
+
|
|
115
|
+
- **Stream progress for long tool calls** (the former top open gap): closed by
|
|
116
|
+
the no-patch round-trip. Bridged tools no longer block inside the MCP
|
|
117
|
+
server; they execute as real pi tools in pi's own loop, so pi's native
|
|
118
|
+
card/spinner UX shows progress while the call runs, and the result content
|
|
119
|
+
is identical to the old blocking path.
|
|
120
|
+
|
|
133
121
|
## Discarded ideas (not worth it)
|
|
134
122
|
|
|
135
123
|
Weighed and rejected; kept here as a graveyard so they are not re-proposed. Full
|
|
@@ -145,10 +133,10 @@ reasoning is in project memory.
|
|
|
145
133
|
mid-session appears next turn. The heartbeat would only help a long-lived
|
|
146
134
|
client that caches the list, and there is none.
|
|
147
135
|
- **Settings, env, and secrets access** — DECLINED. Tools exposed via
|
|
148
|
-
the bridge run in pi's process
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
136
|
+
the bridge run in pi's process and self-authenticate with pi's own
|
|
137
|
+
credentials, so agy already uses pi's creds for every tool; a credential
|
|
138
|
+
never crosses the bridge. A `pi_get_setting` accessor was predicated on
|
|
139
|
+
credential reuse that does not apply.
|
|
152
140
|
- **Image / binary content blocks** — NOT NEEDED. pi shares the
|
|
153
141
|
path to any image it produces (e.g. `/tmp/pi-clipboard-<uuid>.png`), and agy
|
|
154
142
|
reaches and reads those files directly via the bridge's `read` tool, so
|
|
@@ -163,24 +151,19 @@ reasoning is in project memory.
|
|
|
163
151
|
|
|
164
152
|
For each open gap, the default shape:
|
|
165
153
|
|
|
166
|
-
1. Identify the pi-side API
|
|
167
|
-
2.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
the next
|
|
172
|
-
|
|
173
|
-
|
|
154
|
+
1. Identify the pi-side API (must be public; the bridge does not patch pi).
|
|
155
|
+
2. Add a bridge tool wrapper in `src/mcp-server.ts` that parks a call through
|
|
156
|
+
the provider's round-trip store, or answers bridge-side when no pi tool is
|
|
157
|
+
needed (see `src/skills.ts` for that pattern).
|
|
158
|
+
3. Register the tool name with the bridge (it appears in agy's tool catalog on
|
|
159
|
+
the next turn).
|
|
160
|
+
4. Add a test under `tests/mcp-server.test.ts` that round-trips a real call.
|
|
161
|
+
5. Tick the gap's acceptance checkboxes.
|
|
174
162
|
|
|
175
|
-
Most need no change to agy, only the bridge
|
|
176
|
-
the two shipped gaps were closed without any pi dist patch or new MCP tool, by
|
|
177
|
-
working provider/decode-side (`src/provider.ts`, `src/diff-render.ts`); the
|
|
178
|
-
shape above is a default, not a requirement.
|
|
163
|
+
Most need no change to agy, only the bridge or the provider.
|
|
179
164
|
|
|
180
165
|
## Cross-references
|
|
181
166
|
|
|
182
|
-
- `docs/ARCHITECTURE.md` —
|
|
183
|
-
- `docs/PI-INVOKETOOL-PATCH.md` — the local patch to pi that this whole
|
|
184
|
-
feature depends on.
|
|
167
|
+
- `docs/ARCHITECTURE.md` — engine internals, round-trip design, per-pid config layout.
|
|
185
168
|
- `docs/DEVELOPMENT.md` — how to run tests, rebuild, and iterate.
|
|
186
|
-
- `CHANGELOG.md` — shipped work
|
|
169
|
+
- `CHANGELOG.md` — shipped work.
|