pi-agy-acp 0.0.0-stage → 0.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 +22 -0
- package/NOTICE +10 -0
- package/README.md +84 -2
- package/docs/development.md +80 -0
- package/docs/reference.md +157 -0
- package/index.ts +129 -0
- package/package.json +48 -4
- package/src/acp-process.ts +337 -0
- package/src/catalog.ts +265 -0
- package/src/config.ts +50 -0
- package/src/conversation.ts +520 -0
- package/src/format.ts +130 -0
- package/src/history.ts +334 -0
- package/src/host.ts +53 -0
- package/src/jsonrpc.ts +276 -0
- package/src/mcp-bridge.ts +405 -0
- package/src/pi-stream.ts +256 -0
- package/src/preflight.ts +301 -0
- package/src/protocol.ts +65 -0
- package/src/quota.ts +173 -0
- package/src/runtime.ts +1624 -0
- package/src/util.ts +157 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lili-luo
|
|
4
|
+
Copyright (c) 2026 fdkevin0
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
This project adapts dsh-llm-antigravity-acp from:
|
|
2
|
+
https://github.com/lili-luo/dsh-plugin-bundle
|
|
3
|
+
Upstream snapshot: f0499138aa4f39531f258bcbdcebfeecbf17fbbc
|
|
4
|
+
Copyright (c) 2026 lili-luo. MIT license, reproduced in LICENSE.
|
|
5
|
+
|
|
6
|
+
The ACP runtime, JSON-RPC transport, MCP bridge, history projection, model
|
|
7
|
+
catalog, preflight, quota reader, and runtime test fixtures derive
|
|
8
|
+
from that project. Pi entry point, host process integration, local protocol
|
|
9
|
+
contracts and Pi stream translation are adaptations in this repository.
|
|
10
|
+
Internal bridge identifiers are renamed to pi; upstream licensing and attribution are retained.
|
package/README.md
CHANGED
|
@@ -1,3 +1,85 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pi-agy-acp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use Google Antigravity in Pi through the official, locally installed `agy` CLI.
|
|
4
|
+
This extension registers the `antigravity-acp` provider and lets Pi execute the
|
|
5
|
+
model's tool calls. It supports streaming text and reasoning, images, and
|
|
6
|
+
parallel tool calls.
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- Node.js >= 22.18.0.
|
|
11
|
+
- Pi (`@earendil-works/pi-coding-agent`) 1.5.x.
|
|
12
|
+
- The official `agy` CLI >= 1.4.12, signed in with your Google account.
|
|
13
|
+
Run `agy` in your terminal to complete sign-in before using the extension.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
From GitHub (recommended):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pi install git:github.com/fdkevin0/pi-agy-acp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
From npm:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pi install npm:pi-agy-acp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
To install only for the current project, writing to `.pi/settings.json`:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pi install -l git:github.com/fdkevin0/pi-agy-acp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
To try it for one invocation without saving an installation to settings:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pi -e git:github.com/fdkevin0/pi-agy-acp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To install a local clone for development:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
git clone https://github.com/fdkevin0/pi-agy-acp.git
|
|
45
|
+
pi install ./pi-agy-acp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
See [development setup](docs/development.md) for dependencies and local testing.
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
Start `pi`, then use `/model` to select a model under `antigravity-acp`.
|
|
53
|
+
Examples include `gemini-4-argon`, `gemini-3.8-flash`, `claude-opus-5-5`,
|
|
54
|
+
`claude-sonnet-5-5`, and `gpt-oss-120b-medium`. The available list refreshes
|
|
55
|
+
automatically from your account.
|
|
56
|
+
|
|
57
|
+
| Command | Purpose |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `/agy-acp` or `/agy-acp status` | Show runtime state, account details, models, sessions, and the last turn. |
|
|
60
|
+
| `/agy-acp quota` | Show a loading animation in the TUI, then account email, subscription plan, grouped 5h/weekly quota bars, and reset countdowns when available. |
|
|
61
|
+
| `/agy-acp reset` | Close ACP sessions; the next request rebuilds the connection. |
|
|
62
|
+
|
|
63
|
+
Update installed extensions:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
pi update --extensions
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Remove a GitHub installation:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
pi remove git:github.com/fdkevin0/pi-agy-acp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For an npm installation, use `pi remove npm:pi-agy-acp`. Add `-l` when removing
|
|
76
|
+
a project-local installation.
|
|
77
|
+
|
|
78
|
+
Default prices are zero, not a promise of free calls. Pi pricing overrides are
|
|
79
|
+
used when configured.
|
|
80
|
+
|
|
81
|
+
## More information
|
|
82
|
+
|
|
83
|
+
- [Reference](docs/reference.md): commands, configuration, stored data, model discovery, and limitations.
|
|
84
|
+
- [Development](docs/development.md): setup, request flow, source layout, and verification.
|
|
85
|
+
- [Attribution](NOTICE) and [MIT license](LICENSE).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
Start with the [installation guide](../README.md#install) to use the extension.
|
|
4
|
+
For settings and user-visible limits, see the [reference](reference.md).
|
|
5
|
+
|
|
6
|
+
For development, run these commands from your clone:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install
|
|
10
|
+
pi -e ./index.ts
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Request flow
|
|
14
|
+
|
|
15
|
+
1. The extension registers `antigravity-acp` with Pi. The first request starts
|
|
16
|
+
`agy acp --process-per-session` and a loopback MCP bridge.
|
|
17
|
+
2. Pi messages and tool definitions are converted into an ACP prompt. The runtime
|
|
18
|
+
reuses a session when its history prefix still matches; otherwise it replays
|
|
19
|
+
the available history into a new session.
|
|
20
|
+
3. Model tool calls reach the bridge and remain pending while Pi executes them.
|
|
21
|
+
Pi receives a `toolUse` result, then supplies tool results on its next request.
|
|
22
|
+
4. Those results resolve the pending MCP requests, allowing the same ACP turn to
|
|
23
|
+
continue. Long-running tools use a relay to keep the agent waiting.
|
|
24
|
+
5. The adapter drains the runtime's generator before publishing completion, so
|
|
25
|
+
session cleanup finishes before Pi can start its next step.
|
|
26
|
+
|
|
27
|
+
Provider registration and cache-only refresh do not start processes, sockets, or
|
|
28
|
+
timers. Successful session replacement is cleaned up through `session_shutdown`;
|
|
29
|
+
pre-switch and pre-fork interception hooks do not reset the runtime.
|
|
30
|
+
|
|
31
|
+
The bridge binds to `127.0.0.1`, uses per-session bearer credentials, and checks
|
|
32
|
+
structured tool identity before granting permissions. Session changes and
|
|
33
|
+
compaction trigger cleanup and rebuilding; shutdown closes processes and the bridge.
|
|
34
|
+
|
|
35
|
+
## Source layout
|
|
36
|
+
|
|
37
|
+
| File or group | Responsibility |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `index.ts` | Provider registration, commands, and Pi lifecycle hooks. |
|
|
40
|
+
| `src/pi-stream.ts`, `src/protocol.ts` | Pi message conversion and bridge event contracts. |
|
|
41
|
+
| `src/runtime.ts`, `src/conversation.ts`, `src/history.ts` | Sessions, pending tool calls, streaming, and history replay. |
|
|
42
|
+
| `src/acp-process.ts`, `src/jsonrpc.ts`, `src/mcp-bridge.ts` | ACP transport and local MCP server. |
|
|
43
|
+
| `src/host.ts`, `src/preflight.ts`, `src/config.ts` | Process execution, executable discovery, and isolated home setup. |
|
|
44
|
+
| `src/catalog.ts`, `src/quota.ts`, `src/format.ts`, `src/util.ts` | Model catalog, quota queries, TUI notice formatting, and shared utilities. |
|
|
45
|
+
| `tests/` | Scripted agy fixture, runtime tests, and Pi integration tests. |
|
|
46
|
+
|
|
47
|
+
Upstream provenance and licensing are recorded in [NOTICE](../NOTICE) and
|
|
48
|
+
[LICENSE](../LICENSE).
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm run check
|
|
54
|
+
npm test
|
|
55
|
+
pi --no-extensions -e ./index.ts --list-models antigravity-acp
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Tests run directly with Node's native TypeScript support; `tsx` is not required.
|
|
59
|
+
Automated tests use a scripted local `agy` substitute so `npm test` runs offline
|
|
60
|
+
without consuming account quota. They need permission to listen on `127.0.0.1`.
|
|
61
|
+
|
|
62
|
+
Coverage includes tool suspension and resumption, parallel calls, permission
|
|
63
|
+
checks, cancellation, history rewrites, images, quota errors, model discovery,
|
|
64
|
+
account metadata caching, bounded login-log reads, and Pi stream completion.
|
|
65
|
+
Listing models verifies extension loading, not access to the real service.
|
|
66
|
+
|
|
67
|
+
To inspect the package contents without publishing:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npm pack --dry-run
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Documentation conventions
|
|
74
|
+
|
|
75
|
+
Keep all project documentation in English. Use progressive disclosure:
|
|
76
|
+
|
|
77
|
+
- Keep the README focused on the first successful run and essential limitations.
|
|
78
|
+
- Put operational details in the reference and implementation details in this guide.
|
|
79
|
+
- Link to the relevant section instead of duplicating detailed explanations.
|
|
80
|
+
- Include linked documentation in the package's `files` list.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Reference
|
|
2
|
+
|
|
3
|
+
For installation and your first request, start with the [installation guide](../README.md#install).
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Behavior |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `/agy-acp` or `/agy-acp status` | Show a status panel with runtime state, paths, sessions, model reasoning levels, and the last turn. |
|
|
10
|
+
| `/agy-acp quota` | Show account details, grouped quota bars, and reset countdowns. |
|
|
11
|
+
| `/agy-acp reset` | Close ACP sessions; the next request rebuilds a session from Pi's history. |
|
|
12
|
+
|
|
13
|
+
Subcommands support completion with Tab. Unknown arguments display
|
|
14
|
+
`Usage: /agy-acp [status|quota|reset]` as a warning.
|
|
15
|
+
|
|
16
|
+
### Status panel
|
|
17
|
+
|
|
18
|
+
The panel marks the runtime as idle, starting, ready, or in error. Before the first
|
|
19
|
+
turn, it shows the isolated home and notes that agy has not been probed yet;
|
|
20
|
+
viewing status does not start it. Models list their supported reasoning levels,
|
|
21
|
+
including a fixed level where applicable.
|
|
22
|
+
|
|
23
|
+
Once a turn finishes, its summary shows the model, effort, outcome (`completed`,
|
|
24
|
+
`aborted`, or `error`), duration, and retry notice count when nonzero. Duration
|
|
25
|
+
covers the ACP turn, including time waiting for Pi tools, but excludes startup.
|
|
26
|
+
A parked tool call is still part of an active turn, not a completed turn.
|
|
27
|
+
Runtime errors use an error notification; a failed last turn with an otherwise
|
|
28
|
+
healthy runtime uses a warning.
|
|
29
|
+
|
|
30
|
+
### Quota panel
|
|
31
|
+
|
|
32
|
+
In interactive TUI mode, a bordered loader displays `Fetching Antigravity quota...`
|
|
33
|
+
while the request is pending. Press Escape to cancel waiting and return to the
|
|
34
|
+
editor. The underlying quota query may finish and update the cache, but its result
|
|
35
|
+
will not appear after cancellation. Non-TUI modes query directly without a loader.
|
|
36
|
+
|
|
37
|
+
Quota is read through `agy -p /usage --output-format json`. Each model group has
|
|
38
|
+
one row per quota window, with a 12-cell bar showing the remaining fraction,
|
|
39
|
+
a rounded percentage, and a relative reset time. For example:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
Antigravity Quota
|
|
43
|
+
Account: user@example.com · Google AI Ultra
|
|
44
|
+
|
|
45
|
+
Gemini Models
|
|
46
|
+
Gemini Flash, Gemini Pro
|
|
47
|
+
5h [████████████] 100% · resets in 4h 59m
|
|
48
|
+
weekly [███████████░] 91% · resets in 6d 7h
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Missing values display `n/a`; an elapsed reset time displays `resetting soon`.
|
|
52
|
+
Severity uses the actual remaining fraction rather than the rounded percentage:
|
|
53
|
+
|
|
54
|
+
| Condition | Notification |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| All known windows above 20% | Info |
|
|
57
|
+
| Any window at or below 20%, with none at or below 5% | Warning |
|
|
58
|
+
| Any window at or below 5%, or a failed quota query | Error |
|
|
59
|
+
|
|
60
|
+
Errors include the reason. If cached groups are available after a failed query,
|
|
61
|
+
the title marks them as `(stale)` and still displays their bars. An empty successful
|
|
62
|
+
response displays `No quota data available.`.
|
|
63
|
+
|
|
64
|
+
### Account details
|
|
65
|
+
|
|
66
|
+
Both panels show the email and subscription plan when known. The plan comes from
|
|
67
|
+
ACP session metadata and is saved in `catalog.json`. If no plan is cached, the
|
|
68
|
+
first quota check also tries a tool-less ACP discovery session in parallel with
|
|
69
|
+
the quota query. This starts ACP but sends no model prompt. Discovery is attempted
|
|
70
|
+
once per runtime; failure still allows the quota result to appear. Use
|
|
71
|
+
`/agy-acp reset` to allow another attempt. Viewing status never starts discovery.
|
|
72
|
+
|
|
73
|
+
The email is read from the latest login entry in the last 64 KiB of the isolated
|
|
74
|
+
home's `acp.log`; it is not saved in the model cache. With the default home only,
|
|
75
|
+
the reader also checks `~/.gemini/antigravity-cli/cli.log` if needed. A custom
|
|
76
|
+
`PI_AGY_HOME` never falls back to that global log. Either field appears on its own
|
|
77
|
+
when the other is unavailable; the account line is omitted when neither is known.
|
|
78
|
+
These details are best-effort: cached plans and login logs can be stale after an
|
|
79
|
+
account change.
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
Set these environment variables before starting Pi:
|
|
84
|
+
|
|
85
|
+
| Variable | Purpose | Default |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| `PI_AGY_COMMAND` | Absolute path to the `agy` executable. | Automatic discovery. |
|
|
88
|
+
| `PI_AGY_HOME` | Dedicated directory for this extension's agy state. | `~/.pi/agent/cache/antigravity-acp` |
|
|
89
|
+
|
|
90
|
+
For example:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
PI_AGY_COMMAND=/absolute/path/to/agy pi -e ./index.ts
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Stored data and authentication
|
|
97
|
+
|
|
98
|
+
The dedicated directory isolates the bridge agent from your normal agy tools and
|
|
99
|
+
plugins. It contains agy-managed session data, logs, and the extension's model cache.
|
|
100
|
+
|
|
101
|
+
With file-backed authentication, the extension copies the existing OAuth token
|
|
102
|
+
from your normal agy directory and sets its permissions to `0600`. Do not commit
|
|
103
|
+
or share this directory. Authentication and token refresh remain agy's responsibility.
|
|
104
|
+
|
|
105
|
+
## Models and context
|
|
106
|
+
|
|
107
|
+
Loading the extension reads the cached model catalog, or falls back to five model
|
|
108
|
+
families, without starting agy. Pi's model refresh queries ACP for the account's
|
|
109
|
+
catalog. The first request also discovers models and validates the selection.
|
|
110
|
+
Cache-only refreshes and refreshes already cancelled before startup do not launch
|
|
111
|
+
ACP. Server-advertised models are not hidden, and live catalog changes update
|
|
112
|
+
Pi's model selector. The selector exposes only the ACP reasoning levels offered
|
|
113
|
+
for each model. Direct requests map `minimal` to `low` and `xhigh` or `max` to
|
|
114
|
+
`high`; `off` leaves the ACP effort unspecified, using the runtime default.
|
|
115
|
+
|
|
116
|
+
The fallback families are:
|
|
117
|
+
|
|
118
|
+
- `gemini-4-argon`
|
|
119
|
+
- `gemini-3.8-flash`
|
|
120
|
+
- `claude-opus-5-5`
|
|
121
|
+
- `claude-sonnet-5-5`
|
|
122
|
+
- `gpt-oss-120b-medium`
|
|
123
|
+
|
|
124
|
+
These entries are defaults, not a guarantee of account access. Context declarations
|
|
125
|
+
are 256,000 tokens, or 131,072 for GPT-OSS. The history replay budget is 160,000 bytes;
|
|
126
|
+
older history can be omitted to fit, and historical images become text placeholders.
|
|
127
|
+
|
|
128
|
+
## Usage and costs
|
|
129
|
+
|
|
130
|
+
Usage comes only from the ACP `session/prompt` result. Parked tool steps have no
|
|
131
|
+
separate usage report; statistics arrive when the full ACP turn finishes.
|
|
132
|
+
For turns spanning multiple model steps, input token buckets use the upstream
|
|
133
|
+
implementation's averaging method. They are not an exact per-step measurement.
|
|
134
|
+
|
|
135
|
+
Default model prices are zero because pricing is unavailable. If you configure
|
|
136
|
+
Pi model pricing overrides, reported usage is priced using those rates. These
|
|
137
|
+
estimates are not an invoice amount or a promise of free access.
|
|
138
|
+
|
|
139
|
+
The extension does not inspect agy's private databases or invoke or distribute
|
|
140
|
+
binary patch scripts.
|
|
141
|
+
|
|
142
|
+
## Compatibility limits
|
|
143
|
+
|
|
144
|
+
This version targets the `@earendil-works/*` Pi packages at version 1.5.x.
|
|
145
|
+
Host peer dependencies use `*` as required by Pi package conventions; validation
|
|
146
|
+
has been performed against version 1.5.0. Compatibility with older
|
|
147
|
+
`@mariozechner/*` interfaces is not claimed.
|
|
148
|
+
|
|
149
|
+
The bridge supports `onPayload` request replacement and `onProviderStreamEvent`
|
|
150
|
+
observation before conversion to Pi events. At the first ACP stream event, it
|
|
151
|
+
invokes `onResponse` with synthetic status `200` and empty headers before
|
|
152
|
+
normalizing that event. This is a Pi instrumentation notification, not an HTTP
|
|
153
|
+
response from agy. Startup errors before the first event do not emit it.
|
|
154
|
+
|
|
155
|
+
Sampling parameters, output limits, forced `toolChoice`, and provider-scoped
|
|
156
|
+
environment overrides are not mapped to ACP. See
|
|
157
|
+
[development checks](development.md#verification) for the scope of automated validation.
|
package/index.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BorderedLoader,
|
|
3
|
+
type ExtensionAPI,
|
|
4
|
+
type ProviderModelConfig,
|
|
5
|
+
} from '@earendil-works/pi-coding-agent'
|
|
6
|
+
import { AntigravityRuntime } from './src/runtime.ts'
|
|
7
|
+
import { defaults } from './src/config.ts'
|
|
8
|
+
import { spawnAcp, runCommand } from './src/host.ts'
|
|
9
|
+
import { streamPi } from './src/pi-stream.ts'
|
|
10
|
+
import { formatQuota, formatStatus } from './src/format.ts'
|
|
11
|
+
import type { QuotaSnapshot } from './src/quota.ts'
|
|
12
|
+
|
|
13
|
+
export default function (pi: ExtensionAPI) {
|
|
14
|
+
const config = {
|
|
15
|
+
...defaults,
|
|
16
|
+
command: process.env.PI_AGY_COMMAND || '',
|
|
17
|
+
home: process.env.PI_AGY_HOME || '',
|
|
18
|
+
}
|
|
19
|
+
const createRuntime = () =>
|
|
20
|
+
new AntigravityRuntime({
|
|
21
|
+
config,
|
|
22
|
+
spawnAcp,
|
|
23
|
+
runCommand,
|
|
24
|
+
log: { info: () => {}, warn: (message) => console.error(message) },
|
|
25
|
+
onModelsChanged: () => register(),
|
|
26
|
+
})
|
|
27
|
+
let runtime = createRuntime()
|
|
28
|
+
const models = (): ProviderModelConfig[] =>
|
|
29
|
+
runtime.catalog.list().map((m) => {
|
|
30
|
+
const efforts = runtime.catalog.effortsFor(m.id)
|
|
31
|
+
return {
|
|
32
|
+
id: m.id,
|
|
33
|
+
name: m.name,
|
|
34
|
+
input: ['text', 'image'],
|
|
35
|
+
reasoning: efforts.length > 0,
|
|
36
|
+
thinkingLevelMap:
|
|
37
|
+
efforts.length > 0
|
|
38
|
+
? {
|
|
39
|
+
off: null,
|
|
40
|
+
minimal: null,
|
|
41
|
+
low: efforts.includes('low') ? 'low' : null,
|
|
42
|
+
medium: efforts.includes('medium') ? 'medium' : null,
|
|
43
|
+
high: efforts.includes('high') ? 'high' : null,
|
|
44
|
+
xhigh: null,
|
|
45
|
+
max: null,
|
|
46
|
+
}
|
|
47
|
+
: undefined,
|
|
48
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
49
|
+
contextWindow: runtime.contextWindowFor(m.id),
|
|
50
|
+
maxTokens: 65536,
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
const register = () =>
|
|
54
|
+
pi.registerProvider(config.provider, {
|
|
55
|
+
name: config.displayName,
|
|
56
|
+
api: 'antigravity-acp',
|
|
57
|
+
baseUrl: 'acp://local',
|
|
58
|
+
apiKey: 'local-agy',
|
|
59
|
+
models: models(),
|
|
60
|
+
streamSimple: (model, context, options) =>
|
|
61
|
+
streamPi(runtime, model, context, options),
|
|
62
|
+
refreshModels: async (context) => {
|
|
63
|
+
if (context?.allowNetwork !== false && !context?.signal?.aborted) {
|
|
64
|
+
await runtime.warmup()
|
|
65
|
+
}
|
|
66
|
+
return models()
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
register()
|
|
70
|
+
const reset = async () => {
|
|
71
|
+
await runtime.dispose()
|
|
72
|
+
runtime = createRuntime()
|
|
73
|
+
}
|
|
74
|
+
pi.on('session_tree', reset)
|
|
75
|
+
pi.on('session_compact', reset)
|
|
76
|
+
pi.on('session_shutdown', async () => {
|
|
77
|
+
await runtime.dispose()
|
|
78
|
+
})
|
|
79
|
+
pi.registerCommand('agy-acp', {
|
|
80
|
+
description: 'Antigravity ACP status, quota, or reset',
|
|
81
|
+
getArgumentCompletions: (prefix) => {
|
|
82
|
+
const items = ['status', 'quota', 'reset']
|
|
83
|
+
.filter((command) => command.startsWith(prefix.trim()))
|
|
84
|
+
.map((value) => ({ value, label: value }))
|
|
85
|
+
return items.length > 0 ? items : null
|
|
86
|
+
},
|
|
87
|
+
handler: async (args, ctx) => {
|
|
88
|
+
const command = args.trim()
|
|
89
|
+
if (command === 'reset') {
|
|
90
|
+
await reset()
|
|
91
|
+
ctx.ui.notify('Antigravity ACP sessions reset', 'info')
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
if (command !== '' && command !== 'status' && command !== 'quota') {
|
|
95
|
+
ctx.ui.notify('Usage: /agy-acp [status|quota|reset]', 'warning')
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
let snapshot: QuotaSnapshot | null = null
|
|
99
|
+
if (command === 'quota') {
|
|
100
|
+
snapshot =
|
|
101
|
+
ctx.mode === 'tui' && typeof ctx.ui.custom === 'function'
|
|
102
|
+
? await ctx.ui.custom<QuotaSnapshot | null>(
|
|
103
|
+
(tui, theme, _kb, done) => {
|
|
104
|
+
const loader = new BorderedLoader(
|
|
105
|
+
tui,
|
|
106
|
+
theme,
|
|
107
|
+
'Fetching Antigravity quota...',
|
|
108
|
+
)
|
|
109
|
+
loader.onAbort = () => done(null)
|
|
110
|
+
// QuotaReader returns error snapshots, so failures also close the loader.
|
|
111
|
+
void runtime.readQuota(true).then((result) => {
|
|
112
|
+
if (!loader.signal.aborted) done(result)
|
|
113
|
+
})
|
|
114
|
+
return loader
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
: await runtime.readQuota(true)
|
|
118
|
+
if (snapshot === null) {
|
|
119
|
+
ctx.ui.notify('Quota check cancelled', 'info')
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const notice = snapshot
|
|
124
|
+
? formatQuota(snapshot)
|
|
125
|
+
: formatStatus(runtime.status())
|
|
126
|
+
ctx.ui.notify(notice.text, notice.level)
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agy-acp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Google Antigravity ACP provider extension for Pi Coding Agent",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/fdkevin0/pi-agy-acp.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/fdkevin0/pi-agy-acp#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/fdkevin0/pi-agy-acp/issues"
|
|
14
|
+
},
|
|
15
|
+
"pi": {
|
|
16
|
+
"extensions": [
|
|
17
|
+
"./index.ts"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"index.ts",
|
|
22
|
+
"src",
|
|
23
|
+
"README.md",
|
|
24
|
+
"docs",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"NOTICE"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22.18.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@earendil-works/pi-ai": "*",
|
|
33
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "node --test tests/*.test.mjs",
|
|
37
|
+
"check": "tsc --noEmit"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"typescript": "^5.9.0",
|
|
41
|
+
"@types/node": "^22.0.0"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"pi-package",
|
|
45
|
+
"pi-coding-agent",
|
|
46
|
+
"antigravity",
|
|
47
|
+
"agy",
|
|
48
|
+
"acp"
|
|
49
|
+
]
|
|
50
|
+
}
|