opencode-agy-bridge 0.2.2 → 0.2.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/README.md +31 -97
- package/dist/plugin.js +4 -3
- package/dist/provider.d.ts +5 -2
- package/dist/provider.js +36 -11
- package/package.json +16 -5
package/README.md
CHANGED
|
@@ -23,133 +23,81 @@ opencode TUI
|
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
26
|
-
###
|
|
26
|
+
### Automatic (hands-free)
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Add the package with its version to `~/.config/opencode/opencode.json`. OpenCode will download and resolve it from npm automatically — no terminal commands needed.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
### 2. Manual Global Installation
|
|
33
|
-
|
|
34
|
-
If you prefer to install it globally yourself using a package manager:
|
|
30
|
+
### Manual global install
|
|
35
31
|
|
|
36
32
|
```bash
|
|
37
|
-
# Using npm
|
|
38
33
|
npm install -g opencode-agy-bridge
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
bun install -g opencode-agy-bridge
|
|
42
|
-
|
|
43
|
-
# Using pnpm
|
|
44
|
-
pnpm add -g opencode-agy-bridge
|
|
34
|
+
# or: bun install -g opencode-agy-bridge
|
|
35
|
+
# or: pnpm add -g opencode-agy-bridge
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
###
|
|
48
|
-
|
|
49
|
-
If you prefer to build from source:
|
|
38
|
+
### Build from source
|
|
50
39
|
|
|
51
40
|
```bash
|
|
52
41
|
git clone https://github.com/raultov/opencode-agy-bridge.git
|
|
53
42
|
cd opencode-agy-bridge
|
|
54
|
-
|
|
55
|
-
# Using Bun (recommended)
|
|
56
|
-
bun install
|
|
57
|
-
bun run build
|
|
58
|
-
bun test # verify all tests pass
|
|
59
|
-
|
|
60
|
-
# Or using pnpm/npm
|
|
61
|
-
pnpm install && pnpm run build && pnpm test
|
|
43
|
+
bun install && bun run build && bun test
|
|
62
44
|
```
|
|
63
45
|
|
|
64
|
-
## Features
|
|
65
|
-
|
|
66
|
-
- **Robust Delta Extraction:** Automatically normalizes `\r\n` (CRLF) and `\n` (LF) line endings, tolerates trailing whitespace/newline differences, and implements suffix-based alignment to support seamless recovery during context window truncation.
|
|
67
|
-
|
|
68
46
|
## Configuration
|
|
69
47
|
|
|
70
|
-
Add the plugin and provider to
|
|
48
|
+
Add the plugin and provider to `~/.config/opencode/opencode.json`.
|
|
71
49
|
|
|
72
|
-
|
|
50
|
+
> The **node.js** path represents a **package** (directory or npm package name), not a `.js` file. Pointing `"npm"` at a `.js` file will cause a `ProviderInitError` because opencode internally appends `/provider` to resolve the exports map.
|
|
73
51
|
|
|
74
|
-
|
|
52
|
+
### Recommended: automatic from npm
|
|
75
53
|
|
|
76
54
|
```jsonc
|
|
77
55
|
{
|
|
78
56
|
"plugin": [
|
|
79
|
-
|
|
80
|
-
"opencode-agy-bridge@0.2.2"
|
|
57
|
+
"opencode-agy-bridge@0.2.4"
|
|
81
58
|
],
|
|
82
59
|
"provider": {
|
|
83
|
-
// ...your existing providers...
|
|
84
60
|
"agy": {
|
|
85
|
-
"npm": "opencode-agy-bridge
|
|
61
|
+
"npm": "opencode-agy-bridge",
|
|
86
62
|
"name": "Google Antigravity (via agy CLI)",
|
|
87
|
-
"options": {
|
|
88
|
-
|
|
89
|
-
"timeoutMs": 300000
|
|
90
|
-
},
|
|
91
|
-
"models": {
|
|
92
|
-
"antigravity": {
|
|
93
|
-
"name": "Antigravity (server-selected Gemini)"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
63
|
+
"options": { "binary": "agy", "timeoutMs": 300000 },
|
|
64
|
+
"models": { "antigravity": { "name": "Antigravity (server-selected Gemini)" } }
|
|
96
65
|
}
|
|
97
66
|
}
|
|
98
67
|
}
|
|
99
68
|
```
|
|
100
69
|
|
|
101
|
-
###
|
|
70
|
+
### Using npm global install path
|
|
102
71
|
|
|
103
72
|
```jsonc
|
|
104
73
|
{
|
|
105
74
|
"plugin": [
|
|
106
|
-
// ...your existing plugins...
|
|
107
75
|
"opencode-agy-bridge"
|
|
108
76
|
],
|
|
109
77
|
"provider": {
|
|
110
|
-
// ...your existing providers...
|
|
111
78
|
"agy": {
|
|
112
|
-
"npm": "opencode-agy-bridge
|
|
79
|
+
"npm": "opencode-agy-bridge",
|
|
113
80
|
"name": "Google Antigravity (via agy CLI)",
|
|
114
|
-
"options": {
|
|
115
|
-
|
|
116
|
-
"timeoutMs": 300000
|
|
117
|
-
},
|
|
118
|
-
"models": {
|
|
119
|
-
"antigravity": {
|
|
120
|
-
"name": "Antigravity (server-selected Gemini)"
|
|
121
|
-
}
|
|
122
|
-
}
|
|
81
|
+
"options": { "binary": "agy", "timeoutMs": 300000 },
|
|
82
|
+
"models": { "antigravity": { "name": "Antigravity (server-selected Gemini)" } }
|
|
123
83
|
}
|
|
124
84
|
}
|
|
125
85
|
}
|
|
126
86
|
```
|
|
127
87
|
|
|
128
|
-
|
|
129
|
-
> If OpenCode has trouble resolving the global module name directly, you can replace the module names with their absolute paths pointing to your global `node_modules` folder (e.g., `"/usr/local/lib/node_modules/opencode-agy-bridge/dist/plugin.js"` for the plugin and `"/usr/local/lib/node_modules/opencode-agy-bridge/dist/provider.js"` for the provider).
|
|
130
|
-
|
|
131
|
-
### For Local Development / Manual Installation
|
|
88
|
+
### Local development (absolute paths)
|
|
132
89
|
|
|
133
90
|
```jsonc
|
|
134
91
|
{
|
|
135
92
|
"plugin": [
|
|
136
|
-
// ...your existing plugins...
|
|
137
93
|
"/home/USER/workspace/opencode-agy-bridge/dist/plugin.js"
|
|
138
94
|
],
|
|
139
95
|
"provider": {
|
|
140
|
-
// ...your existing providers...
|
|
141
96
|
"agy": {
|
|
142
97
|
"npm": "/home/USER/workspace/opencode-agy-bridge",
|
|
143
98
|
"name": "Google Antigravity (via agy CLI)",
|
|
144
|
-
"options": {
|
|
145
|
-
|
|
146
|
-
"timeoutMs": 300000
|
|
147
|
-
},
|
|
148
|
-
"models": {
|
|
149
|
-
"antigravity": {
|
|
150
|
-
"name": "Antigravity (server-selected Gemini)"
|
|
151
|
-
}
|
|
152
|
-
}
|
|
99
|
+
"options": { "binary": "agy", "timeoutMs": 300000 },
|
|
100
|
+
"models": { "antigravity": { "name": "Antigravity (server-selected Gemini)" } }
|
|
153
101
|
}
|
|
154
102
|
}
|
|
155
103
|
}
|
|
@@ -157,6 +105,10 @@ Just add the package directly with the desired version tag. OpenCode will downlo
|
|
|
157
105
|
|
|
158
106
|
Then restart OpenCode and run `/model` → select `agy/antigravity`.
|
|
159
107
|
|
|
108
|
+
## Features
|
|
109
|
+
|
|
110
|
+
- **Robust Delta Extraction:** Automatically normalizes `\r\n` (CRLF) and `\n` (LF) line endings, tolerates trailing whitespace/newline differences, and implements suffix-based alignment to support seamless recovery during context window truncation.
|
|
111
|
+
|
|
160
112
|
## Known limitations
|
|
161
113
|
|
|
162
114
|
| Limitation | Detail |
|
|
@@ -183,35 +135,17 @@ src/
|
|
|
183
135
|
|
|
184
136
|
## Development
|
|
185
137
|
|
|
186
|
-
Using **Bun**:
|
|
187
|
-
```bash
|
|
188
|
-
bun run build
|
|
189
|
-
bun test
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Using **pnpm**:
|
|
193
|
-
```bash
|
|
194
|
-
pnpm run build
|
|
195
|
-
pnpm test
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Using **npm**:
|
|
199
138
|
```bash
|
|
200
|
-
|
|
201
|
-
|
|
139
|
+
bun run build # compile TypeScript
|
|
140
|
+
bun test # run test suite
|
|
202
141
|
```
|
|
203
142
|
|
|
204
143
|
## CI/CD (GitHub Actions)
|
|
205
144
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- **CI (`ci.yml`):** Runs on push and pull requests to `main` or `master` to compile the project and execute all unit tests using Bun.
|
|
209
|
-
- **Release (`release.yml`):** Runs automatically when a new version tag matching `v*` (e.g., `v0.2.2`) is pushed to the repository. It automatically installs dependencies, builds, tests, and publishes the package to the public npm registry.
|
|
210
|
-
|
|
211
|
-
Note that both `npm` and `pnpm` share the same public registry (`registry.npmjs.org`), so a single publish step makes the package installable by both package managers.
|
|
145
|
+
- **CI (`ci.yml`):** Runs on push and pull requests to `main` — compiles and runs all tests.
|
|
146
|
+
- **Release (`release.yml`):** Runs on `v*` tags — builds, tests, and publishes to npm.
|
|
212
147
|
|
|
213
148
|
### Setup
|
|
214
149
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
2. Add the token as a repository secret named `NPM_TOKEN` in your GitHub repository settings under **Settings** → **Secrets and variables** → **Actions**.
|
|
150
|
+
1. Generate a Granular Access Token on [npmjs.com](https://www.npmjs.com/) with **Bypass 2FA** enabled.
|
|
151
|
+
2. Add it as repository secret `NPM_TOKEN` in GitHub **Settings → Secrets and variables → Actions**.
|
package/dist/plugin.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const plugin = async () => ({
|
|
2
|
+
config: async () => { },
|
|
2
3
|
"chat.headers": async (incoming, output) => {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
if (incoming?.model?.providerID !== "agy")
|
|
5
|
+
return;
|
|
6
|
+
if (!output?.headers)
|
|
5
7
|
return;
|
|
6
|
-
// Pass the stable OpenCode session ID so agy can reuse conversations
|
|
7
8
|
output.headers["x-agy-session-id"] = incoming.sessionID;
|
|
8
9
|
},
|
|
9
10
|
});
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProviderV2 } from "@ai-sdk/provider";
|
|
1
|
+
import type { ProviderV2, LanguageModelV2 } from "@ai-sdk/provider";
|
|
2
2
|
export interface AgyProviderOptions {
|
|
3
3
|
binary?: string;
|
|
4
4
|
conversationsDir?: string;
|
|
@@ -7,5 +7,8 @@ export interface AgyProviderOptions {
|
|
|
7
7
|
timeoutMs?: number;
|
|
8
8
|
}
|
|
9
9
|
export declare function extractDelta(prevOutput: string, fullText: string, conversationBound: boolean): string;
|
|
10
|
-
export declare function createAgyProvider(opts?: AgyProviderOptions): ProviderV2
|
|
10
|
+
export declare function createAgyProvider(opts?: AgyProviderOptions): ProviderV2 & {
|
|
11
|
+
(modelId: string): LanguageModelV2;
|
|
12
|
+
provider: string;
|
|
13
|
+
};
|
|
11
14
|
export default function defaultFactory(opts?: AgyProviderOptions): ProviderV2;
|
package/dist/provider.js
CHANGED
|
@@ -49,8 +49,6 @@ function buildLanguageModel(modelId, opts) {
|
|
|
49
49
|
const store = new SessionStore(opts.stateFile);
|
|
50
50
|
const conversationsDir = opts.conversationsDir ?? defaultConversationsDir();
|
|
51
51
|
const doGenerate = async (callOpts) => {
|
|
52
|
-
// Use the stable OpenCode session ID injected via plugin chat.headers hook.
|
|
53
|
-
// Falls back to providerMetadata or a random UUID for standalone/testing.
|
|
54
52
|
const sessionId = callOpts.headers?.["x-agy-session-id"] ??
|
|
55
53
|
callOpts.providerOptions?.agy
|
|
56
54
|
?.sessionId ??
|
|
@@ -68,13 +66,11 @@ function buildLanguageModel(modelId, opts) {
|
|
|
68
66
|
let before = null;
|
|
69
67
|
try {
|
|
70
68
|
before = conversationId ? null : await snapshot(conversationsDir);
|
|
71
|
-
// Only send new messages when conversation is already bound.
|
|
72
|
-
// agy preserves context internally via --conversation, so sending
|
|
73
|
-
// the full history each turn confuses it and causes hallucination.
|
|
74
69
|
const newMessages = conversationId
|
|
75
70
|
? callOpts.prompt.slice(processedMessages)
|
|
76
71
|
: callOpts.prompt;
|
|
77
72
|
const prompt = flattenPrompt(newMessages);
|
|
73
|
+
console.error("[agy-bridge] doGenerate session=%s conv=%s msgs=%d/%d", sessionId.slice(0, 8), conversationId?.slice(0, 8) ?? "-", newMessages.length, callOpts.prompt.length);
|
|
78
74
|
const result = await runAgy({
|
|
79
75
|
prompt,
|
|
80
76
|
cwd: process.cwd(),
|
|
@@ -195,19 +191,48 @@ function buildLanguageModel(modelId, opts) {
|
|
|
195
191
|
doStream,
|
|
196
192
|
};
|
|
197
193
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const languageModel = (modelId) => buildLanguageModel(modelId, resolvedOpts);
|
|
194
|
+
let factoryInitWarned = false;
|
|
195
|
+
function unsupportedEmbeddingModel(modelId) {
|
|
201
196
|
return {
|
|
202
|
-
|
|
203
|
-
|
|
197
|
+
specificationVersion: "v2",
|
|
198
|
+
provider: "agy",
|
|
199
|
+
modelId,
|
|
200
|
+
maxEmbeddingsPerCall: 0,
|
|
201
|
+
supportsParallelCalls: false,
|
|
202
|
+
doEmbed: async () => {
|
|
204
203
|
throw new Error("agy bridge does not support text embeddings");
|
|
205
204
|
},
|
|
206
|
-
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function unsupportedImageModel(modelId) {
|
|
208
|
+
return {
|
|
209
|
+
specificationVersion: "v2",
|
|
210
|
+
provider: "agy",
|
|
211
|
+
modelId,
|
|
212
|
+
maxImagesPerCall: 0,
|
|
213
|
+
doGenerate: async () => {
|
|
207
214
|
throw new Error("agy bridge does not support image generation");
|
|
208
215
|
},
|
|
209
216
|
};
|
|
210
217
|
}
|
|
218
|
+
export function createAgyProvider(opts) {
|
|
219
|
+
const resolvedOpts = opts ?? {};
|
|
220
|
+
if (!factoryInitWarned) {
|
|
221
|
+
factoryInitWarned = true;
|
|
222
|
+
console.error("[agy-bridge] createAgyProvider called");
|
|
223
|
+
}
|
|
224
|
+
const factory = (modelId) => {
|
|
225
|
+
console.error("[agy-bridge] languageModel called for modelId=%s", modelId);
|
|
226
|
+
return buildLanguageModel(modelId, resolvedOpts);
|
|
227
|
+
};
|
|
228
|
+
factory.provider = "agy";
|
|
229
|
+
factory.specificationVersion = "v2";
|
|
230
|
+
factory.languageModel = factory;
|
|
231
|
+
factory.textEmbeddingModel = (modelId) => unsupportedEmbeddingModel(modelId);
|
|
232
|
+
factory.imageModel = (modelId) => unsupportedImageModel(modelId);
|
|
233
|
+
return factory;
|
|
234
|
+
}
|
|
211
235
|
export default function defaultFactory(opts) {
|
|
236
|
+
console.error("[agy-bridge] defaultFactory called");
|
|
212
237
|
return createAgyProvider(opts);
|
|
213
238
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-agy-bridge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "./
|
|
5
|
+
"main": "./dist/provider.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"description": "OpenCode plugin + provider that routes LLM prompts to agy (Google Antigravity CLI)",
|
|
8
8
|
"exports": {
|
|
9
|
-
".": "./dist/
|
|
10
|
-
"./provider": "./dist/provider.js"
|
|
9
|
+
".": "./dist/provider.js",
|
|
10
|
+
"./provider": "./dist/provider.js",
|
|
11
|
+
"./plugin": "./dist/plugin.js"
|
|
11
12
|
},
|
|
12
13
|
"files": [
|
|
13
14
|
"dist",
|
|
@@ -18,12 +19,22 @@
|
|
|
18
19
|
"build": "tsc",
|
|
19
20
|
"test": "bun test"
|
|
20
21
|
},
|
|
21
|
-
"
|
|
22
|
+
"peerDependencies": {
|
|
22
23
|
"@ai-sdk/provider": "^3.0.0"
|
|
23
24
|
},
|
|
25
|
+
"peerDependenciesMeta": {
|
|
26
|
+
"@ai-sdk/provider": {
|
|
27
|
+
"optional": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
24
30
|
"devDependencies": {
|
|
31
|
+
"@ai-sdk/provider": "^3.0.0",
|
|
25
32
|
"@opencode-ai/plugin": "^1.15.12",
|
|
26
33
|
"@types/bun": "latest",
|
|
27
34
|
"typescript": "^5.8.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@ai-sdk/openai": "^3.0.67",
|
|
38
|
+
"zod": "^3.25.0-beta.20250519T094321"
|
|
28
39
|
}
|
|
29
40
|
}
|