paseo-acp-agy 1.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arthur Melo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/PROTOCOL.md ADDED
@@ -0,0 +1,149 @@
1
+ # Protocol Specification & Mapping: Antigravity stream-json ↔ ACP
2
+
3
+ `agy-acp` exposes the official Google Antigravity CLI (`agy`) to Paseo through ACP while keeping authentication and model execution inside the official CLI.
4
+
5
+ ## Antigravity process
6
+
7
+ Each Paseo ACP session owns one persistent `agy` process:
8
+
9
+ ```bash
10
+ agy --input-format stream-json --output-format stream-json --print=""
11
+ ```
12
+
13
+ Optional session flags are applied when the process starts or is restarted:
14
+
15
+ - `--model <model-id>`
16
+ - `--effort <low|medium|high>` when supported by the selected model
17
+ - `--mode <mode-id>`
18
+ - `--conversation <conversation-id>` when resuming
19
+ - `--sandbox`
20
+ - `--dangerously-skip-permissions` only when explicitly configured
21
+
22
+ Configuration changes schedule a controlled restart before the next prompt. On POSIX systems `agy` is launched as a process-group leader; shutdown, restart and turn cancellation signal the process group so tool subprocesses are not left orphaned.
23
+
24
+ ## Antigravity stream-json
25
+
26
+ ### Input
27
+
28
+ One NDJSON object per user turn:
29
+
30
+ ```json
31
+ {"event":"user","message":{"content":"User prompt"}}
32
+ ```
33
+
34
+ ### Output
35
+
36
+ `agy` emits NDJSON events:
37
+
38
+ - `init` — process/session metadata and `conversation_id`
39
+ - `step_update` — streaming assistant text, thoughts, tool calls and usage
40
+ - `result` — terminal result for a prompt turn
41
+
42
+ One open stdin/stdout stream is reused for multiple turns.
43
+
44
+ ## ACP wire methods
45
+
46
+ The ACP wire protocol uses snake_case method names. `agy-acp` accepts these methods:
47
+
48
+ | ACP method | agy-acp behavior |
49
+ |---|---|
50
+ | `initialize` | Advertise provider/session capabilities |
51
+ | `session/new` | Create a new isolated session |
52
+ | `session/resume` | Restore and validate a persisted ACP session without history replay |
53
+ | `session/prompt` | Send a prompt to the persistent `agy` process |
54
+ | `session/cancel` | Cancel the reserved/running turn; signal the `agy` process group when running |
55
+ | `session/close` | Persist state and terminate the process tree |
56
+ | `session/set_mode` | Change mode; restart before the next turn if needed |
57
+ | `session/set_model` | Change base model; restart before the next turn if needed |
58
+ | `session/set_config_option` | Change `thought_level` / reasoning effort |
59
+ | `session/update` | Stream messages, thoughts, tool calls, usage and commands to Paseo |
60
+ | `provider/usage` | Return current Antigravity quota and credit state |
61
+
62
+ For backwards compatibility, the server also accepts the exact pre-hardening aliases:
63
+
64
+ - `setSessionMode`
65
+ - `unstable_setSessionModel`
66
+ - `setSessionConfigOption`
67
+
68
+ ### `session/load`
69
+
70
+ `agy-acp` currently advertises `loadSession: false`. ACP `session/load` requires the agent to replay prior conversation history through `session/update` notifications. The adapter intentionally does not claim that capability until replay is implemented. Paseo persistence uses `session/resume`, which restores model context without replaying already-rendered history.
71
+
72
+ ## Turn concurrency and cancellation
73
+
74
+ A session-level prompt operation is reserved synchronously before any slash-command or process startup/restart `await`. Therefore:
75
+
76
+ - a second `session/prompt` cannot enter while `/resume`, `/usage`, or another asynchronous slash command is running;
77
+ - a second prompt cannot enter during first-turn startup;
78
+ - cancellation received during startup prevents the user prompt from ever being written to `agy` stdin;
79
+ - stale child events cannot resolve or reject a newer turn;
80
+ - each active process turn tracks the exact child process that owns it;
81
+ - the session prompt reservation is always released in `finally`, for both slash-command and ordinary prompt paths.
82
+
83
+ ## Models and thinking effort
84
+
85
+ `agy-acp` discovers models through `agy models`. Model variants ending in `-high`, `-medium` or `-low` are exposed as a base model plus a separate ACP `thought_level` config option. Discovery is cached for one minute per `agy` binary path, with a fallback list if discovery fails.
86
+
87
+ ## Session persistence and resume validation
88
+
89
+ ACP session metadata is stored outside the repository under:
90
+
91
+ ```text
92
+ ${XDG_STATE_HOME:-~/.local/state}/agy-acp/sessions/
93
+ ```
94
+
95
+ Each session is stored in its own `0600` JSON file inside a `0700` directory. Persisted state contains only:
96
+
97
+ - ACP `sessionId`
98
+ - Antigravity `conversation_id`
99
+ - cwd
100
+ - model
101
+ - effort
102
+ - mode
103
+ - accumulated token/cost/context usage
104
+ - update timestamp
105
+
106
+ No Google credentials or OAuth tokens are read or persisted by the adapter.
107
+
108
+ When Paseo requests `session/resume`, the adapter starts `agy --conversation <id>`, waits for its `init` event, and verifies that Antigravity actually opened the requested conversation before returning success.
109
+
110
+ ## Token usage, context window, cost and quota
111
+
112
+ - Cumulative `inputTokens`, `outputTokens`, `cachedInputTokens` and `totalTokens` are persisted per ACP session.
113
+ - Usage from a completed Antigravity `result` is recorded even when the turn ends with `status: ERROR`, because model/tool work may already have consumed billable tokens.
114
+ - The model used for cost calculation is snapshotted at the beginning of the prompt operation. A `session/set_model` received mid-turn applies to the next Antigravity process, without repricing the current turn.
115
+ - Raw session cost is accumulated without per-turn rounding. Rounding occurs only in UI-facing ACP payloads, preserving micro-costs across many small turns.
116
+ - Context-window limits are attached to model definitions and streaming usage updates.
117
+ - `fetchAntigravityUsage()` treats `/usage` as the primary availability probe. A failed, timed-out or missing `agy` command returns `status: unavailable` with an error instead of a false zero-usage `available` result.
118
+ - `/credits` failure is treated as partial data loss when `/usage` succeeds: quota remains available, balances are omitted and the error explains the missing credit data.
119
+
120
+ ## Child-process lifecycle
121
+
122
+ - One ACP session = one `agy` process tree.
123
+ - On POSIX, the child is a process-group leader and signals target the whole group.
124
+ - A child being replaced is terminated and awaited before a replacement is spawned.
125
+ - `SIGTERM` is used first; `SIGKILL` follows a bounded timeout.
126
+ - Child event handlers are identity-checked so an old process cannot alter a newer process.
127
+
128
+ ## Attachments
129
+
130
+ Inline base64 images are written under the adapter state directory with `0600` permissions and a content-addressed file name. The adapter:
131
+
132
+ - accepts only known image MIME types;
133
+ - validates base64 by decode/re-encode equivalence;
134
+ - enforces a default 20 MiB decoded-size limit (`AGY_ACP_MAX_ATTACHMENT_BYTES` can override it);
135
+ - converts valid `file://` URIs with Node's URL parser.
136
+
137
+ ## Slash commands
138
+
139
+ The adapter intercepts selected local commands such as `/resume`, `/usage`, `/credits`, `/skills`, `/agents`, `/changelog` and `/help`.
140
+
141
+ - Resume identifiers are validated before filesystem lookup.
142
+ - Paseo session IDs resolve through the persisted session store rather than by scraping logs.
143
+ - `/resume` stats all conversation candidates first and reads transcript contents only for the newest requested entries.
144
+ - `/resume <id>` validates the Antigravity conversation before reporting success.
145
+ - Subprocess-based slash commands use bounded timeouts and output buffers.
146
+
147
+ ## CI
148
+
149
+ `.github/workflows/agy-acp.yml` runs `npm ci`, `npm audit --omit=dev --audit-level=high`, `npm run typecheck` and `npm test` for changes under `tools/agy-acp`.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # paseo-acp-agy
2
+
3
+ > **Agent Client Protocol (ACP)** provider adapter connecting **Google Antigravity (`agy`)** to **[Paseo](https://paseo.sh)**, **Zed**, and any ACP-compliant agent client over stdio.
4
+
5
+ [![CI](https://github.com/tucomel/paseo-acp-agy/actions/workflows/ci.yml/badge.svg)](https://github.com/tucomel/paseo-acp-agy/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ `paseo-acp-agy` allows you to use Google Antigravity as a first-class agent provider inside Paseo. It implements the JSON-RPC [Agent Client Protocol](https://agentclientprotocol.com) over standard input/output (`stdio`), dynamically exposing supported models, tracking session token usage, calculating real-time cost, displaying context window usage, and supporting slash commands.
13
+
14
+ ### Features
15
+ - **Zero-Downtime Daemon Compatibility**: Conforms to the [Paseo Server & CLI specification](https://paseo.sh/docs#server--cli). Updates to this adapter apply to future agent launches without restarting the Paseo daemon.
16
+ - **Dynamic Model Catalog**: Exposes Google Gemini (Flash, Pro) and Anthropic Claude models configured in your Antigravity CLI environment.
17
+ - **Usage & Quota Telemetry**: Real-time context window meters, prompt/output token tracking, pricing windows, and quota limit notifications.
18
+ - **Session Management**: Native support for session modes (Default / Plan mode), session cancellation, and resume.
19
+ - **Slash Commands**: In-session support for `/help`, `/usage`, and `/resume`.
20
+
21
+ ---
22
+
23
+ ## Quick Start in Paseo
24
+
25
+ ### 1. Configure Provider in Paseo
26
+
27
+ Add `antigravity` under `agents.providers` in your `~/.paseo/config.json`:
28
+
29
+ ```json
30
+ {
31
+ "agents": {
32
+ "providers": {
33
+ "antigravity": {
34
+ "extends": "acp",
35
+ "label": "Antigravity",
36
+ "command": ["npx", "-y", "paseo-acp-agy", "--acp"],
37
+ "enabled": true
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ > **Local / Development Setup:**
45
+ > If you cloned this repository locally, you can compile and point directly to the binary:
46
+ > ```json
47
+ > "command": ["node", "/path/to/paseo-acp-agy/dist/index.js"]
48
+ > ```
49
+ > Or install globally:
50
+ > ```bash
51
+ > npm install -g paseo-acp-agy
52
+ > ```
53
+ > And configure `"command": ["paseo-acp-agy"]`.
54
+
55
+ ### 2. Reload Paseo Configuration
56
+
57
+ Apply changes immediately without restarting the daemon:
58
+
59
+ ```bash
60
+ paseo reload
61
+ ```
62
+
63
+ ### 3. Verify with Diagnostics
64
+
65
+ Run the official Paseo provider diagnostic command:
66
+
67
+ ```bash
68
+ paseo provider diagnostic antigravity
69
+ ```
70
+
71
+ List detected models:
72
+
73
+ ```bash
74
+ paseo provider models antigravity
75
+ ```
76
+
77
+ ### 4. Run an Agent
78
+
79
+ Launch a task directly from your terminal:
80
+
81
+ ```bash
82
+ paseo run --provider antigravity "Analyze the repository architecture"
83
+ ```
84
+
85
+ Or select **Antigravity** from the provider dropdown in the Paseo Desktop App or Web UI (`https://app.paseo.sh`).
86
+
87
+ ### 5. Official Paseo Catalog Entry
88
+
89
+ To include `paseo-acp-agy` in Paseo's built-in provider store (`ACP_PROVIDER_CATALOG`), see the [Paseo Catalog Specification](docs/paseo-catalog-entry.md).
90
+
91
+ ---
92
+
93
+ ## Requirements
94
+
95
+ - **Node.js**: >= 20.0.0 (Node.js 22 recommended)
96
+ - **Google Antigravity CLI (`agy`)**: Installed and authenticated in your `PATH` (or specified via `AGY_BIN_PATH`).
97
+ - **Paseo**: [Paseo CLI / Daemon](https://paseo.sh/docs#server--cli) (`@getpaseo/cli`) >= 0.7.0.
98
+
99
+ ---
100
+
101
+ ## Environment Variables
102
+
103
+ | Variable | Description | Default |
104
+ | :--- | :--- | :--- |
105
+ | `AGY_BIN_PATH` | Path to the Google Antigravity binary | Auto-detected from `PATH` or `~/.local/bin/agy` |
106
+ | `AGY_ACP_LOG_FILE` | Enable debug file logging | Disabled |
107
+
108
+ ---
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ # Clone repository
114
+ git clone https://github.com/tucomel/paseo-acp-agy.git
115
+ cd paseo-acp-agy
116
+
117
+ # Install dependencies
118
+ npm install
119
+
120
+ # Typecheck
121
+ npm run typecheck
122
+
123
+ # Run test suite (56+ unit & protocol tests)
124
+ npm test
125
+
126
+ # Build distribution
127
+ npm run build
128
+
129
+ # Test ACP initialization via stdio
130
+ printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{}}}\n' | node dist/index.js
131
+ ```
132
+
133
+ ---
134
+
135
+ ## License
136
+
137
+ MIT © [Arthur Melo](https://github.com/tucomel)
@@ -0,0 +1,28 @@
1
+ import { Readable, Writable } from "node:stream";
2
+ import { SessionManager } from "./session.js";
3
+ export declare class ACPServer {
4
+ private sessionManager;
5
+ private input;
6
+ private output;
7
+ private binaryPath;
8
+ private rl;
9
+ private isRunning;
10
+ constructor(options?: {
11
+ input?: Readable;
12
+ output?: Writable;
13
+ sessionManager?: SessionManager;
14
+ binaryPath?: string;
15
+ });
16
+ start(): void;
17
+ private send;
18
+ private sendNotification;
19
+ private sendSuccess;
20
+ private sendError;
21
+ private publishCommands;
22
+ private sessionState;
23
+ private requireSession;
24
+ private validateModel;
25
+ private turnUsagePayload;
26
+ private handleLine;
27
+ stop(): Promise<void>;
28
+ }