opencode-see-image 0.1.0 → 0.2.1
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 +35 -3
- package/index.ts +47 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,13 +22,23 @@ That's it — the plugin self-contains both the tool and the triggering instruct
|
|
|
22
22
|
|
|
23
23
|
## Prerequisites
|
|
24
24
|
|
|
25
|
-
You need a connected vision-capable provider. The
|
|
25
|
+
You need a connected vision-capable provider. The plugin auto-detects whichever you have connected — **either of these works**:
|
|
26
26
|
|
|
27
|
+
### Option A — Free (OpenCode Zen)
|
|
28
|
+
1. Run `/connect` in opencode
|
|
29
|
+
2. Select **opencode** (OpenCode Zen)
|
|
30
|
+
3. Paste your API key from [opencode.ai/auth](https://opencode.ai/auth)
|
|
31
|
+
|
|
32
|
+
The plugin falls back to **big-pickle** (free, vision-capable, ~20s). No subscription needed.
|
|
33
|
+
|
|
34
|
+
### Option B — Paid, fast (OpenCode Go)
|
|
27
35
|
1. Run `/connect` in opencode
|
|
28
36
|
2. Select **opencode-go**
|
|
29
37
|
3. Paste your API key from [opencode.ai/auth](https://opencode.ai/auth)
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
The plugin prefers **minimax-m3** via opencode-go (~3s) when available.
|
|
40
|
+
|
|
41
|
+
**Resolution order:** explicit `SEE_IMAGE_API_KEY` env → configured `SEE_IMAGE_PROVIDER` → `opencode-go` (MiniMax M3) → `opencode` (big-pickle, free).
|
|
32
42
|
|
|
33
43
|
## How it works
|
|
34
44
|
|
|
@@ -81,7 +91,15 @@ To use a different opencode-go model (e.g. Kimi K2.7):
|
|
|
81
91
|
export SEE_IMAGE_MODEL="kimi-k2.7-code"
|
|
82
92
|
```
|
|
83
93
|
|
|
84
|
-
### Verified vision-capable models
|
|
94
|
+
### Verified vision-capable models
|
|
95
|
+
|
|
96
|
+
**Free (OpenCode Zen):**
|
|
97
|
+
|
|
98
|
+
| Model | Speed | Notes |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `big-pickle` | ~20s | Free. Accurate. Default fallback when only Zen is connected. |
|
|
101
|
+
|
|
102
|
+
**Paid (OpenCode Go):**
|
|
85
103
|
|
|
86
104
|
| Model | Speed | Notes |
|
|
87
105
|
|---|---|---|
|
|
@@ -102,6 +120,20 @@ When opencode rejects an image attachment, the model only receives a bare filena
|
|
|
102
120
|
|
|
103
121
|
Pass an absolute `filePath` to skip the search.
|
|
104
122
|
|
|
123
|
+
## Install via your agent (copy-paste this)
|
|
124
|
+
|
|
125
|
+
Paste this prompt to your opencode agent — it'll install the plugin for you:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Install the opencode-see-image plugin so I can send you screenshots. Do this:
|
|
129
|
+
|
|
130
|
+
1. Edit ~/.config/opencode/opencode.jsonc (create it if missing). Preserve any existing fields and the $schema. Add "opencode-see-image" to the "plugin" array. If "plugin" doesn't exist, add it as ["opencode-see-image"].
|
|
131
|
+
2. Check that a vision-capable provider is connected by looking for ~/.local/share/opencode/auth.json with either an "opencode-go" entry (paid, fast) OR an "opencode" entry (free). If neither is present, tell me to run /connect and select either opencode-go or opencode (key from opencode.ai/auth).
|
|
132
|
+
3. Tell me to quit and restart opencode for the plugin to load.
|
|
133
|
+
|
|
134
|
+
After I restart and attach a screenshot, you should call the see_image tool to view it.
|
|
135
|
+
```
|
|
136
|
+
|
|
105
137
|
## License
|
|
106
138
|
|
|
107
139
|
MIT
|
package/index.ts
CHANGED
|
@@ -28,26 +28,53 @@ const EXT_MEDIA: Record<string, string> = {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// ─── Auth ───────────────────────────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Resolves a usable API key + the endpoint + model to use. Falls back through
|
|
32
|
+
// a chain so users with any connected opencode subscription (paid opencode-go
|
|
33
|
+
// or free opencode Zen) get a working default with zero config.
|
|
34
|
+
function resolveAuth(): { key: string; endpoint: string; model: string } {
|
|
35
|
+
// 1. Explicit env vars win outright.
|
|
36
|
+
if (process.env.SEE_IMAGE_API_KEY) {
|
|
37
|
+
return { key: process.env.SEE_IMAGE_API_KEY, endpoint: ENDPOINT, model: MODEL }
|
|
38
|
+
}
|
|
34
39
|
|
|
35
|
-
// 2.
|
|
40
|
+
// 2. Walk opencode's auth store and try the configured provider first,
|
|
41
|
+
// then a curated fallback chain (paid → free).
|
|
36
42
|
const authPath = path.join(os.homedir(), ".local/share/opencode/auth.json")
|
|
43
|
+
let auth: any = {}
|
|
37
44
|
try {
|
|
38
|
-
|
|
39
|
-
const entry = auth[PROVIDER_ID]
|
|
40
|
-
if (entry && (entry.key || entry.access)) {
|
|
41
|
-
return entry.key || entry.access
|
|
42
|
-
}
|
|
45
|
+
auth = JSON.parse(fs.readFileSync(authPath, "utf8"))
|
|
43
46
|
} catch {
|
|
44
|
-
//
|
|
47
|
+
// ignore — handled by the empty-auth path below
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Each candidate: [providerId, endpoint, defaultModel]
|
|
51
|
+
const candidates: Array<[string, string, string]> = [
|
|
52
|
+
[PROVIDER_ID, ENDPOINT, MODEL],
|
|
53
|
+
// Free fallback: OpenCode Zen's big-pickle supports vision at no cost.
|
|
54
|
+
["opencode", "https://opencode.ai/zen/v1/messages", "big-pickle"],
|
|
55
|
+
// Paid fallbacks on opencode-go:
|
|
56
|
+
["opencode-go", "https://opencode.ai/zen/go/v1/messages", "minimax-m3"],
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
const tried: string[] = []
|
|
60
|
+
for (const [pid, ep, mdl] of candidates) {
|
|
61
|
+
const entry = auth[pid]
|
|
62
|
+
const k = entry && (entry.key || entry.access)
|
|
63
|
+
if (k) {
|
|
64
|
+
// If the user pinned PROVIDER_ID but not MODEL, honor the candidate's
|
|
65
|
+
// default model only when provider matches the pinned one; otherwise
|
|
66
|
+
// keep the configured MODEL (may be set via env).
|
|
67
|
+
const useModel =
|
|
68
|
+
pid === PROVIDER_ID || !process.env.SEE_IMAGE_MODEL ? mdl : MODEL
|
|
69
|
+
return { key: k, endpoint: ep, model: useModel }
|
|
70
|
+
}
|
|
71
|
+
tried.push(pid)
|
|
45
72
|
}
|
|
46
73
|
|
|
47
74
|
throw new Error(
|
|
48
|
-
`see_image: no API key.
|
|
49
|
-
`
|
|
50
|
-
`(
|
|
75
|
+
`see_image: no API key. Connect a provider in opencode via /connect — ` +
|
|
76
|
+
`either "opencode-go" (paid, fast MiniMax M3) or "opencode" (free, big-pickle). ` +
|
|
77
|
+
`Or set SEE_IMAGE_API_KEY explicitly. (Checked providers: ${tried.join(", ") || "none"} in ${authPath}.)`,
|
|
51
78
|
)
|
|
52
79
|
}
|
|
53
80
|
|
|
@@ -136,8 +163,10 @@ const seeImageTool = tool({
|
|
|
136
163
|
? args.question
|
|
137
164
|
: "Describe this image in detail. If it is a screenshot, describe the UI, text content, and layout precisely. This description will be used by another model to answer the user, so be thorough and accurate."
|
|
138
165
|
|
|
166
|
+
const { key, endpoint, model } = resolveAuth()
|
|
167
|
+
|
|
139
168
|
const body = {
|
|
140
|
-
model
|
|
169
|
+
model,
|
|
141
170
|
max_tokens: 2048,
|
|
142
171
|
messages: [
|
|
143
172
|
{
|
|
@@ -153,8 +182,7 @@ const seeImageTool = tool({
|
|
|
153
182
|
],
|
|
154
183
|
}
|
|
155
184
|
|
|
156
|
-
const
|
|
157
|
-
const res = await fetch(ENDPOINT, {
|
|
185
|
+
const res = await fetch(endpoint, {
|
|
158
186
|
method: "POST",
|
|
159
187
|
headers: {
|
|
160
188
|
"x-api-key": key,
|
|
@@ -168,7 +196,7 @@ const seeImageTool = tool({
|
|
|
168
196
|
if (!res.ok) {
|
|
169
197
|
const errText = await res.text()
|
|
170
198
|
throw new Error(
|
|
171
|
-
`see_image: vision call to "${
|
|
199
|
+
`see_image: vision call to "${model}" @ ${endpoint} failed: HTTP ${res.status} — ${errText.slice(0, 300)}`,
|
|
172
200
|
)
|
|
173
201
|
}
|
|
174
202
|
|
|
@@ -183,13 +211,13 @@ const seeImageTool = tool({
|
|
|
183
211
|
|
|
184
212
|
if (!text) {
|
|
185
213
|
throw new Error(
|
|
186
|
-
`see_image: model "${
|
|
214
|
+
`see_image: model "${model}" returned no text. Response: ${JSON.stringify(data).slice(0, 300)}`,
|
|
187
215
|
)
|
|
188
216
|
}
|
|
189
217
|
|
|
190
218
|
context.metadata({
|
|
191
219
|
title: `see_image: ${path.basename(fullPath)}`,
|
|
192
|
-
metadata: { model
|
|
220
|
+
metadata: { model, endpoint, file: fullPath },
|
|
193
221
|
})
|
|
194
222
|
|
|
195
223
|
return text
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-see-image",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Give non-vision opencode models the ability to see images/screenshots by routing them to a vision-capable model (MiniMax M3 via opencode-go by default).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|