opencode-actualyze 2.0.0 → 2.0.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 +521 -499
- package/dist/rpc.d.ts +2 -2
- package/dist/server.js +9 -14
- package/dist/tui.js +67 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,26 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/opencode-actualyze)
|
|
4
4
|
[](https://github.com/actualyze-ai/opencode-actualyze/actions/workflows/release.yml)
|
|
5
|
-
[](https://opensource.org/
|
|
5
|
+
[](https://opensource.org/license/MIT)
|
|
6
6
|
|
|
7
7
|
Actualyze's plugin for [OpenCode](https://opencode.ai) adds
|
|
8
|
-
[Actualyze](https://actualyze.ai) as a provider.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
reasoning
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
[Actualyze](https://actualyze.ai) as a provider. Connect an Actualyze API key
|
|
9
|
+
and your team's models appear in OpenCode's model picker, with no provider
|
|
10
|
+
config. The plugin fills in each model's context and output limits, its tool
|
|
11
|
+
and reasoning support, its input types, and its prices from Actualyze's
|
|
12
|
+
catalog. The `/actualyze` command shows the key in use, whether the catalog
|
|
13
|
+
answered for it, the model list, and links into the Actualyze app.
|
|
14
|
+
|
|
15
|
+
It also works with other OpenAI-compatible servers: it detects the models a
|
|
16
|
+
server serves and populates their catalog entries the same way. Probes read
|
|
17
|
+
the metadata of eight servers: Actualyze, Ollama, oMLX, vLLM, TGI, SGLang,
|
|
18
|
+
LM Studio, and KoboldCpp. The Ollama probe also covers llama.cpp and LocalAI.
|
|
19
|
+
The Model Scout browser, `/modelscout`, lists every discovered model and
|
|
20
|
+
where each value came from.
|
|
21
|
+
|
|
22
|
+
The plugin requires OpenCode 2 and is tested against OpenCode 2.1.3. If you
|
|
23
|
+
used `opencode-model-scout`, see
|
|
19
24
|
[Moving from opencode-model-scout](#moving-from-opencode-model-scout).
|
|
20
25
|
|
|
21
26
|
## Quick Start
|
|
22
27
|
|
|
23
|
-
### With Actualyze
|
|
24
|
-
|
|
25
28
|
Actualyze needs no provider config. The plugin adds an `actualyze` provider
|
|
26
29
|
for `https://app.actualyze.ai/openai/v1`, and it appears as soon as OpenCode
|
|
27
30
|
has your API key.
|
|
@@ -48,12 +51,251 @@ has your API key.
|
|
|
48
51
|
|
|
49
52
|
3. The Actualyze models appear in the model picker once discovery finishes.
|
|
50
53
|
`/actualyze` shows whether the catalog answered for your key and, if it
|
|
51
|
-
did not, what to do next.
|
|
52
|
-
|
|
54
|
+
did not, what to do next.
|
|
55
|
+
|
|
56
|
+
For a server other than Actualyze, see
|
|
57
|
+
[Other OpenAI-Compatible Servers](#other-openai-compatible-servers).
|
|
58
|
+
|
|
59
|
+
## Actualyze
|
|
60
|
+
|
|
61
|
+
Actualyze serves its model catalog through an OpenAI-compatible endpoint, and
|
|
62
|
+
its `/v1/models` entries can carry each model's full metadata.
|
|
63
|
+
|
|
64
|
+
### The built-in provider
|
|
65
|
+
|
|
66
|
+
The plugin adds this provider to OpenCode's catalog:
|
|
67
|
+
|
|
68
|
+
| Field | Value |
|
|
69
|
+
| ------------------ | ------------------------------------------ |
|
|
70
|
+
| ID | `actualyze` |
|
|
71
|
+
| Name | Actualyze |
|
|
72
|
+
| `package` | `@opencode/ai/providers/openai-compatible` |
|
|
73
|
+
| `settings.baseURL` | `https://app.actualyze.ai/openai/v1` |
|
|
74
|
+
| `settings.probe` | `actualyze` |
|
|
75
|
+
|
|
76
|
+
It also registers an Actualyze integration, which is what `/connect` and
|
|
77
|
+
`opencode auth login actualyze` offer. The integration takes a stored API key
|
|
78
|
+
or the `ACTUALYZE_API_KEY` environment variable of the background service.
|
|
79
|
+
Discovery and chat both use that key. The integration's ID is `actualyze`,
|
|
80
|
+
the same as the provider's, so a `providers.actualyze` config entry and
|
|
81
|
+
`opencode auth login actualyze` both reach the integration the provider reads
|
|
82
|
+
its key from.
|
|
83
|
+
|
|
84
|
+
Until the integration has a key, OpenCode hides the provider, so without an
|
|
85
|
+
Actualyze key the built-in provider adds nothing to the model picker.
|
|
86
|
+
|
|
87
|
+
### Another Actualyze environment
|
|
88
|
+
|
|
89
|
+
To use a different deployment, set only its base URL. Your config is merged
|
|
90
|
+
over the built-in provider field by field, so the name, package, probe, and
|
|
91
|
+
key handling stay as they are:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"providers": {
|
|
96
|
+
"actualyze": {
|
|
97
|
+
"settings": {
|
|
98
|
+
"baseURL": "https://actualyze.example.com/openai/v1"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Any `providers.actualyze` entry in your config makes OpenCode list the
|
|
106
|
+
provider even without a key. Discovery then runs without credentials, and
|
|
107
|
+
`/modelscout` and `/actualyze` show the endpoint's error until you add one.
|
|
108
|
+
Add the key with `/actualyze`, `/connect`, or `opencode auth login actualyze`
|
|
109
|
+
as usual: the entry does not create a second Actualyze integration. A
|
|
110
|
+
`settings.apiKey` in the entry also works, without connecting the
|
|
111
|
+
integration. A connected key takes precedence over `settings.apiKey` for both
|
|
112
|
+
discovery and chat, so the two always use the same key.
|
|
113
|
+
|
|
114
|
+
### When another source defines `actualyze`
|
|
115
|
+
|
|
116
|
+
A models.dev catalog or a plugin listed before this one can define an
|
|
117
|
+
`actualyze` provider of its own. Then:
|
|
118
|
+
|
|
119
|
+
- The plugin leaves that provider as it is and does not add its own.
|
|
120
|
+
- The plugin registers the `actualyze` integration only when no source has
|
|
121
|
+
registered one, so `/connect` lists Actualyze once.
|
|
122
|
+
- A provider defined with `"activation": "auto"` and no integration of its
|
|
123
|
+
own reads its key from that `actualyze` integration, so OpenCode hides it
|
|
124
|
+
until a key is connected there.
|
|
125
|
+
- The plugin does not discover that provider, because OpenCode already knows
|
|
126
|
+
its ID, and `/actualyze` reads `○ Not managed by Model Scout`. Add
|
|
127
|
+
`"probe": "actualyze"` to its `settings` in your config to opt in.
|
|
128
|
+
|
|
129
|
+
### What the plugin reads from Actualyze
|
|
130
|
+
|
|
131
|
+
- **Which entries.** In auto mode, one entry whose `owned_by` is exactly
|
|
132
|
+
`actualyze` selects the probe, even in a catalog that mixes owners, and the
|
|
133
|
+
probe checks only the entries Actualyze owns. The rest are listed and
|
|
134
|
+
enriched from models.dev as usual. With `"probe": "actualyze"`, the
|
|
135
|
+
built-in provider's setting, the probe checks every listed model.
|
|
136
|
+
- **List first.** A checked entry that Actualyze owns and that carries the
|
|
137
|
+
full metadata (the `context_window` key and a `capabilities` object) is
|
|
138
|
+
read straight from `/v1/models`. For every other checked entry the probe
|
|
139
|
+
requests `GET /v1/models/{id}`, and it keeps the answer only when Actualyze
|
|
140
|
+
owns that model.
|
|
141
|
+
- **Fields.** `context_window` and `max_output_tokens` become the limits.
|
|
142
|
+
Capability flags (`vision`, `tool_use`, `thinking`, `thinking_adaptive`,
|
|
143
|
+
`temperature`, `document`, `audio`, `video`) are three-valued: `true` and
|
|
144
|
+
`false` are definitive, `null` means unknown. `modalities.input` is used
|
|
145
|
+
for input modalities when present. `created` becomes the release time.
|
|
146
|
+
- **Cost.** `cost.input`, `cost.output`, `cost.cache_read`, and
|
|
147
|
+
`cost.cache_write` are USD per million tokens. The plugin writes a missing
|
|
148
|
+
cache price as `0` in OpenCode's `cost`, and `/modelscout` shows it as not
|
|
149
|
+
reported. A model without `cost` gets no prices.
|
|
150
|
+
- **No effort variants.** Actualyze's chat endpoint does not pass
|
|
151
|
+
`reasoning_effort` on to the upstream model, so reasoning models from
|
|
152
|
+
Actualyze get no `low`/`medium`/`high` variants.
|
|
153
|
+
|
|
154
|
+
## `/actualyze` Command
|
|
155
|
+
|
|
156
|
+
`/actualyze` takes you from no key to a working Actualyze catalog without
|
|
157
|
+
leaving OpenCode. Open it with `/actualyze`, pick **Actualyze** from the
|
|
158
|
+
command palette, or press `a` in `/modelscout`.
|
|
159
|
+
|
|
160
|
+
The header shows the Actualyze wordmark and the endpoint: its host for an
|
|
161
|
+
https endpoint, such as `app.actualyze.ai` for the built-in provider, and
|
|
162
|
+
`http://host:port` for an http one. When
|
|
163
|
+
`providers.actualyze.settings.baseURL` points anywhere other than the
|
|
164
|
+
built-in endpoint, the header adds a `custom endpoint` badge, and every app
|
|
165
|
+
link uses that endpoint's origin. The line under the header says where
|
|
166
|
+
things stand, and names the key in use: the connection's label in quotes,
|
|
167
|
+
`ACTUALYZE_API_KEY` for the environment variable, or `settings.apiKey`.
|
|
168
|
+
|
|
169
|
+
An Actualyze inference key can read the model catalog and nothing about the
|
|
170
|
+
account: no identity, usage, spend, or budget. So `/actualyze` reports
|
|
171
|
+
"Catalog accessible" when the model list answered for the key, and never
|
|
172
|
+
claims that chat works. A read-only key, for example, lists models and is
|
|
173
|
+
refused on every chat request.
|
|
174
|
+
|
|
175
|
+
### States
|
|
176
|
+
|
|
177
|
+
| Status line | What it means | What to do |
|
|
178
|
+
| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
179
|
+
| `○ Loading…` | `/actualyze` is reading OpenCode's model lists and the plugin's catalog. | Wait. |
|
|
180
|
+
| `▲ OpenCode's model lists did not load` | OpenCode did not answer with its provider and model lists. The error is shown below the status line. | `r` reads them again. |
|
|
181
|
+
| `○ Not connected` | OpenCode has no Actualyze key. | Create a key in the app, then press `k` and paste it. The card lists the steps. |
|
|
182
|
+
| `○ Saving key…` | You submitted a key and OpenCode has not confirmed it yet. | Wait. Closing the dialog does not undo a completed save. |
|
|
183
|
+
| `▲ Save not confirmed` | Saving failed or took longer than 15 seconds. OpenCode may have stored the key anyway. | Check with `c` before trying again with `k`. |
|
|
184
|
+
| `○ Checking the current connection…` | The key is saved and the plugin has no result for it yet. After 20 seconds the line reads "Still checking the current connection…". | Wait. No inference request is sent. |
|
|
185
|
+
| `○ Checking the connection…` | A key is connected and the plugin is still resolving it. | Wait. |
|
|
186
|
+
| `○ Loading models…` | The first model list for this key is on its way. | Wait. |
|
|
187
|
+
| `● Catalog accessible · key "Work" · 11 models · checked 2 min ago` | The model list answered. The count is chat models, as in `/modelscout`; the filter row reports hidden embeddings. | Browse them; `enter` on a model opens the model picker with it highlighted. |
|
|
188
|
+
| `▲ No models for this key` | The catalog answered with an empty list: the key works, but its team has no model access yet. | Ask a workspace admin. `y` copies the Catalog link. |
|
|
189
|
+
| `▲ Key rejected (401)` | Actualyze answers this way for a revoked or expired key, a key without the inference scope, or a key from another Actualyze environment. | `k` for another key, `y` to copy the API Keys link, `c` for connections. |
|
|
190
|
+
| `▲ Access denied (403)` | Actualyze refused the model list request for this key. | Check the key's permissions and model access with your administrator, or use `k` for another key. |
|
|
191
|
+
| `▲ Budget or entitlement blocked (402)` | Actualyze did not allow the model list request. The key cannot read a balance or reset date. | `y` copies the Budgets link; that page may need an admin role. |
|
|
192
|
+
| `▲ Catalog rate limited (429)` | The model list is rate limited. This is a catalog limit, not an inference quota. The footer shows the wait: `retry (42 s) r`. | Retry with `r` once the wait ends; otherwise the plugin checks again on its next scheduled refresh, or when settings or the key change. |
|
|
193
|
+
| `▲ Could not reach the endpoint` | The connection failed. The header shows the endpoint. | Check the network, VPN, proxy, and `providers.actualyze.settings.baseURL`, then retry with `r`. |
|
|
194
|
+
| `▲ Endpoint did not answer in time` | The model list request timed out. | Check the network or the endpoint, then retry with `r`. |
|
|
195
|
+
| `▲ Actualyze server error (503)` | Actualyze failed to list its models. | Retry with `r`. |
|
|
196
|
+
| `▲ No model list at this endpoint (404)` | The base URL points at the wrong path. | Make `settings.baseURL` end in `/openai/v1`. |
|
|
197
|
+
| `▲ Unexpected answer (…)` | Another HTTP status, or an answer that is not a model list. | Check `settings.baseURL`. |
|
|
198
|
+
| `▲ Discovery was interrupted` or `▲ Discovery failed` | The check did not finish. | It runs again on the next refresh; `r` retries now. |
|
|
199
|
+
| `▲ Discovery status unavailable` | The plugin's server half did not answer, so only the connection OpenCode reports is known. | `k` and `c` still work; `r` reads the catalog again. |
|
|
200
|
+
| `○ Not managed by Model Scout` | Another plugin or a models.dev catalog defines the `actualyze` provider, so the plugin does not discover it. | Add `"probe": "actualyze"` to `providers.actualyze.settings` to opt in. |
|
|
201
|
+
|
|
202
|
+
The glyph carries the state's color; the words stay in the theme's text
|
|
203
|
+
color. When the line is too narrow, the age goes first and then the key
|
|
204
|
+
label, whole, so the line never ends in a cut word. Each card under the
|
|
205
|
+
status line starts with a title and gives the details below it.
|
|
206
|
+
|
|
207
|
+
After a failure, a key that had a good catalog before keeps it: the card sits
|
|
208
|
+
above the models from the last good check. When the key comes from
|
|
209
|
+
`settings.apiKey` or `ACTUALYZE_API_KEY`, the failure card says so, and adds
|
|
210
|
+
that a key connected with `k` takes precedence. When the provider's
|
|
211
|
+
`headers` carry the key (`Authorization` or `X-Actualyze-Api-Key`), a notice
|
|
212
|
+
says that discovery uses those headers, not the connected key.
|
|
213
|
+
|
|
214
|
+
When `providers.actualyze.settings.probe` names no probe, the status line
|
|
215
|
+
adds `▲ unknown probe` once the catalog is accessible, and a notice names the
|
|
216
|
+
value and lists the accepted ones. Remove the setting, or set it to
|
|
217
|
+
`actualyze`, so the probe reads the models' limits, prices, and
|
|
218
|
+
capabilities.
|
|
219
|
+
|
|
220
|
+
### Keys in `/actualyze`
|
|
221
|
+
|
|
222
|
+
| Key | Action |
|
|
223
|
+
| ----- | ----------------------------------------------------------------------------------- |
|
|
224
|
+
| `k` | Connect a key: "connect key" without a connection, "another key" with one |
|
|
225
|
+
| `c` | Open OpenCode's connections; pick Actualyze there to switch, rename, or remove keys |
|
|
226
|
+
| `l` | Open the [links screen](#links) |
|
|
227
|
+
| `y` | On a card, copy the link it names; in the model list, copy `provider/model` |
|
|
228
|
+
| `r` | Check the catalog again; during a wait the hint is dimmed and reads "retry (N s)" |
|
|
229
|
+
| `b` | Open `/modelscout` |
|
|
230
|
+
| `?` | List the keys |
|
|
231
|
+
| `esc` | Close |
|
|
232
|
+
|
|
233
|
+
While a card fills the dialog, only the keys it offers, `?`, and `esc` work.
|
|
234
|
+
The footer lists the card's keys in one order: the key action, retry, copy
|
|
235
|
+
link, links, connections, all providers, then keys. When the footer runs out
|
|
236
|
+
of room it leaves out the hints that do not fit and keeps any later one that
|
|
237
|
+
does; the card then lists the left-out keys in an action line at its end, in
|
|
238
|
+
the same order, so every key shows once. `?` lists them all. A card longer
|
|
239
|
+
than the dialog shows `↓ N more` and scrolls with `↑`, `↓`, `pgup`, `pgdn`,
|
|
240
|
+
`home`, and `end`; the footer adds `scroll ↑↓` after the card's keys when
|
|
241
|
+
there is room for all of them.
|
|
53
242
|
|
|
54
|
-
|
|
243
|
+
Once the catalog is accessible, the model list works like `/modelscout`
|
|
244
|
+
limited to Actualyze, without a provider header or provider filter. `r`
|
|
245
|
+
refreshes Actualyze; there is no `R`. The footer shows `k` and `l` after the
|
|
246
|
+
model keys and, when there is room, `c` and `b` at its end; `?` lists all
|
|
247
|
+
four.
|
|
248
|
+
|
|
249
|
+
`k` works only when the provider reads its key from the `actualyze`
|
|
250
|
+
integration and that integration offers a plain key method. Otherwise the
|
|
251
|
+
card points to `c`. The plugin never deletes a key; removing one happens in
|
|
252
|
+
OpenCode's connections.
|
|
253
|
+
|
|
254
|
+
### Entering a key
|
|
255
|
+
|
|
256
|
+
`k` opens OpenCode's prompt titled **Actualyze API key**. The key is visible
|
|
257
|
+
while you type, because OpenCode's prompt does not mask input. Press `enter`
|
|
258
|
+
to submit. The plugin trims the key, hands it once to OpenCode to store under
|
|
259
|
+
the Actualyze integration, and drops it; it never stores, logs, or shows the
|
|
260
|
+
key itself. `/actualyze` then comes back, shows "Saving key…", and checks the
|
|
261
|
+
catalog with the new key.
|
|
262
|
+
|
|
263
|
+
Pressing `esc` in the prompt cancels and closes `/actualyze`. Submitting an
|
|
264
|
+
empty prompt returns to `/actualyze` unchanged. If the plugin reloads while
|
|
265
|
+
the prompt is open, the prompt closes and nothing is saved; enter the key
|
|
266
|
+
again with `/actualyze`. A key submitted after the plugin reloaded, or after
|
|
267
|
+
the project changed, is not saved either, and a toast says so. If you close
|
|
268
|
+
`/actualyze` while OpenCode is still saving and the save is never confirmed,
|
|
269
|
+
a toast says "OpenCode did not confirm the Actualyze key was saved".
|
|
270
|
+
|
|
271
|
+
### Links
|
|
272
|
+
|
|
273
|
+
`l` lists Actualyze app pages on the provider's origin:
|
|
274
|
+
|
|
275
|
+
| Link | Path |
|
|
276
|
+
| --------------- | ------------------------------------ |
|
|
277
|
+
| API Keys | `/account/settings?tab=security` |
|
|
278
|
+
| Catalog | `/control/catalog?tab=consume` |
|
|
279
|
+
| Budgets | `/management/budgets` |
|
|
280
|
+
| Usage | `/observability?tab=inference` |
|
|
281
|
+
| Troubleshooting | `/observability?tab=troubleshooting` |
|
|
282
|
+
|
|
283
|
+
`↑`, `↓`, `home`, and `end` choose a link, `enter` or `y` copies it the same
|
|
284
|
+
way `/modelscout` copies (see [Copying](#copying)), and `backspace` or `l`
|
|
285
|
+
returns. After a failure the matching link is selected first: API Keys for
|
|
286
|
+
401 and 403, Budgets for 402, and Troubleshooting for the rest. Budgets may
|
|
287
|
+
need an admin role in Actualyze. The plugin cannot open a web browser, so
|
|
288
|
+
copy the link and paste it into one. When `settings.baseURL` is not an http
|
|
289
|
+
or https URL, there are no links, and the header says so.
|
|
55
290
|
|
|
56
|
-
|
|
291
|
+
## Other OpenAI-Compatible Servers
|
|
292
|
+
|
|
293
|
+
Besides Actualyze, the plugin discovers the models of any OpenAI-compatible
|
|
294
|
+
server you configure as a provider and fills in their catalog entries.
|
|
295
|
+
|
|
296
|
+
### Quick start with another server
|
|
297
|
+
|
|
298
|
+
1. Install the plugin as in the [Quick Start](#quick-start).
|
|
57
299
|
|
|
58
300
|
2. Add a provider with `settings.probe` to `~/.config/opencode/opencode.json`:
|
|
59
301
|
|
|
@@ -77,7 +319,7 @@ has your API key.
|
|
|
77
319
|
usually within a few seconds and without a restart. Run `/modelscout` to
|
|
78
320
|
see what was found and where each value came from.
|
|
79
321
|
|
|
80
|
-
|
|
322
|
+
### The problem it solves
|
|
81
323
|
|
|
82
324
|
An OpenAI-compatible `/v1/models` endpoint reports model IDs and little else.
|
|
83
325
|
OpenCode sees `qwen3:30b-a3b` or `gemma3-12b-it` and has no idea whether the
|
|
@@ -86,17 +328,17 @@ is. Without that, OpenCode falls back to generic defaults, and the model
|
|
|
86
328
|
picker never shows models you did not type into your config by hand.
|
|
87
329
|
|
|
88
330
|
Most inference servers do publish this metadata, each through its own API.
|
|
89
|
-
|
|
331
|
+
The plugin asks those APIs, fills the remaining gaps from the
|
|
90
332
|
[models.dev](https://models.dev) data OpenCode already has, and adds every
|
|
91
333
|
served model to the catalog.
|
|
92
334
|
|
|
93
|
-
|
|
335
|
+
### How discovery works
|
|
94
336
|
|
|
95
337
|
The plugin has two halves. The server half runs inside OpenCode's background
|
|
96
338
|
service and does the discovery. The TUI half adds two commands:
|
|
97
|
-
[`/
|
|
98
|
-
and [`/
|
|
99
|
-
|
|
339
|
+
[`/actualyze`](#actualyze-command), which connects an Actualyze key and
|
|
340
|
+
explains the state of its catalog, and [`/modelscout`](#modelscout-command),
|
|
341
|
+
a browser of every discovered model.
|
|
100
342
|
|
|
101
343
|
For each provider it targets (see
|
|
102
344
|
[Which providers are discovered](#which-providers-are-discovered)), the server
|
|
@@ -122,79 +364,9 @@ Discovery never runs during plugin setup, so it does not slow OpenCode's
|
|
|
122
364
|
startup. Inventories stored by an earlier run are served right away, before
|
|
123
365
|
any network request.
|
|
124
366
|
|
|
125
|
-
|
|
367
|
+
### Configuration
|
|
126
368
|
|
|
127
|
-
|
|
128
|
-
opencode plugin add opencode-actualyze
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
This installs the package and adds it to your global OpenCode configuration.
|
|
132
|
-
`opencode plugin remove opencode-actualyze` takes it out again.
|
|
133
|
-
|
|
134
|
-
To configure it by hand, list it in the `plugins` array of `opencode.json`:
|
|
135
|
-
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"plugins": ["opencode-actualyze"]
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
To pass [plugin options](#plugin-options), use the object form:
|
|
143
|
-
|
|
144
|
-
```json
|
|
145
|
-
{
|
|
146
|
-
"plugins": [
|
|
147
|
-
{
|
|
148
|
-
"package": "opencode-actualyze",
|
|
149
|
-
"options": { "refreshIntervalMs": 1800000 }
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
The package contains a server plugin and a TUI plugin. OpenCode loads the TUI
|
|
156
|
-
half automatically together with the server half, so there is nothing else to
|
|
157
|
-
add for `/modelscout` and `/actualyze`.
|
|
158
|
-
|
|
159
|
-
### Running from a checkout
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
git clone https://github.com/actualyze-ai/opencode-actualyze.git
|
|
163
|
-
cd opencode-actualyze
|
|
164
|
-
npm install
|
|
165
|
-
npm run compile
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Then point `plugins` at the build output directory:
|
|
169
|
-
|
|
170
|
-
```json
|
|
171
|
-
{
|
|
172
|
-
"plugins": ["/absolute/path/to/opencode-actualyze/dist"]
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
OpenCode loads a local plugin directory by looking for `server.js` and
|
|
177
|
-
`tui.js` inside it, so the entry is `dist`, not the repository root.
|
|
178
|
-
|
|
179
|
-
### The background service and environment variables
|
|
180
|
-
|
|
181
|
-
OpenCode 2 runs plugins in one shared background service per user, not in the
|
|
182
|
-
terminal where you start `opencode`. Config substitutions such as
|
|
183
|
-
`{env:LOCAL_LLM_KEY}` therefore read the service's environment, and a variable
|
|
184
|
-
exported in your shell is not visible to them. Set it on the service and
|
|
185
|
-
restart it:
|
|
186
|
-
|
|
187
|
-
```bash
|
|
188
|
-
opencode service set env LOCAL_LLM_KEY <value>
|
|
189
|
-
opencode service restart
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Alternatively, read the key from a file with `{file:~/path/to/key}`. A
|
|
193
|
-
relative `{file:}` path resolves against the directory of the config file.
|
|
194
|
-
|
|
195
|
-
## Configuration
|
|
196
|
-
|
|
197
|
-
### Which providers are discovered
|
|
369
|
+
#### Which providers are discovered
|
|
198
370
|
|
|
199
371
|
A provider is a discovery target when it has `settings.baseURL` and one of
|
|
200
372
|
these holds:
|
|
@@ -203,23 +375,24 @@ these holds:
|
|
|
203
375
|
- **It is a plain provider from your config.** Its package is the
|
|
204
376
|
openai-compatible package, it has no `canonical`, and its ID is not one
|
|
205
377
|
OpenCode already knows from models.dev, from a built-in provider, or from a
|
|
206
|
-
plugin listed before
|
|
207
|
-
|
|
378
|
+
plugin listed before this one. Such a provider is discovered without a
|
|
379
|
+
probe: the plugin lists its models and fills metadata from models.dev and
|
|
380
|
+
heuristics.
|
|
208
381
|
|
|
209
382
|
Everything else needs `settings.probe`. That includes a provider whose ID
|
|
210
383
|
matches a models.dev provider (for example `deepseek` or `groq`) and an alias
|
|
211
|
-
of a catalog provider set up with `canonical`.
|
|
212
|
-
default so it never floods the picker with every ID a hosted API lists.
|
|
384
|
+
of a catalog provider set up with `canonical`. The plugin leaves those alone
|
|
385
|
+
by default so it never floods the picker with every ID a hosted API lists.
|
|
213
386
|
|
|
214
387
|
#### Built-in local providers
|
|
215
388
|
|
|
216
|
-
|
|
389
|
+
The plugin never probes the provider IDs `ollama`, `lmstudio`, `vllm`, and
|
|
217
390
|
`opencode`, even with `settings.probe` set. OpenCode 2 has its own discovery
|
|
218
391
|
for Ollama, LM Studio, and vLLM on their default local ports under those IDs,
|
|
219
392
|
and the built-in `opencode` provider hides paid models on purpose when you
|
|
220
393
|
have no key.
|
|
221
394
|
|
|
222
|
-
To get
|
|
395
|
+
To get the plugin's probes for a local server, configure it under your own
|
|
223
396
|
provider ID, such as `my-ollama`. If that provider points at the same port as
|
|
224
397
|
a built-in one, its models are listed twice, once per provider. Disable the
|
|
225
398
|
built-in provider plugin to avoid that:
|
|
@@ -233,30 +406,30 @@ built-in provider plugin to avoid that:
|
|
|
233
406
|
The other built-ins are `-opencode.provider.lmstudio` and
|
|
234
407
|
`-opencode.provider.vllm`.
|
|
235
408
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
| Field | Description
|
|
239
|
-
| ------------------ |
|
|
240
|
-
| `package` | `@opencode/ai/providers/openai-compatible`.
|
|
241
|
-
| `settings.baseURL` |
|
|
242
|
-
| `settings.apiKey` | Sent as `Authorization: Bearer <key>` on discovery requests when the provider has no connected key. A key connected in OpenCode (stored or from the environment) takes precedence, as it does for chat.
|
|
243
|
-
| `settings.probe` | `auto` or a probe ID from the table below.
|
|
244
|
-
| `headers` | Sent with every discovery and probe request. An `Authorization` header here replaces the one built from the API key.
|
|
245
|
-
|
|
246
|
-
| `settings.probe` | Effect
|
|
247
|
-
| ---------------- |
|
|
248
|
-
| `auto` | Fingerprint the server and run the matching probe. If nothing matches, models are still listed.
|
|
249
|
-
| `actualyze` | Actualyze probe.
|
|
250
|
-
| `ollama` | Ollama probe; also the right choice for llama.cpp and LocalAI.
|
|
251
|
-
| `omlx` | oMLX probe.
|
|
252
|
-
| `vllm` | vLLM probe.
|
|
253
|
-
| `tgi` | Text Generation Inference probe.
|
|
254
|
-
| `sglang` | SGLang probe.
|
|
255
|
-
| `lmstudio` | LM Studio probe.
|
|
256
|
-
| `koboldcpp` | KoboldCpp probe.
|
|
257
|
-
| anything else | Opts the provider in, but no probe runs. `/modelscout`
|
|
258
|
-
|
|
259
|
-
|
|
409
|
+
#### Provider settings
|
|
410
|
+
|
|
411
|
+
| Field | Description |
|
|
412
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
413
|
+
| `package` | `@opencode/ai/providers/openai-compatible`. The plugin also accepts `aisdk:@ai-sdk/openai-compatible` and `@ai-sdk/openai-compatible`. The package matters for auto-eligibility and for reasoning-effort variants. |
|
|
414
|
+
| `settings.baseURL` | The OpenAI-compatible API root OpenCode sends chat requests to, usually ending in `/v1`. Required. Discovery finds the model list with or without the trailing `/v1`. |
|
|
415
|
+
| `settings.apiKey` | Sent as `Authorization: Bearer <key>` on discovery requests when the provider has no connected key. A key connected in OpenCode (stored or from the environment) takes precedence, as it does for chat. |
|
|
416
|
+
| `settings.probe` | `auto` or a probe ID from the table below. |
|
|
417
|
+
| `headers` | Sent with every discovery and probe request. An `Authorization` header here replaces the one built from the API key. |
|
|
418
|
+
|
|
419
|
+
| `settings.probe` | Effect |
|
|
420
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
421
|
+
| `auto` | Fingerprint the server and run the matching probe. If nothing matches, models are still listed. |
|
|
422
|
+
| `actualyze` | Actualyze probe. |
|
|
423
|
+
| `ollama` | Ollama probe; also the right choice for llama.cpp and LocalAI. |
|
|
424
|
+
| `omlx` | oMLX probe. |
|
|
425
|
+
| `vllm` | vLLM probe. |
|
|
426
|
+
| `tgi` | Text Generation Inference probe. |
|
|
427
|
+
| `sglang` | SGLang probe. |
|
|
428
|
+
| `lmstudio` | LM Studio probe. |
|
|
429
|
+
| `koboldcpp` | KoboldCpp probe. |
|
|
430
|
+
| anything else | Opts the provider in, but no probe runs. `/modelscout` and `/actualyze` flag the value as an unknown probe and list the accepted ones. |
|
|
431
|
+
|
|
432
|
+
#### Examples
|
|
260
433
|
|
|
261
434
|
Several local servers next to each other:
|
|
262
435
|
|
|
@@ -264,7 +437,7 @@ Several local servers next to each other:
|
|
|
264
437
|
{
|
|
265
438
|
"providers": {
|
|
266
439
|
"studio-omlx": {
|
|
267
|
-
"name": "oMLX",
|
|
440
|
+
"name": "Studio oMLX",
|
|
268
441
|
"package": "@opencode/ai/providers/openai-compatible",
|
|
269
442
|
"settings": {
|
|
270
443
|
"baseURL": "http://localhost:8000/v1",
|
|
@@ -273,7 +446,7 @@ Several local servers next to each other:
|
|
|
273
446
|
}
|
|
274
447
|
},
|
|
275
448
|
"my-ollama": {
|
|
276
|
-
"name": "Ollama
|
|
449
|
+
"name": "GPU box Ollama",
|
|
277
450
|
"package": "@opencode/ai/providers/openai-compatible",
|
|
278
451
|
"settings": {
|
|
279
452
|
"baseURL": "http://gpu-box.local:11434/v1",
|
|
@@ -300,6 +473,7 @@ A gateway that needs an extra header:
|
|
|
300
473
|
{
|
|
301
474
|
"providers": {
|
|
302
475
|
"team-gateway": {
|
|
476
|
+
"name": "Team gateway",
|
|
303
477
|
"package": "@opencode/ai/providers/openai-compatible",
|
|
304
478
|
"headers": { "X-Team": "research" },
|
|
305
479
|
"settings": {
|
|
@@ -312,46 +486,35 @@ A gateway that needs an extra header:
|
|
|
312
486
|
}
|
|
313
487
|
```
|
|
314
488
|
|
|
315
|
-
###
|
|
489
|
+
### What the plugin sets on each model
|
|
316
490
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
| Option | Description | Default |
|
|
320
|
-
| ------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
321
|
-
| `timeoutMs` | Time budget for one provider's discovery: model list, fingerprinting, and probe together. | `15000`. Values are clamped to 1000 through 60000. |
|
|
322
|
-
| `refreshIntervalMs` | How often each provider is rediscovered in the background. `0` or a negative value turns periodic refresh off. | `600000` (10 minutes). Positive values are clamped to 60000 through 86400000. |
|
|
323
|
-
|
|
324
|
-
Values that are not numbers are ignored and the default applies.
|
|
325
|
-
|
|
326
|
-
## What Scout Sets on Each Model
|
|
491
|
+
The plugin adds the models a server lists that are not already declared for
|
|
492
|
+
that provider. For each one it writes:
|
|
327
493
|
|
|
328
|
-
|
|
329
|
-
|
|
494
|
+
| Field | Value |
|
|
495
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
496
|
+
| `name` | A readable name derived from the model ID. |
|
|
497
|
+
| `family` | From the probe, otherwise from a models.dev match. |
|
|
498
|
+
| `limit.context` | From the probe, otherwise OpenCode's default of 200000. |
|
|
499
|
+
| `limit.output` | From the probe, capped at the context window when the probe reports one too. When no source reports it, `0`: OpenCode treats that as unknown and asks for up to 32,000 output tokens, fewer when the prompt leaves less room in the window. |
|
|
500
|
+
| `capabilities.tools` | From the probe, including an explicit `false`; otherwise from models.dev; otherwise `true`. |
|
|
501
|
+
| `capabilities.input` | `text`, plus `image`, `pdf`, `audio`, and `video` where the probe or models.dev reports them. A model with unknown image support stays text-only. |
|
|
502
|
+
| `capabilities.output` | `["text"]`. |
|
|
503
|
+
| `variants` | `low`, `medium`, and `high`, each setting `reasoningEffort`, for reasoning models on the openai-compatible package. Reasoning comes from the probe or from a models.dev match that has effort variants. Actualyze models get none. |
|
|
504
|
+
| `cost` | Prices the probe reports, in USD per million tokens. A missing cache price becomes `0`. Without reported prices, `cost` is empty. |
|
|
505
|
+
| `time.released` | The Actualyze `created` time; `0` for other servers. |
|
|
506
|
+
| `enabled` | `false` for embedding models, which keeps them out of the picker. `/modelscout` lists them when its type filter includes embeddings. |
|
|
330
507
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
| `limit.context` | From the probe, otherwise OpenCode's default of 200000. |
|
|
336
|
-
| `limit.output` | From the probe, capped at the context limit. When no source reports it, `0`, which OpenCode reads as "unknown" and sizes the output budget to the room the prompt leaves in the context window. |
|
|
337
|
-
| `capabilities.tools` | From the probe, including an explicit `false`; otherwise from models.dev; otherwise `true`. |
|
|
338
|
-
| `capabilities.input` | `text`, plus `image`, `pdf`, `audio`, and `video` where the probe or models.dev reports them. A model with unknown image support stays text-only. |
|
|
339
|
-
| `capabilities.output` | `["text"]`. |
|
|
340
|
-
| `variants` | `low`, `medium`, and `high`, each setting `reasoningEffort`, for reasoning models on the openai-compatible package. Reasoning comes from the probe or from a models.dev match that has effort variants. Actualyze models get none. |
|
|
341
|
-
| `cost` | Prices the probe reports, in USD per million tokens. A missing cache price becomes `0`. Without reported prices, `cost` is empty. |
|
|
342
|
-
| `time.released` | The Actualyze `created` time; `0` for other servers. |
|
|
343
|
-
| `enabled` | `false` for embedding models, which keeps them out of the picker. `/modelscout` lists them when its type filter includes embeddings. |
|
|
508
|
+
A model counts as an embedding model when the probe says so, or, when the
|
|
509
|
+
probe reports no model type, when its ID contains `embed`. The plugin does
|
|
510
|
+
not set parameter size, quantization, file size, or temperature support on
|
|
511
|
+
the model; `/modelscout` shows them in its details.
|
|
344
512
|
|
|
345
|
-
|
|
346
|
-
data, when its ID contains `embed`. Scout does not set parameter size,
|
|
347
|
-
quantization, file size, or temperature support on the model;
|
|
348
|
-
`/modelscout` shows them in its details.
|
|
349
|
-
|
|
350
|
-
### Declared models are never modified
|
|
513
|
+
#### Declared models are never modified
|
|
351
514
|
|
|
352
515
|
A model ID that already exists for the provider, because you declared it in
|
|
353
516
|
config or because it comes from the provider's models.dev entry, is left
|
|
354
|
-
exactly as it is.
|
|
517
|
+
exactly as it is. The plugin adds the other served models around it.
|
|
355
518
|
|
|
356
519
|
```json
|
|
357
520
|
{
|
|
@@ -377,7 +540,7 @@ Here `qwen3:30b` keeps your name and limits, and every other model the server
|
|
|
377
540
|
serves is added with discovered metadata. In `/modelscout`, the Evidence
|
|
378
541
|
screen for `qwen3:30b` gives its origin as declared in your config.
|
|
379
542
|
|
|
380
|
-
|
|
543
|
+
### Supported servers
|
|
381
544
|
|
|
382
545
|
| Server | Probe | Status | What it reports |
|
|
383
546
|
| ------------- | ----------- | -------- | --------------------------------------------------------------------------------------- |
|
|
@@ -397,10 +560,10 @@ is API-compatible according to its source code but has not been run against a
|
|
|
397
560
|
live instance. An Untested probe was written from the server's API
|
|
398
561
|
documentation, and reports from people running those servers are welcome.
|
|
399
562
|
|
|
400
|
-
With `"probe": "auto"`,
|
|
563
|
+
With `"probe": "auto"`, the plugin identifies the server in this order:
|
|
401
564
|
|
|
402
|
-
1. Any model entry whose `owned_by` is exactly `actualyze`
|
|
403
|
-
|
|
565
|
+
1. Any model entry whose `owned_by` is exactly `actualyze` selects the
|
|
566
|
+
Actualyze probe.
|
|
404
567
|
2. Every entry reporting the same known owner selects that server: `omlx`,
|
|
405
568
|
`vllm`, `sglang`, `llamacpp`, `koboldcpp`, or `library` for Ollama.
|
|
406
569
|
3. Entries with `aliases`, `tags`, or `status` fields point to llama.cpp.
|
|
@@ -410,129 +573,44 @@ With `"probe": "auto"`, scout identifies the server in this order:
|
|
|
410
573
|
An Ollama server whose models do not all report the owner `library` is not
|
|
411
574
|
detected. Set `"probe": "ollama"` for it.
|
|
412
575
|
|
|
413
|
-
## Actualyze
|
|
414
|
-
|
|
415
|
-
Actualyze serves its model catalog through an OpenAI-compatible endpoint, and
|
|
416
|
-
each `/v1/models` entry carries the platform's full metadata.
|
|
417
|
-
|
|
418
|
-
### The built-in provider
|
|
419
|
-
|
|
420
|
-
Scout adds this provider to OpenCode's catalog:
|
|
421
|
-
|
|
422
|
-
| Field | Value |
|
|
423
|
-
| ------------------ | ------------------------------------------ |
|
|
424
|
-
| ID | `actualyze` |
|
|
425
|
-
| Name | Actualyze |
|
|
426
|
-
| `package` | `@opencode/ai/providers/openai-compatible` |
|
|
427
|
-
| `settings.baseURL` | `https://app.actualyze.ai/openai/v1` |
|
|
428
|
-
| `settings.probe` | `actualyze` |
|
|
429
|
-
|
|
430
|
-
It also registers an Actualyze integration, which is what `/connect` and
|
|
431
|
-
`opencode auth login actualyze` offer. The integration takes a stored API key
|
|
432
|
-
or the `ACTUALYZE_API_KEY` environment variable of the background service.
|
|
433
|
-
Discovery and chat both use that key. The integration's ID is `actualyze`,
|
|
434
|
-
the same as the provider's, so a `providers.actualyze` config entry and
|
|
435
|
-
`opencode auth login actualyze` both reach the integration the provider reads
|
|
436
|
-
its key from.
|
|
437
|
-
|
|
438
|
-
Until the integration has a key, OpenCode hides the provider, so installing
|
|
439
|
-
the plugin without Actualyze changes nothing in the model picker.
|
|
440
|
-
|
|
441
|
-
### Another Actualyze environment
|
|
442
|
-
|
|
443
|
-
To use a different deployment, set only its base URL. Your config is merged
|
|
444
|
-
over the built-in provider field by field, so the name, package, probe, and
|
|
445
|
-
key handling stay as they are:
|
|
446
|
-
|
|
447
|
-
```json
|
|
448
|
-
{
|
|
449
|
-
"providers": {
|
|
450
|
-
"actualyze": {
|
|
451
|
-
"settings": {
|
|
452
|
-
"baseURL": "https://actualyze.example.com/openai/v1"
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
Any `providers.actualyze` entry in your config makes OpenCode list the
|
|
460
|
-
provider even without a key. Discovery then runs without credentials, and
|
|
461
|
-
`/modelscout` and `/actualyze` show the endpoint's error until you add one.
|
|
462
|
-
Add the key with `/actualyze`, `/connect`, or `opencode auth login actualyze`
|
|
463
|
-
as usual: the entry does not create a second Actualyze integration. A `settings.apiKey` in the entry also
|
|
464
|
-
works, without connecting the integration. A connected key takes precedence
|
|
465
|
-
over `settings.apiKey` for both discovery and chat, so the two always use the
|
|
466
|
-
same key.
|
|
467
|
-
|
|
468
|
-
If a models.dev catalog or another plugin already defines an `actualyze`
|
|
469
|
-
provider, scout leaves that provider as it is and does not add its own. When
|
|
470
|
-
an `actualyze` integration also exists, as a catalog registers one with its
|
|
471
|
-
provider, scout does not register its own, so `/connect` lists Actualyze once.
|
|
472
|
-
Otherwise scout still registers the `actualyze` integration. A provider that
|
|
473
|
-
another plugin defined with `"activation": "auto"` and no integration of its
|
|
474
|
-
own then depends on that integration: OpenCode hides it until a key is
|
|
475
|
-
connected there. Scout does not discover such a provider by default, because
|
|
476
|
-
its ID is one OpenCode already knows; add `"probe": "actualyze"` to its
|
|
477
|
-
`settings` in your config to opt in.
|
|
478
|
-
|
|
479
|
-
### How the probe reads Actualyze
|
|
480
|
-
|
|
481
|
-
- **Detection.** In auto mode, one entry with `owned_by` set exactly to
|
|
482
|
-
`actualyze` or `atlas` is enough to select the probe, even in a catalog
|
|
483
|
-
that mixes owners. The probe then reads only the Actualyze-owned entries;
|
|
484
|
-
the rest are listed and enriched from models.dev as usual. With
|
|
485
|
-
`"probe": "actualyze"` every listed model is treated as an Actualyze model.
|
|
486
|
-
`"probe": "atlas"` still works as a deprecated alias.
|
|
487
|
-
- **List first.** The probe reads metadata straight from the `/v1/models`
|
|
488
|
-
entries. It requests `GET /v1/models/{id}` only for owned entries that lack
|
|
489
|
-
the full metadata, which happens on older deployments.
|
|
490
|
-
- **Fields.** `context_window` and `max_output_tokens` become the limits.
|
|
491
|
-
Capability flags (`vision`, `tool_use`, `thinking`, `thinking_adaptive`,
|
|
492
|
-
`temperature`, `document`, `audio`, `video`) are three-valued: `true` and
|
|
493
|
-
`false` are definitive, `null` means unknown. `modalities.input` is used
|
|
494
|
-
for input modalities when present. `created` becomes the release time.
|
|
495
|
-
- **Cost.** `cost.input`, `cost.output`, `cost.cache_read`, and
|
|
496
|
-
`cost.cache_write` are USD per million tokens. OpenCode's `cost` records a
|
|
497
|
-
missing cache price as `0`, and `/modelscout` shows it as unknown. A model
|
|
498
|
-
without `cost` gets no prices.
|
|
499
|
-
- **No effort variants.** Actualyze's chat endpoint does not pass
|
|
500
|
-
`reasoning_effort` on to the upstream model, so reasoning models from
|
|
501
|
-
Actualyze get no `low`/`medium`/`high` variants.
|
|
502
|
-
|
|
503
576
|
## `/modelscout` Command
|
|
504
577
|
|
|
505
578
|
Type `/modelscout`, or pick **Model Scout** from the command palette. It opens
|
|
506
|
-
a browser of the models
|
|
507
|
-
a model. The dialog appears at once and fills in when OpenCode's
|
|
508
|
-
and
|
|
509
|
-
run starts or settles and when OpenCode's model catalog
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
579
|
+
a browser of the models the plugin's providers serve, without sending
|
|
580
|
+
anything to a model. The dialog appears at once and fills in when OpenCode's
|
|
581
|
+
model lists and the plugin's discovery catalog arrive. It updates in place
|
|
582
|
+
when a discovery run starts or settles and when OpenCode's model catalog
|
|
583
|
+
changes.
|
|
584
|
+
|
|
585
|
+
The list covers every provider the plugin discovers, plus any OpenCode
|
|
586
|
+
provider that looks like a discovery target: one with `settings.baseURL` and
|
|
587
|
+
either `settings.probe` or the openai-compatible package. Providers are
|
|
588
|
+
sorted by name, and models within each provider by name until you change the
|
|
589
|
+
sort.
|
|
515
590
|
|
|
516
591
|
### Reading the list
|
|
517
592
|
|
|
518
593
|
```
|
|
519
|
-
▾ Actualyze
|
|
520
|
-
Claude Haiku 4.5 200K T I R
|
|
521
|
-
● Claude Sonnet 4.5 200K T I R
|
|
522
|
-
GPT
|
|
523
|
-
|
|
524
|
-
▾ Studio oMLX
|
|
594
|
+
▾ Actualyze 4 models ● ready
|
|
595
|
+
Claude Haiku 4.5 200K T I R $1/$5
|
|
596
|
+
● Claude Sonnet 4.5 200K T I R $3/$15
|
|
597
|
+
GPT 5 400K T I R $1.25/$10.00
|
|
598
|
+
GPT OSS 120B 131K T · R $0.15/$0.60
|
|
599
|
+
▾ Studio oMLX 2 models ● ready
|
|
525
600
|
Gemma 3 12B ~200K · I ·
|
|
526
601
|
Qwen3 Coder 30B 262K t · ·
|
|
527
|
-
▸ Team gateway
|
|
602
|
+
▸ Team gateway 3 models ▲ key rejected
|
|
528
603
|
```
|
|
529
604
|
|
|
530
605
|
- **Provider headers** show the model count, as `visible/total` while search
|
|
531
606
|
or filters hide some, and the discovery status: `● ready`, `○ checking`
|
|
532
|
-
while discovery runs, `○ resolving` while
|
|
533
|
-
`○ waiting` until discovery has a result for the current key, or a
|
|
534
|
-
such as `▲ key rejected`, `▲ rate limited`, or `▲ unreachable`. A
|
|
535
|
-
provider keeps the models from its last good discovery.
|
|
607
|
+
while discovery runs, `○ resolving` while the plugin looks up which key to
|
|
608
|
+
use, `○ waiting` until discovery has a result for the current key, or a
|
|
609
|
+
failure such as `▲ key rejected`, `▲ rate limited`, or `▲ unreachable`. A
|
|
610
|
+
failing provider keeps the models from its last good discovery.
|
|
611
|
+
`▲ unknown probe` means `settings.probe` names no probe: the models are
|
|
612
|
+
listed, but no probe fills in their limits, prices, or capabilities. A
|
|
613
|
+
failure shows in its place until it clears.
|
|
536
614
|
- **`●`** before a model name marks the model the prompt uses now. A colored
|
|
537
615
|
band marks the selected row; while the search box has focus, a `▌` marks
|
|
538
616
|
it instead.
|
|
@@ -540,15 +618,18 @@ name, and models within each provider by name until you change the sort.
|
|
|
540
618
|
reported one and OpenCode uses its default of 200,000 tokens.
|
|
541
619
|
- **`T I R`** stand for tool calls, image input, and reasoning. An uppercase
|
|
542
620
|
letter is reported by the server, your config, or OpenCode. A lowercase
|
|
543
|
-
letter is assumed from an OpenCode default or inferred from models.dev
|
|
544
|
-
|
|
621
|
+
letter is assumed from an OpenCode default or inferred from a models.dev
|
|
622
|
+
match. `·` means not reported or not supported.
|
|
545
623
|
- **Prices** are USD per million tokens, input/output, and `?` marks an
|
|
546
624
|
unknown side. When one side shows cents, so does the other. A trailing `+`
|
|
547
625
|
means the price rises above a context size; the details list every tier.
|
|
626
|
+
Only models declared with tiered prices in your config or a models.dev
|
|
627
|
+
entry have tiers.
|
|
548
628
|
|
|
549
629
|
The title line counts providers and models and says how many providers need
|
|
550
|
-
attention
|
|
551
|
-
how many, for example
|
|
630
|
+
attention: a failed discovery or an unknown probe. Embedding models are
|
|
631
|
+
hidden by default, and the filter line says how many, for example
|
|
632
|
+
`1 embedding hidden`.
|
|
552
633
|
|
|
553
634
|
At 120 columns and wider, a preview of the selected row's details sits
|
|
554
635
|
beside the list. The preview does not scroll: when it is cut off, its last
|
|
@@ -557,9 +638,9 @@ selected model sits under the list instead (facts that do not fit are
|
|
|
557
638
|
counted as `+N`). At any width, `i` opens the details on their own screen,
|
|
558
639
|
across the whole dialog. Details and the key list that run longer than the
|
|
559
640
|
dialog scroll (the key list by whole entries), with `↑ N more` and
|
|
560
|
-
`↓ N more` at the edges. Resizing the terminal switches between the two
|
|
561
|
-
closing the dialog. The dialog takes at most `rows - 4`
|
|
562
|
-
room above and below it.
|
|
641
|
+
`↓ N more` at the edges. Resizing the terminal switches between the two
|
|
642
|
+
layouts without closing the dialog. The dialog takes at most `rows - 4`
|
|
643
|
+
rows, so it leaves room above and below it.
|
|
563
644
|
|
|
564
645
|
The first open selects the prompt's current model, or the first chat model
|
|
565
646
|
when the current one is not listed. Search, filters, sort, collapsed
|
|
@@ -595,8 +676,10 @@ While the search box has focus, every key you type goes into the search.
|
|
|
595
676
|
Keys held with `ctrl`, `alt`, or `cmd` always go to OpenCode.
|
|
596
677
|
|
|
597
678
|
The footer shows the keys of the current view and dims the ones that do not
|
|
598
|
-
apply to the selection.
|
|
599
|
-
|
|
679
|
+
apply to the selection. When the dialog is too narrow for every hint, the
|
|
680
|
+
footer leaves out the ones that do not fit and keeps the rest in their usual
|
|
681
|
+
order. `close esc` always stays, and `keys ?` stays except while you type a
|
|
682
|
+
search or read the key list.
|
|
600
683
|
|
|
601
684
|
### Search, filters, and sort
|
|
602
685
|
|
|
@@ -628,22 +711,25 @@ prices and every context tier), and the capabilities, grouped as supported,
|
|
|
628
711
|
assumed, inferred, not supported, and not reported. Then come the provider
|
|
629
712
|
and its endpoint, the family, parameter count, quantization, and size. A
|
|
630
713
|
value no source reported says so in words: "Not reported; OpenCode uses
|
|
631
|
-
200,000" for the context, and "Not reported; OpenCode
|
|
632
|
-
|
|
714
|
+
200,000" for the context, and "Not reported; OpenCode asks for up to 32,000,
|
|
715
|
+
fewer if the prompt leaves less room" for the output limit.
|
|
633
716
|
|
|
634
717
|
Provider details give the discovery status and when it was last checked,
|
|
635
|
-
and after a failure what went wrong and what to do about it.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
718
|
+
and after a failure what went wrong and what to do about it. For an unknown
|
|
719
|
+
probe they name the configured value and list the values `settings.probe`
|
|
720
|
+
accepts, for example
|
|
721
|
+
`Unknown probe "my-probe"; use auto or one of: actualyze, ollama, omlx, …`.
|
|
722
|
+
They also show the server type (the probe, or that it was detected
|
|
723
|
+
automatically), the number of chat and embedding models, how many models
|
|
724
|
+
your config declares and the plugin leaves unchanged, which key discovery
|
|
725
|
+
uses (a connected key, `settings.apiKey`, the provider's headers, or none),
|
|
726
|
+
and when `r` can run again.
|
|
641
727
|
|
|
642
728
|
### Evidence
|
|
643
729
|
|
|
644
730
|
`d` shows where each value comes from. For a model it is a table of every
|
|
645
731
|
field with its value and source, followed by the model's origin (discovered
|
|
646
|
-
by
|
|
732
|
+
by the plugin, declared in your config, or known to OpenCode only), the
|
|
647
733
|
configured and resolved probe, the endpoint origin, and any conflicts
|
|
648
734
|
between sources. For a provider it lists the model-list and probe attempts,
|
|
649
735
|
the probe, the endpoint, the key source, the last good and last attempted
|
|
@@ -657,7 +743,7 @@ status and retry time.
|
|
|
657
743
|
| `server list` | The server's model list |
|
|
658
744
|
| `models.dev` | A models.dev match |
|
|
659
745
|
| `heuristic` | Inferred from the model ID |
|
|
660
|
-
| `scout default` |
|
|
746
|
+
| `scout default` | The plugin's default, such as text input |
|
|
661
747
|
| `OpenCode default` | OpenCode's default value, not an observation |
|
|
662
748
|
| `OpenCode` | OpenCode's model list, for a provider without discovery |
|
|
663
749
|
|
|
@@ -666,17 +752,17 @@ Endpoint origins never include credentials, paths, or query strings.
|
|
|
666
752
|
### Choosing a model
|
|
667
753
|
|
|
668
754
|
`enter` on a model, or `m`, opens OpenCode's model picker in place of the
|
|
669
|
-
browser with its search filled in, so the model is the highlighted
|
|
670
|
-
result. Press `enter` again to select it; for a model with effort
|
|
671
|
-
OpenCode may then ask which one. The choice happens in the picker
|
|
672
|
-
plugins cannot set the prompt's model.
|
|
755
|
+
browser with its search filled in, so the model is usually the highlighted
|
|
756
|
+
first result. Press `enter` again to select it; for a model with effort
|
|
757
|
+
variants, OpenCode may then ask which one. The choice happens in the picker
|
|
758
|
+
because plugins cannot set the prompt's model.
|
|
673
759
|
|
|
674
760
|
The search is the provider's name and the model's name as the picker shows
|
|
675
761
|
them, for example `Actualyze GPT OSS 120B`. The picker matches provider names
|
|
676
762
|
only while at least one integration has a connection, so without one the
|
|
677
|
-
search is the model's name alone. If the picker's search field
|
|
678
|
-
|
|
679
|
-
|
|
763
|
+
search is the model's name alone. If the picker's search field does not
|
|
764
|
+
appear within a second, or you press a key before the plugin fills it in,
|
|
765
|
+
the picker stays open without a search, as it would from `/models`.
|
|
680
766
|
|
|
681
767
|
`enter` and `m` are unavailable for embedding models, for a model OpenCode
|
|
682
768
|
does not list yet, for a deprecated model, which the picker leaves out, and
|
|
@@ -700,15 +786,16 @@ The picker orders its results, so check the highlighted row before you press
|
|
|
700
786
|
|
|
701
787
|
`y` copies `provider/model`, the form `opencode run --model` takes, and `Y`
|
|
702
788
|
copies the raw model ID. The text goes to the terminal through the OSC 52
|
|
703
|
-
escape sequence, and the notice line says `Copy sent to terminal
|
|
704
|
-
do not confirm OSC 52, and some ignore it or need it turned on.
|
|
705
|
-
reports that the terminal does not support OSC 52, the browser
|
|
706
|
-
in full under the notice for 30 seconds instead, so you can
|
|
789
|
+
escape sequence, and the notice line says `Copy sent to terminal: <text>`.
|
|
790
|
+
Terminals do not confirm OSC 52, and some ignore it or need it turned on.
|
|
791
|
+
When OpenCode reports that the terminal does not support OSC 52, the browser
|
|
792
|
+
shows the text in full under the notice for 30 seconds instead, so you can
|
|
793
|
+
select it.
|
|
707
794
|
|
|
708
795
|
### Refreshing
|
|
709
796
|
|
|
710
|
-
`r` asks
|
|
711
|
-
every provider. Discovery for one provider and key starts at most once a
|
|
797
|
+
`r` asks the plugin's server half to rediscover the selected provider, and
|
|
798
|
+
`R` every provider. Discovery for one provider and key starts at most once a
|
|
712
799
|
minute, and never before a time the server asked for with `Retry-After` or
|
|
713
800
|
`X-RateLimit-Reset` (at most one hour ahead). A refresh inside that window
|
|
714
801
|
is skipped with a countdown, for example
|
|
@@ -717,9 +804,11 @@ the provider's details show the same wait.
|
|
|
717
804
|
|
|
718
805
|
### Other states
|
|
719
806
|
|
|
720
|
-
- **Loading.** The dialog
|
|
721
|
-
|
|
722
|
-
|
|
807
|
+
- **Loading.** The dialog reads
|
|
808
|
+
`○ Reading models from OpenCode and scout…`.
|
|
809
|
+
- **OpenCode's lists did not load.** The dialog reads
|
|
810
|
+
`▲ Could not load models from OpenCode.` with the error, and `r` reads the
|
|
811
|
+
lists again.
|
|
723
812
|
- **No providers.** A card explains how to connect Actualyze (`a`) or add
|
|
724
813
|
another OpenAI-compatible server.
|
|
725
814
|
- **No matches.** `x` clears search and filters, and `f` changes the
|
|
@@ -727,10 +816,10 @@ the provider's details show the same wait.
|
|
|
727
816
|
- **A provider without models.** A note under its header says whether
|
|
728
817
|
discovery is still checking, the model list failed, the server returned no
|
|
729
818
|
models (`r` refreshes), or only hidden embedding models matched.
|
|
730
|
-
- **
|
|
731
|
-
times out after 3 seconds, the browser shows OpenCode's own model list
|
|
819
|
+
- **The plugin's server half does not answer.** If the catalog request fails
|
|
820
|
+
or times out after 3 seconds, the browser shows OpenCode's own model list
|
|
732
821
|
with a notice such as
|
|
733
|
-
`▲ Discovery details unavailable: scout's server half did not answer.`
|
|
822
|
+
`▲ Discovery details unavailable: scout's server half did not answer. Showing OpenCode's model list.`
|
|
734
823
|
Discovery status, failure details, evidence sources, and refresh are
|
|
735
824
|
missing in that mode.
|
|
736
825
|
- **The server half fails to load.** OpenCode does not load the TUI half
|
|
@@ -738,151 +827,111 @@ the provider's details show the same wait.
|
|
|
738
827
|
- **The browser cannot be built.** The command shows a plain, scrollable list
|
|
739
828
|
of the same models and reports the error in a toast.
|
|
740
829
|
|
|
741
|
-
##
|
|
830
|
+
## Installation
|
|
742
831
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
832
|
+
```bash
|
|
833
|
+
opencode plugin add opencode-actualyze
|
|
834
|
+
```
|
|
746
835
|
|
|
747
|
-
|
|
748
|
-
`
|
|
749
|
-
`
|
|
750
|
-
a `custom endpoint` badge, and every app link uses that endpoint's origin.
|
|
751
|
-
The line under the header says where things stand, and names the key in
|
|
752
|
-
use: the connection's label in quotes, `ACTUALYZE_API_KEY` for the
|
|
753
|
-
environment variable, or `settings.apiKey`.
|
|
836
|
+
This installs the package and adds it to your global OpenCode configuration.
|
|
837
|
+
`opencode plugin update opencode-actualyze` updates it, and
|
|
838
|
+
`opencode plugin remove opencode-actualyze` takes it out again.
|
|
754
839
|
|
|
755
|
-
|
|
756
|
-
account: no identity, usage, spend, or budget. So `/actualyze` reports
|
|
757
|
-
"Catalog accessible" when the model list answered for the key, and never
|
|
758
|
-
claims that chat works. A read-only key, for example, lists models and is
|
|
759
|
-
refused on every chat request.
|
|
840
|
+
To configure it by hand, list it in the `plugins` array of `opencode.json`:
|
|
760
841
|
|
|
761
|
-
|
|
842
|
+
```json
|
|
843
|
+
{
|
|
844
|
+
"plugins": ["opencode-actualyze"]
|
|
845
|
+
}
|
|
846
|
+
```
|
|
762
847
|
|
|
763
|
-
|
|
764
|
-
| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
765
|
-
| `○ Not connected` | OpenCode has no Actualyze key. | Create a key in the app, then press `k` and paste it. The card lists the steps. |
|
|
766
|
-
| `○ Saving key…` | You submitted a key and OpenCode has not confirmed it yet. | Wait. Closing the dialog does not undo a completed save. |
|
|
767
|
-
| `▲ Save not confirmed` | Saving failed or took longer than 15 seconds. OpenCode may have stored the key anyway. | Check with `c` before trying again with `k`. |
|
|
768
|
-
| `○ Checking the current connection…` | The key is saved and scout has no result for it yet. After 20 seconds the line reads "Still checking the current connection…". | Wait. No inference request is sent. |
|
|
769
|
-
| `○ Checking the connection…` | A key is connected and scout is still resolving it. | Wait. |
|
|
770
|
-
| `○ Loading models…` | The first model list for this key is on its way. | Wait. |
|
|
771
|
-
| `● Catalog accessible · key "Work" · 11 models · checked 2 min ago` | The model list answered. The count is chat models, as in `/modelscout`; the filter row reports hidden embeddings. | Browse them; `enter` on a model opens the model picker with it highlighted. |
|
|
772
|
-
| `▲ No models for this key` | The catalog answered with an empty list: the key works, but its team has no model access yet. | Ask a workspace admin. `y` copies the Catalog link. |
|
|
773
|
-
| `▲ Key rejected (401)` | Actualyze answers this way for a revoked or expired key, a key without the inference scope, or a key from another Actualyze environment. | `k` for another key, `y` to copy the API Keys link, `c` for connections. |
|
|
774
|
-
| `▲ Access denied (403)` | Actualyze refused the model list request for this key. | Check the key's permissions and model access with your administrator, or use `k` for another key. |
|
|
775
|
-
| `▲ Budget or entitlement blocked (402)` | Actualyze did not allow the model list request. The key cannot read a balance or reset date. | `y` copies the Budgets link; that page may need an admin role. |
|
|
776
|
-
| `▲ Catalog rate limited (429)` | The model list is rate limited. This is a catalog limit, not an inference quota. The footer shows the wait: `retry (42 s) r`. | Retry with `r` once the wait ends; otherwise Model Scout checks again on its next scheduled refresh, or when settings or the key change. |
|
|
777
|
-
| `▲ Could not reach the endpoint` | The connection failed. The header shows the endpoint. | Check the network, VPN, proxy, and `providers.actualyze.settings.baseURL`, then retry with `r`. |
|
|
778
|
-
| `▲ Endpoint did not answer in time` | The model list request timed out. | Check the network or the endpoint, then retry with `r`. |
|
|
779
|
-
| `▲ Actualyze server error (503)` | Actualyze failed to list its models. | Retry with `r`. |
|
|
780
|
-
| `▲ No model list at this endpoint (404)` | The base URL points at the wrong path. | Make `settings.baseURL` end in `/openai/v1`. |
|
|
781
|
-
| `▲ Unexpected answer (…)` | Another HTTP status, or an answer that is not a model list. | Check `settings.baseURL`. |
|
|
782
|
-
| `▲ Discovery was interrupted` or `▲ Discovery failed` | The check did not finish. | It runs again on the next refresh; `r` retries now. |
|
|
783
|
-
| `▲ Discovery status unavailable` | Scout's server half did not answer, so only the connection OpenCode reports is known. | `k` and `c` still work; `r` reads the catalog again. |
|
|
784
|
-
| `○ Not managed by Model Scout` | Another plugin or a models.dev catalog defines the `actualyze` provider, so scout does not discover it. | Add `"probe": "actualyze"` to `providers.actualyze.settings` to opt in. |
|
|
848
|
+
To pass [plugin options](#plugin-options), use the object form:
|
|
785
849
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
850
|
+
```json
|
|
851
|
+
{
|
|
852
|
+
"plugins": [
|
|
853
|
+
{
|
|
854
|
+
"package": "opencode-actualyze",
|
|
855
|
+
"options": { "refreshIntervalMs": 1800000 }
|
|
856
|
+
}
|
|
857
|
+
]
|
|
858
|
+
}
|
|
859
|
+
```
|
|
790
860
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
that a key connected with `k` takes precedence. When the provider's `headers` carry
|
|
795
|
-
the key (`Authorization` or `X-Actualyze-Api-Key`), a notice says that
|
|
796
|
-
discovery uses those headers, not the connected key.
|
|
861
|
+
The package contains a server plugin and a TUI plugin. OpenCode loads the TUI
|
|
862
|
+
half automatically together with the server half, so there is nothing else to
|
|
863
|
+
add for `/actualyze` and `/modelscout`.
|
|
797
864
|
|
|
798
|
-
###
|
|
865
|
+
### Plugin options
|
|
799
866
|
|
|
800
|
-
|
|
801
|
-
| ----- | ----------------------------------------------------------------------------------- |
|
|
802
|
-
| `k` | Connect a key: "connect key" without a connection, "another key" with one |
|
|
803
|
-
| `c` | Open OpenCode's connections; pick Actualyze there to switch, rename, or remove keys |
|
|
804
|
-
| `l` | Open the [links screen](#links) |
|
|
805
|
-
| `y` | On a card, copy the link it names; in the model list, copy `provider/model` |
|
|
806
|
-
| `r` | Check the catalog again; during a wait the hint is dimmed and reads "retry (N s)" |
|
|
807
|
-
| `b` | Open `/modelscout` |
|
|
808
|
-
| `?` | List the keys |
|
|
809
|
-
| `esc` | Close |
|
|
867
|
+
Pass these through the object form of the `plugins` entry.
|
|
810
868
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
does; the card then lists the left-out keys in an action line at its end, in
|
|
816
|
-
the same order, so every key shows once. `?` lists them all. A card longer
|
|
817
|
-
than the dialog shows `↓ N more` and scrolls with `↑`, `↓`, `pgup`, `pgdn`,
|
|
818
|
-
`home`, and `end`; the footer adds `scroll ↑↓` after the card's keys when
|
|
819
|
-
there is room for all of them.
|
|
869
|
+
| Option | Description | Default |
|
|
870
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
871
|
+
| `timeoutMs` | Time budget for one provider's discovery: model list, fingerprinting, and probe together. | `15000`. Values are clamped to 1000 through 60000. |
|
|
872
|
+
| `refreshIntervalMs` | How often each provider is rediscovered in the background. `0` or a negative value turns periodic refresh off. | `600000` (10 minutes). Positive values are clamped to 60000 through 86400000. |
|
|
820
873
|
|
|
821
|
-
|
|
822
|
-
limited to Actualyze, without a provider header or provider filter. `r`
|
|
823
|
-
refreshes Actualyze; there is no `R`. The footer shows `k` and `l` when
|
|
824
|
-
there is room, and `?` lists `k`, `l`, `c`, and `b`.
|
|
874
|
+
Values that are not numbers are ignored and the default applies.
|
|
825
875
|
|
|
826
|
-
|
|
827
|
-
integration and that integration offers a plain key method. Otherwise the
|
|
828
|
-
card points to `c`. Model Scout never deletes a key; removing one happens in
|
|
829
|
-
OpenCode's connections.
|
|
876
|
+
### Running from a checkout
|
|
830
877
|
|
|
831
|
-
|
|
878
|
+
Building needs Node.js 22.18 or a later 22.x release, or Node.js 24 or later.
|
|
832
879
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
880
|
+
```bash
|
|
881
|
+
git clone https://github.com/actualyze-ai/opencode-actualyze.git
|
|
882
|
+
cd opencode-actualyze
|
|
883
|
+
npm install
|
|
884
|
+
npm run compile
|
|
885
|
+
```
|
|
839
886
|
|
|
840
|
-
|
|
841
|
-
empty prompt returns to `/actualyze` unchanged. If Model Scout reloads while
|
|
842
|
-
the prompt is open, the prompt closes and nothing is saved; enter the key
|
|
843
|
-
again with `/actualyze`. A key submitted after Model Scout reloaded, or after
|
|
844
|
-
the project changed, is not saved either, and a toast says so. If you close
|
|
845
|
-
`/actualyze` while OpenCode is still saving and the save is never confirmed,
|
|
846
|
-
a toast says "OpenCode did not confirm the Actualyze key was saved".
|
|
887
|
+
Then point `plugins` at the build output directory:
|
|
847
888
|
|
|
848
|
-
|
|
889
|
+
```json
|
|
890
|
+
{
|
|
891
|
+
"plugins": ["/absolute/path/to/opencode-actualyze/dist"]
|
|
892
|
+
}
|
|
893
|
+
```
|
|
849
894
|
|
|
850
|
-
|
|
895
|
+
OpenCode loads a local plugin directory by looking for `server.js` and
|
|
896
|
+
`tui.js` inside it, so the entry is `dist`, not the repository root.
|
|
851
897
|
|
|
852
|
-
|
|
853
|
-
| --------------- | ------------------------------------ |
|
|
854
|
-
| API Keys | `/account/settings?tab=security` |
|
|
855
|
-
| Catalog | `/control/catalog?tab=consume` |
|
|
856
|
-
| Budgets | `/management/budgets` |
|
|
857
|
-
| Usage | `/observability?tab=inference` |
|
|
858
|
-
| Troubleshooting | `/observability?tab=troubleshooting` |
|
|
898
|
+
### The background service and environment variables
|
|
859
899
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
900
|
+
OpenCode 2 runs plugins in one shared background service per user, not in the
|
|
901
|
+
terminal where you start `opencode`. Config substitutions such as
|
|
902
|
+
`{env:LOCAL_LLM_KEY}` therefore read the service's environment, and a variable
|
|
903
|
+
exported in your shell is not visible to them. Set it on the service and
|
|
904
|
+
restart it:
|
|
905
|
+
|
|
906
|
+
```bash
|
|
907
|
+
opencode service set env LOCAL_LLM_KEY <value>
|
|
908
|
+
opencode service restart
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
Alternatively, read the key from a file with `{file:~/path/to/key}`. A
|
|
912
|
+
relative `{file:}` path resolves against the directory of the config file.
|
|
867
913
|
|
|
868
914
|
## Caching and Refresh
|
|
869
915
|
|
|
870
916
|
- **Stored inventories.** Each successful discovery is saved in OpenCode's
|
|
871
917
|
plugin storage, keyed by a hash of the provider ID, normalized base URL,
|
|
872
918
|
probe selection, API key, and headers. Unless discovery used
|
|
873
|
-
`settings.apiKey`, the key also covers the connected key
|
|
874
|
-
its absence. The stored data holds model IDs and metadata, never keys
|
|
875
|
-
headers.
|
|
876
|
-
- **Startup.** A provider gets its stored models once
|
|
877
|
-
the key that project uses (the connected key, else `settings.apiKey`)
|
|
878
|
-
found the inventory discovered with it. That lookup runs right after
|
|
879
|
-
plugin loads and makes no network request.
|
|
880
|
-
- **Background refresh.**
|
|
881
|
-
configuration, providers, plugins, integrations, or credentials
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
919
|
+
`settings.apiKey`, the key also covers the connected key the plugin used,
|
|
920
|
+
or its absence. The stored data holds model IDs and metadata, never keys
|
|
921
|
+
or headers. The plugin keeps the 128 most recent entries.
|
|
922
|
+
- **Startup.** A provider gets its stored models once the plugin has looked
|
|
923
|
+
up the key that project uses (the connected key, else `settings.apiKey`)
|
|
924
|
+
and found the inventory discovered with it. That lookup runs right after
|
|
925
|
+
the plugin loads and makes no network request.
|
|
926
|
+
- **Background refresh.** The plugin checks its providers when it loads;
|
|
927
|
+
when configuration, providers, plugins, integrations, or credentials
|
|
928
|
+
change; and every `refreshIntervalMs`. A check starts discovery only for a
|
|
929
|
+
provider that has no inventory for its current endpoint and key, or, with
|
|
930
|
+
periodic refresh on, whose inventory is about `refreshIntervalMs` old. `r`
|
|
931
|
+
or `R` in `/modelscout` and `r` in `/actualyze` start discovery at once.
|
|
932
|
+
Discovery for one provider and credential starts at most once a minute.
|
|
933
|
+
Projects open at the same time share one discovery run per identical
|
|
934
|
+
provider and credential.
|
|
886
935
|
- **Retry times.** When the model list answers 429 or 503 with
|
|
887
936
|
`Retry-After`, or 429 with `X-RateLimit-Reset`, no discovery with that
|
|
888
937
|
credential starts before that time, at most one hour ahead. Another key
|
|
@@ -894,9 +943,9 @@ https URL, there are no links, and the header says so.
|
|
|
894
943
|
removes that provider's discovered models until rediscovery finishes.
|
|
895
944
|
- **Account switches.** When the active account for a provider changes, for
|
|
896
945
|
example with `opencode auth switch`, its discovered models are removed at
|
|
897
|
-
once and replaced by the inventory for the new credential, which
|
|
898
|
-
discovers unless it already holds a fresh one. Models from one
|
|
899
|
-
never show under another.
|
|
946
|
+
once and replaced by the inventory for the new credential, which the
|
|
947
|
+
plugin discovers unless it already holds a fresh one. Models from one
|
|
948
|
+
account never show under another.
|
|
900
949
|
|
|
901
950
|
## Troubleshooting
|
|
902
951
|
|
|
@@ -913,81 +962,53 @@ https URL, there are no links, and the header says so.
|
|
|
913
962
|
`"probe": "auto"` to its `settings` is the reliable opt-in, except for the
|
|
914
963
|
IDs `ollama`, `lmstudio`, `vllm`, and `opencode`, which are never probed.
|
|
915
964
|
- **The API key is empty.** `{env:...}` resolves in the background service.
|
|
916
|
-
Set the variable with `opencode service set env` and restart the service,
|
|
917
|
-
use `{file:...}`.
|
|
918
|
-
- **Models are listed twice.** A
|
|
919
|
-
point at the same server. Disable the built-in one with
|
|
965
|
+
Set the variable with `opencode service set env` and restart the service,
|
|
966
|
+
or use `{file:...}`.
|
|
967
|
+
- **Models are listed twice.** A provider the plugin discovers and a built-in
|
|
968
|
+
local provider point at the same server. Disable the built-in one with
|
|
920
969
|
`-opencode.provider.<name>` in `plugins`.
|
|
921
970
|
- **The output limit is 0.** No source reported one. OpenCode treats `0` as
|
|
922
|
-
unknown and
|
|
971
|
+
unknown and asks for up to 32,000 output tokens, fewer when the prompt
|
|
972
|
+
leaves less room.
|
|
923
973
|
|
|
924
974
|
## Moving from opencode-model-scout
|
|
925
975
|
|
|
926
|
-
`opencode-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
1, see [Using OpenCode 1](#using-opencode-1) instead.
|
|
931
|
-
|
|
932
|
-
On OpenCode 2, replace the package in your OpenCode configuration. `remove`
|
|
933
|
-
takes the entry exactly as it is configured, including a version pin such as
|
|
934
|
-
`opencode-model-scout@1.6.0`:
|
|
976
|
+
`opencode-actualyze` is the successor of `opencode-model-scout` and requires
|
|
977
|
+
OpenCode 2. Remove the old package from your configuration and add the new
|
|
978
|
+
one. `remove` takes the entry exactly as it is configured, including any
|
|
979
|
+
version pin:
|
|
935
980
|
|
|
936
981
|
```bash
|
|
937
982
|
opencode plugin remove opencode-model-scout
|
|
938
983
|
opencode plugin add opencode-actualyze
|
|
939
984
|
```
|
|
940
985
|
|
|
941
|
-
To do it by hand,
|
|
942
|
-
|
|
943
|
-
|
|
986
|
+
To do it by hand, replace the `opencode-model-scout` entry in the `plugins`
|
|
987
|
+
array of `opencode.json` with `opencode-actualyze`; in object form, change
|
|
988
|
+
its `package` field. An entry that points at a checkout of
|
|
944
989
|
`opencode-model-scout` should point at the `dist` directory of an
|
|
945
990
|
`opencode-actualyze` checkout instead (see
|
|
946
|
-
[Running from a checkout](#running-from-a-checkout)).
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
appear once the first discovery finishes,
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
```json
|
|
969
|
-
{
|
|
970
|
-
"plugin": ["opencode-actualyze@1.7.0"]
|
|
971
|
-
}
|
|
972
|
-
```
|
|
973
|
-
|
|
974
|
-
and `tui.json`:
|
|
975
|
-
|
|
976
|
-
```json
|
|
977
|
-
{
|
|
978
|
-
"$schema": "https://opencode.ai/tui.json",
|
|
979
|
-
"plugin": ["opencode-actualyze@1.7.0"]
|
|
980
|
-
}
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
The 1.x documentation is the
|
|
984
|
-
[README in the 1.7.0 package](https://unpkg.com/opencode-actualyze@1.7.0/README.md).
|
|
985
|
-
|
|
986
|
-
Coming from `opencode-model-scout` on OpenCode 1, replace its entry (for
|
|
987
|
-
example `opencode-model-scout@1.6.0`) with `opencode-actualyze@1.7.0` in both
|
|
988
|
-
`opencode.json` and `tui.json`, and remove the old entry so only one loads.
|
|
989
|
-
In 1.7.0 the dialog is `/actualyze` instead of `/modelscout`, and a provider
|
|
990
|
-
that set `"probe": "atlas"` needs `"probe": "actualyze"`.
|
|
991
|
+
[Running from a checkout](#running-from-a-checkout)). Keep only one of the
|
|
992
|
+
two: each entry loads as a separate plugin.
|
|
993
|
+
|
|
994
|
+
What changes:
|
|
995
|
+
|
|
996
|
+
- **Plugin ID.** The plugin ID is now `opencode-actualyze`, so anything that
|
|
997
|
+
names the plugin by its ID needs the new one. That includes a client of
|
|
998
|
+
the plugin's RPC contract, which `opencode-actualyze/rpc` exports. Saved
|
|
999
|
+
discovery state starts fresh, because OpenCode keeps it under the plugin
|
|
1000
|
+
ID; the discovered models appear again once the first discovery finishes,
|
|
1001
|
+
usually within a few seconds.
|
|
1002
|
+
- **Commands.** The `/modelscout` browser keeps its name, and `/actualyze`
|
|
1003
|
+
is added.
|
|
1004
|
+
- **Probe values.** A `settings.probe` value the plugin does not recognize
|
|
1005
|
+
shows a warning in `/modelscout` and `/actualyze` that lists the accepted
|
|
1006
|
+
values.
|
|
1007
|
+
- **Actualyze providers.** A provider entry that points at
|
|
1008
|
+
`https://app.actualyze.ai/openai/v1` can be removed, because the built-in
|
|
1009
|
+
`actualyze` provider covers it. Its models then appear under the
|
|
1010
|
+
`actualyze` provider; connect your key with `/actualyze` or
|
|
1011
|
+
`opencode auth login actualyze`.
|
|
991
1012
|
|
|
992
1013
|
## Contributing
|
|
993
1014
|
|
|
@@ -996,4 +1017,5 @@ the live harness and TUI scenarios, and how to add a probe.
|
|
|
996
1017
|
|
|
997
1018
|
## License
|
|
998
1019
|
|
|
999
|
-
MIT. Based on
|
|
1020
|
+
MIT. Based on
|
|
1021
|
+
[opencode-lmstudio](https://github.com/agustif/opencode-lmstudio).
|