dsh-opencode-go 0.1.24 → 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.en.md +66 -12
- package/README.md +172 -79
- package/THIRD_PARTY_NOTICES.md +6 -2
- package/assets/icon.png +0 -0
- package/docs/advanced.en.md +32 -35
- package/docs/advanced.md +33 -35
- package/docs/assets/logo-dark.png +0 -0
- package/docs/assets/logo-light.png +0 -0
- package/docs/assets/usage-history-desktop.jpg +0 -0
- package/docs/assets/usage-history-mobile.jpg +0 -0
- package/docs/assets/usage-history-models.jpg +0 -0
- package/docs/development.md +61 -119
- package/docs/independent-package.md +4 -2
- package/docs/usage-analytics.en.md +57 -0
- package/docs/usage-analytics.md +57 -0
- package/docs/verification.md +51 -917
- package/lib/build-info.json +1 -1
- package/lib/client.js +3429 -2618
- package/lib/free-http-worker.js +32 -0
- package/lib/index.js +5135 -3746
- package/lib/types/accounts.d.ts +96 -31
- package/lib/types/adapter.d.ts +63 -51
- package/lib/types/analytics.d.ts +35 -0
- package/lib/types/catalog.d.ts +109 -44
- package/lib/types/client/AnalyticsDialog.d.ts +18 -0
- package/lib/types/client/Section.d.ts +41 -7
- package/lib/types/client/UsagePill.d.ts +15 -6
- package/lib/types/client/controller.d.ts +178 -0
- package/lib/types/client/dashboard-copy.d.ts +58 -0
- package/lib/types/client/index.d.ts +18 -12
- package/lib/types/client/{locales.d.ts → presentation.d.ts} +97 -9
- package/lib/types/config.d.ts +14 -15
- package/lib/types/contracts.d.ts +338 -0
- package/lib/types/conversion.d.ts +155 -0
- package/lib/types/free-channel.d.ts +21 -0
- package/lib/types/free-http-worker.d.ts +1 -0
- package/lib/types/free-policy.d.ts +4 -0
- package/lib/types/free-protocol.d.ts +16 -0
- package/lib/types/free-runtime.d.ts +2 -0
- package/lib/types/free-socks-tunnel.d.ts +4 -0
- package/lib/types/free-transport.d.ts +19 -0
- package/lib/types/index.d.ts +8 -40
- package/lib/types/pricing.d.ts +29 -0
- package/lib/types/sdk-types.d.ts +1540 -2902
- package/lib/types/transport.d.ts +71 -0
- package/lib/vendor-licenses.txt +55 -31
- package/package.json +77 -78
- package/docs/assets/usage-panel.png +0 -0
- package/docs/fork-review-2026-09-25.md +0 -191
- package/docs/native-call-comparison-v020-rc2.md +0 -116
- package/lib/types/account-manager.d.ts +0 -25
- package/lib/types/account-operations.d.ts +0 -31
- package/lib/types/account-policy.d.ts +0 -16
- package/lib/types/account-recovery.d.ts +0 -2
- package/lib/types/account-selection.d.ts +0 -30
- package/lib/types/account-service.d.ts +0 -12
- package/lib/types/accounts-contract.d.ts +0 -38
- package/lib/types/call-trace.d.ts +0 -54
- package/lib/types/catalog-manager.d.ts +0 -20
- package/lib/types/client/AccountsCard.d.ts +0 -19
- package/lib/types/client/ModelEditor.d.ts +0 -20
- package/lib/types/client/accounts-controller.d.ts +0 -71
- package/lib/types/client/hint-mark.d.ts +0 -17
- package/lib/types/client/host-compat.d.ts +0 -7
- package/lib/types/client/host-primitives.d.ts +0 -11
- package/lib/types/client/section-controller.d.ts +0 -202
- package/lib/types/client/settings.d.ts +0 -18
- package/lib/types/client/staged-form.d.ts +0 -201
- package/lib/types/client/usage.d.ts +0 -4
- package/lib/types/config-contract.d.ts +0 -70
- package/lib/types/conversion/config.d.ts +0 -4
- package/lib/types/conversion/context.d.ts +0 -56
- package/lib/types/conversion/image-offload.d.ts +0 -13
- package/lib/types/conversion/image-pool.d.ts +0 -24
- package/lib/types/conversion/index.d.ts +0 -5
- package/lib/types/conversion/replay.d.ts +0 -66
- package/lib/types/conversion/stream.d.ts +0 -44
- package/lib/types/gateway-diagnostics.d.ts +0 -23
- package/lib/types/gateway-error.d.ts +0 -2
- package/lib/types/gateway-url.d.ts +0 -6
- package/lib/types/google-fetch.d.ts +0 -6
- package/lib/types/host-settings.d.ts +0 -11
- package/lib/types/json-response.d.ts +0 -14
- package/lib/types/metadata-cache.d.ts +0 -12
- package/lib/types/model-metadata.d.ts +0 -21
- package/lib/types/models-contract.d.ts +0 -66
- package/lib/types/models.d.ts +0 -13
- package/lib/types/protocol-contract.d.ts +0 -5
- package/lib/types/protocol-policy.d.ts +0 -4
- package/lib/types/provider-identity.d.ts +0 -4
- package/lib/types/proxy-url.d.ts +0 -2
- package/lib/types/proxy.d.ts +0 -11
- package/lib/types/reasoning.d.ts +0 -40
- package/lib/types/remote-contract.d.ts +0 -3
- package/lib/types/remotes.d.ts +0 -3
- package/lib/types/request-budget.d.ts +0 -12
- package/lib/types/request-control.d.ts +0 -2
- package/lib/types/settings-bridge.d.ts +0 -22
- package/lib/types/usage-contract.d.ts +0 -35
- package/lib/types/usage-display.d.ts +0 -4
- package/lib/types/usage.d.ts +0 -27
- /package/lib/types/{google-generative-ai.d.ts → google.d.ts} +0 -0
package/docs/advanced.en.md
CHANGED
|
@@ -42,24 +42,25 @@ socks5://127.0.0.1:1080
|
|
|
42
42
|
|
|
43
43
|
HTTP, HTTPS, SOCKS5, and URLs containing a username and password are supported. Subsequent conversations, catalog updates, and usage queries use the saved proxy. Connections originate from the machine running DSH; on a remote deployment, `127.0.0.1` refers to that server.
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### Dual routes and manual configuration
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
`dsh-opencode-go` (DSH OpenCode Go) discovers all chat models from `baseURL/models` and activates when at least one usable API key is configured. `dsh-opencode-free` (DSH OpenCode Free) discovers only chat models with a valid declared tariff whose text input, output, cache and every context tier are all zero, from `freeBaseURL/models`. Missing or invalid prices never qualify as free. Free activates whenever the plugin is enabled.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Free shares the account roster, prefers usable saved keys and follows automatic account retry settings. Without a usable key it sends `Bearer public`. Both routes preserve original model IDs, including overlapping names. Settings provides separate model tabs; Go keeps existing ID keys, while Free uses `dsh-opencode-free/<model ID>` in visibility and capacity settings.
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
protocolOverrides:
|
|
55
|
-
deepseek-v4.1-flash: openai-responses
|
|
56
|
-
```
|
|
51
|
+
Free inference sends direct API requests through the bundled standalone Bun 1.4.4 HTTP worker, with no local OpenCode dependency. The existing Node SDK still handles discovery, message/tool conversion and response parsing; Go retains its transport. Free uses the observed `opencode/latest/2.2.5/cli` user agent and the existing host-session normalization, without placeholder tools or captured account/project/session values. Compatibility does not guarantee upstream free access.
|
|
52
|
+
|
|
53
|
+
Free requests handle rate limits automatically. `FreeUsageLimitError` becomes `FREE_QUOTA`, a generic 429 becomes `FREE_RATE_LIMIT`, an explicit OpenCode client restriction becomes `FREE_CLIENT_RESTRICTED`, and an otherwise unclassified 403 becomes `FREE_ACCESS_DENIED`. Go error codes and account switching retain their behavior. Explicit Go account quota/authentication failures on Free still follow existing account fallback settings; shared Free limits neither rotate accounts nor fall back to paid Go.
|
|
57
54
|
|
|
58
|
-
|
|
55
|
+
Shared Free restrictions and network, timeout or server errors honor `Retry-After` delta-seconds or HTTP-date, including delays of many hours. Without a valid header, exponential backoff starts at 60 seconds and caps at 15 minutes. Cooldowns are isolated by Free gateway and proxy configuration. New calls during cooldown return `FREE_COOLDOWN` without inference traffic; no automatic retry is scheduled. Users can retry after expiry; success resets the fallback counter. State is held in the plugin instance and starts fresh after restart.
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
The platform binary installs through npm optional dependencies. Install scripts may be disabled, but optional dependencies must be included. A missing runtime reports `MISSING_BUN_RUNTIME` on Free; reinstall the plugin with optional dependencies enabled. Go remains available. Supported operating systems and CPUs follow Bun's official platform packages.
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
Each Free HTTP request owns a worker, with at most four concurrent workers and cancellable queueing. Requests use stdin; response headers and raw SSE bytes use stdout. Keys never enter argv or temporary files. Consumer cancellation, timeouts and plugin unload stop requests and reap workers. Encoded IPC requests are limited to 256 MiB. Bun handles HTTP/HTTPS proxies; SOCKS5 uses a per-request loopback byte tunnel with random authentication credentials while Bun still performs target TLS. A proxy failure never falls back to a direct connection.
|
|
60
|
+
|
|
61
|
+
Protocols, capabilities, reasoning controls and tariffs come directly from each gateway’s `/models` entries. Official gateways prefer declared protocol URLs; custom gateways keep their configured prefix. Separate `go.models.json` and `free.models.json` files under `~/.dsh/cache/dsh-opencode-go/` support ETag revalidation and offline retention. Cache documents identify their source URL and cannot be reused for another gateway.
|
|
62
|
+
|
|
63
|
+
The following patch configures shared accounts and per-model settings:
|
|
63
64
|
|
|
64
65
|
```yaml
|
|
65
66
|
- id: opencode-go
|
|
@@ -73,11 +74,14 @@ Add an `opencode-go` configuration block to a patch file. It can be combined wit
|
|
|
73
74
|
name: Backup
|
|
74
75
|
apiKeyEnv: OPENCODE_GO_BACKUP_KEY
|
|
75
76
|
autoSwitch: true
|
|
77
|
+
freeBaseURL: https://opencode.ai/inference/v1
|
|
76
78
|
proxyURL: http://127.0.0.1:7890
|
|
77
79
|
refreshMinutes: 60
|
|
78
80
|
modelVisibility:
|
|
79
81
|
deepseek-v4-pro: false
|
|
80
82
|
modelLimits:
|
|
83
|
+
dsh-opencode-free/beam-free:
|
|
84
|
+
maxTokens: 8192
|
|
81
85
|
deepseek-v4.1-flash:
|
|
82
86
|
maxTokens: 8192
|
|
83
87
|
qwen3.7-plus:
|
|
@@ -89,49 +93,42 @@ Keep the options you need and supply the corresponding keys through DSH credenti
|
|
|
89
93
|
|
|
90
94
|
| Option | Purpose |
|
|
91
95
|
| --- | --- |
|
|
92
|
-
| `baseURL` |
|
|
96
|
+
| `baseURL` | OpenCode Go gateway address; defaults to `https://opencode.ai/inference/go/v1`, with official inference endpoints selected by model protocol |
|
|
97
|
+
| `freeBaseURL` | Platform free gateway, default `https://opencode.ai/inference/v1`; editable with URL validation in advanced settings |
|
|
93
98
|
| `usageDisplay` | Usage display mode: `auto`, `always`, or `off` |
|
|
94
99
|
| `proxyURL` | Network proxy; an empty string uses the default network settings |
|
|
95
100
|
| `refreshMinutes` | Model catalog cache lifetime; defaults to 60 minutes, with manual refresh available in Settings |
|
|
96
101
|
| `modelVisibility` | Control model picker visibility by model ID |
|
|
97
|
-
| `protocolOverrides` | Experimental `deepseek-v4.1-flash: openai-responses`; unset or null follows the gateway |
|
|
98
102
|
| `modelLimits` | Per-model `contextWindow` and `maxTokens` overrides, plus additional `thinkingBudgets` options; null uses defaults |
|
|
99
103
|
| `maxImages` | Maximum images in one request's history; unset by default, with oldest images offloaded when exceeded |
|
|
100
104
|
| `streamIdleTimeoutMs` | Maximum wait for the next stream event; defaults to 300000 milliseconds |
|
|
101
105
|
| `requestPreparationTimeoutMs` | Deadline for discovery and each attempt's credential/image preparation; defaults to 60000 milliseconds |
|
|
102
106
|
| `requestTimeoutMs` | Whole dispatch deadline, including discovery, account fallback and streaming; defaults to 1800000 milliseconds. Prepared calls start this timer at dispatch |
|
|
103
107
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Image offloading keeps the original attachment and replaces the old image in the request with a text placeholder. Raising the limit does not automatically restore previously offloaded images.
|
|
108
|
+
The default official gateway lists models at `GET https://opencode.ai/inference/go/v1/models` and reads usage at `GET https://opencode.ai/inference/go/v1/usage`. Inference follows each model's declared protocol and the [official endpoint documentation](https://opencode.ai/v2/docs/console/go/#endpoints). The following paths share the prefix `https://opencode.ai/inference/go`:
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
| Model protocol | Inference path |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| OpenAI Chat Completions, such as GLM-5.3-Flash | `/openai/v1/chat/completions` |
|
|
113
|
+
| OpenAI Responses, such as Grok 4.7 and GPT 6 Luna | `/openai/v1/responses` |
|
|
114
|
+
| Anthropic Messages, such as Claude Haiku 5.5 | `/anthropic/v1/messages` |
|
|
115
|
+
| Google, such as Gemini 4 Argon Contributor | `/google/v1beta/models/{model}:streamGenerateContent` |
|
|
111
116
|
|
|
112
|
-
|
|
117
|
+
The legacy official base `https://opencode.ai/zen/go/v1` migrates automatically, and settings writes store the new address. There is no need to change the gateway for each model. Custom gateways keep the configured `baseURL` prefix and let each protocol SDK append its resource path; official protocol segments are not added automatically. A working listing does not verify every inference route.
|
|
113
118
|
|
|
114
|
-
|
|
119
|
+
Usage failures retain the HTTP status and show a redacted summary when the upstream provides a readable reason. HTTP 403 includes a reminder to check the API key and Go subscription permissions. “Key saved” only confirms local credential storage; check the subscription for the account or workspace that owns the key, along with the gateway and proxy settings.
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
export DSH_OPENCODE_GO_DEBUG_DIR=/tmp/dsh-opencode-go-debug
|
|
118
|
-
dsh web
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Windows PowerShell:
|
|
121
|
+
Image offloading keeps the original attachment and replaces the old image in the request with a text placeholder. Raising the limit does not automatically restore previously offloaded images.
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
$env:DSH_OPENCODE_GO_DEBUG_DIR = "$env:TEMP\dsh-opencode-go-debug"
|
|
125
|
-
dsh web
|
|
126
|
-
```
|
|
123
|
+
Image count overflow is detected before attachment reads. Each request prepares at most four images concurrently and stops when known encoded bytes exceed its payload budget. There is no plugin-wide image queue or shared payload pool.
|
|
127
124
|
|
|
128
|
-
Reproduce the failure to get a JSON file path in the error message. The record contains the model, request parameter summaries, HTTP status, upstream log and route IDs, and the error response, for use in an [issue report](https://github.com/Duskriver/dsh-opencode-go/issues). Review the returned error content before sharing. Clear the environment variable and restart DSH to disable diagnostics.
|
|
129
125
|
|
|
130
|
-
|
|
126
|
+
A cold catalog outage reports `DISCOVERY_FAILED`; a warm catalog retains previously verified models. Only an explicit empty gateway listing clears membership. A partially malformed listing keeps its valid models and reports the ignored row count in settings and logs. Ordinary advanced form settings commit in one revision-checked batch. Credentials use a separate service; failed credential drafts remain, and retry submits only uncommitted parts.
|
|
131
127
|
|
|
128
|
+
Request failures retain HTTP classification, redacted upstream summaries and applicable context-capacity hints. The plugin no longer writes internal diagnostic files or per-call traces.
|
|
132
129
|
|
|
133
130
|
## Account operations and saving
|
|
134
131
|
|
|
135
|
-
|
|
132
|
+
Account operations run in a host-owned memory queue, with credential writes completed before settings updates. Closing the page does not cancel a storage write already in progress. There is no transaction journal or startup recovery loop; retry an unsuccessful operation from the accounts card.
|
|
136
133
|
|
|
137
134
|
Reset all to defaults in advanced settings removes overrides at the current layer and restores inherited values; save to apply the reset. It does not remove accounts or keys, or clear model limit overrides.
|
package/docs/advanced.md
CHANGED
|
@@ -42,20 +42,23 @@ socks5://127.0.0.1:1080
|
|
|
42
42
|
|
|
43
43
|
支持 HTTP、HTTPS、SOCKS5 和带用户名、密码的代理 URL。保存后,后续对话、模型目录更新和用量查询使用新代理。代理运行在 DSH 所在的机器上;远程部署中的 `127.0.0.1` 指服务器自身。
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### 双路由与手动配置
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
`dsh-opencode-go`(DSH OpenCode Go)从 `baseURL` 的 `/models` 动态发现全部聊天模型,需要至少一个可用 API Key 才激活。`dsh-opencode-free`(DSH OpenCode Free)从 `freeBaseURL` 的 `/models` 筛选已声明合法价格、且文本输入、输出、缓存及所有上下文阶梯均为零的聊天模型;缺失或非法价格不会被视为免费。插件开启即激活 Free 路由。
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Free 共用账号列表,优先使用已配置的可用 Key,并遵循多账号自动切换设置;没有可用 Key 时使用 `Bearer public`。两个路由分别保留原始模型 ID,同名模型可同时存在。设置页顶部的两个模型 Tab 分别编辑各自列表;Go 沿用原 ID 设置键,Free 使用 `dsh-opencode-free/<模型 ID>`。
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```
|
|
51
|
+
Free 推理通过插件附带的独立 Bun 1.4.4 HTTP worker 直接发送 API 请求;不依赖本机 OpenCode。模型发现、消息和工具转换、响应解析仍由现有 Node SDK 负责,Go 沿用原传输。Free 使用实测的 `opencode/latest/2.2.5/cli` UA,保留宿主会话 ID 的原有规范化,不注入占位工具或抓包中的账号、项目和会话值。这些兼容行为不保证上游开放免费服务。
|
|
52
|
+
|
|
53
|
+
Free 请求自动处理限流:`FreeUsageLimitError` 返回 `FREE_QUOTA`,普通 429 返回 `FREE_RATE_LIMIT`,明确的 OpenCode 客户端限制返回 `FREE_CLIENT_RESTRICTED`,其他未明确分类的 403 返回 `FREE_ACCESS_DENIED`。Go 的错误码和账号切换保持原有规则;Free 中明确的 Go 账号额度或凭据错误仍可按既有设置切换账号,共享 Free 限制不会换号或回退到付费 Go。
|
|
54
|
+
|
|
55
|
+
对共享免费限制及网络、超时、服务端错误,优先遵循 `Retry-After` 秒数或 HTTP 日期(不会把数小时的退避缩短成几分钟);没有有效头时,从 60 秒开始指数退避,最多 15 分钟。冷却按免费网关与代理配置隔离,冷却期间新调用返回 `FREE_COOLDOWN`,不发送推理请求,也不自动定时重试。到期后可由用户重试;成功请求重置本地退避计数。退避计数只保存在当前插件实例内,重启后清空。
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
Bun 通过 npm 可选依赖安装对应平台的二进制;禁用安装脚本仍可使用,但不能省略可选依赖。若缺少运行时,Free 会报告 `MISSING_BUN_RUNTIME`,可重新安装插件并启用 optional dependencies;Go 不受影响。当前平台包支持的系统和 CPU 以 Bun 的官方发行包为准。
|
|
58
|
+
|
|
59
|
+
每个 Free HTTP 请求使用一个 worker,默认最多并发 4 个,其余请求可排队或取消。请求通过标准输入传递,响应头和原始 SSE 字节通过标准输出返回;Key 不进入命令行参数或临时文件。消费者停止、超时、取消或卸载插件都会终止相关请求并回收 worker。IPC 请求上限为编码后 256 MiB。HTTP/HTTPS 代理由 Bun 连接;SOCKS5 使用该请求专属、带随机认证凭据的本机字节隧道,目标 TLS 握手仍由 Bun 完成。代理失败不会回退到直连。
|
|
60
|
+
|
|
61
|
+
协议、能力、思考控制与价格直接来自各自的 `/models` 条目。官方网关优先使用条目声明的协议地址;自定义网关保留配置的前缀。两个模型源分别缓存到 `~/.dsh/cache/dsh-opencode-go/go.models.json` 与 `free.models.json`,支持 ETag 与离线保留;缓存带有网关来源标记,不会用于其他地址。
|
|
59
62
|
|
|
60
63
|
在 patch 文件中添加 `opencode-go` 配置块,可与上面的默认模型配置一起使用:
|
|
61
64
|
|
|
@@ -71,11 +74,14 @@ socks5://127.0.0.1:1080
|
|
|
71
74
|
name: 备用账号
|
|
72
75
|
apiKeyEnv: OPENCODE_GO_BACKUP_KEY
|
|
73
76
|
autoSwitch: true
|
|
77
|
+
freeBaseURL: https://opencode.ai/inference/v1
|
|
74
78
|
proxyURL: http://127.0.0.1:7890
|
|
75
79
|
refreshMinutes: 60
|
|
76
80
|
modelVisibility:
|
|
77
81
|
deepseek-v4-pro: false
|
|
78
82
|
modelLimits:
|
|
83
|
+
dsh-opencode-free/beam-free:
|
|
84
|
+
maxTokens: 8192
|
|
79
85
|
deepseek-v4.1-flash:
|
|
80
86
|
maxTokens: 8192
|
|
81
87
|
qwen3.7-plus:
|
|
@@ -87,49 +93,41 @@ socks5://127.0.0.1:1080
|
|
|
87
93
|
|
|
88
94
|
| 配置项 | 用途 |
|
|
89
95
|
| --- | --- |
|
|
90
|
-
| `baseURL` |
|
|
96
|
+
| `baseURL` | OpenCode Go 网关地址,默认 `https://opencode.ai/inference/go/v1`;官方网关自动按模型协议选择推理端点 |
|
|
97
|
+
| `freeBaseURL` | 平台免费模型网关,默认 `https://opencode.ai/inference/v1`;高级设置可编辑并校验 URL |
|
|
91
98
|
| `usageDisplay` | 额度显示模式:`auto`、`always` 或 `off` |
|
|
92
99
|
| `proxyURL` | 网络代理;空字符串使用默认网络设置 |
|
|
93
100
|
| `refreshMinutes` | 模型目录缓存时长,默认 60 分钟;设置页可随时手动刷新 |
|
|
94
|
-
| `modelVisibility` |
|
|
95
|
-
| `protocolOverrides` | 实验性协议覆盖;目前仅支持 `deepseek-v4.1-flash: openai-responses`,省略或模型值为 `null` 时自动跟随目录 |
|
|
101
|
+
| `modelVisibility` | Go 用原模型 ID;Free 用 `dsh-opencode-free/<模型 ID>`,分别控制显示 |
|
|
96
102
|
| `modelLimits` | 按模型覆盖 `contextWindow`、`maxTokens`,或用 `thinkingBudgets` 添加思考预算选项;空值使用默认设置 |
|
|
97
103
|
| `maxImages` | 单次请求历史中的图片数量上限,默认不设上限;超过时先卸载最旧图片 |
|
|
98
104
|
| `streamIdleTimeoutMs` | 等待下一个流事件的最长时间,默认 300000 毫秒 |
|
|
99
105
|
| `requestPreparationTimeoutMs` | 目录查询及每次尝试的凭据、图片准备时限,默认 60000 毫秒 |
|
|
100
106
|
| `requestTimeoutMs` | 一次发送的完整时限,包含目录查询、账号切换和流式输出,默认 1800000 毫秒;预先准备的调用从发送时计时 |
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
图片卸载会保留原始附件,并将请求中的旧图片替换为文字占位;调高上限不会自动恢复已卸载的历史图片。
|
|
108
|
+
默认官方网关使用 `GET https://opencode.ai/inference/go/v1/models` 读取模型列表,使用 `GET https://opencode.ai/inference/go/v1/usage` 查询额度。推理端点按模型目录声明的协议选择,与[官方文档](https://opencode.ai/v2/docs/console/go/#endpoints)一致,以下路径均以 `https://opencode.ai/inference/go` 为前缀:
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
需要排查请求失败时,在启动 DSH 前设置诊断目录:
|
|
110
|
+
| 模型协议 | 推理路径 |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| OpenAI Chat Completions(如 GLM-5.3-Flash) | `/openai/v1/chat/completions` |
|
|
113
|
+
| OpenAI Responses(如 Grok 4.7、GPT 6 Luna) | `/openai/v1/responses` |
|
|
114
|
+
| Anthropic Messages(如 Claude Haiku 5.5) | `/anthropic/v1/messages` |
|
|
115
|
+
| Google(如 Gemini 4 Argon Contributor) | `/google/v1beta/models/{model}:streamGenerateContent` |
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
export DSH_OPENCODE_GO_DEBUG_DIR=/tmp/dsh-opencode-go-debug
|
|
116
|
-
dsh web
|
|
117
|
-
```
|
|
117
|
+
读取旧官方地址 `https://opencode.ai/zen/go/v1` 时,插件会自动迁移,保存设置时也会写入新地址。无需为每个模型手动修改网关。自定义网关继续使用填写的 `baseURL` 作为请求前缀,由各协议 SDK 拼接资源路径;不会自动添加官方网关的协议分段。列表可访问不代表所有推理接口都可用。
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
额度查询失败时,面板会保留 HTTP 状态码,并在上游提供可读原因时显示脱敏后的摘要。HTTP 403 会提示检查 API Key 和 Go 订阅权限;账号显示“已配置 key”仅代表本地保存了凭据。可同时核对 Key 所属账号或 workspace 的订阅状态,以及网关与代理配置。
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
$env:DSH_OPENCODE_GO_DEBUG_DIR = "$env:TEMP\dsh-opencode-go-debug"
|
|
123
|
-
dsh web
|
|
124
|
-
```
|
|
121
|
+
图片卸载会保留原始附件,并将请求中的旧图片替换为文字占位;调高上限不会自动恢复已卸载的历史图片。
|
|
125
122
|
|
|
126
|
-
|
|
123
|
+
图片数量超限会在附件读取前检测。每个请求最多并发准备 4 张图片,并在已知编码大小超过单次请求预算时停止;插件不再维护全局图片队列或共享内存池。
|
|
127
124
|
|
|
128
|
-
|
|
125
|
+
首次查询目录失败会报告 `DISCOVERY_FAILED`;已有目录时保留之前确认过的模型。网关明确返回空列表才会清空目录。列表中仅部分行格式错误时,仍可使用有效模型,设置页与日志会提示被忽略的行数。高级表单的普通配置项一次提交并检查版本;凭据由独立服务保存,凭据保存失败时保留其草稿,重试只提交未成功的部分。
|
|
129
126
|
|
|
127
|
+
请求失败时,错误信息仍包含 HTTP 分类、脱敏后的上游摘要,以及适用的上下文容量提示。插件不再输出内部诊断文件或逐调用追踪。
|
|
130
128
|
|
|
131
129
|
## 账号操作与保存
|
|
132
130
|
|
|
133
|
-
|
|
131
|
+
账号操作按宿主内存队列顺序执行,凭据写入完成后再更新设置。页面中断不会取消已经开始的存储写入;进程重启后没有事务日志或自动恢复循环,未成功的操作可从账号卡片重新执行。
|
|
134
132
|
|
|
135
133
|
高级设置的“全部恢复默认”会清除当前层的自定义覆盖,恢复继承值;需要保存后才生效。它不删除账号或 Key,也不清除模型容量覆盖。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/development.md
CHANGED
|
@@ -1,140 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Development
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The development baseline is DSH `0.2.1-rc.5`, Cordis `4.0.5` and Schemastery `3.18.5`. Runtime DSH peers require `>=0.2.1-rc.5`; Cordis requires `~4.0.5`. Install the locked dependencies with `npm ci`.
|
|
4
4
|
|
|
5
5
|
## Commands
|
|
6
6
|
|
|
7
7
|
| Command | Purpose |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| `npm
|
|
10
|
-
| `npm run compile` |
|
|
11
|
-
| `npm run check:dist` |
|
|
12
|
-
| `npm
|
|
13
|
-
| `npm test` |
|
|
14
|
-
| `npm run
|
|
15
|
-
| `npm run
|
|
16
|
-
| `npm run
|
|
17
|
-
| `npm run test:install -- npm` / `-- pnpm` | Run just one package manager; unknown names fail |
|
|
18
|
-
| `npm run verify` | Run core, compatibility, and installation checks |
|
|
9
|
+
| `npm run typecheck` | Check the host and browser TypeScript projects |
|
|
10
|
+
| `npm run compile` | Rebuild the host bundle, browser factory and declarations in `lib/` |
|
|
11
|
+
| `npm run check:dist` | Compare an independent rebuild with every shipped artifact |
|
|
12
|
+
| `npm test` | Run the Vitest suite |
|
|
13
|
+
| `npm run test:ci` | Check artifacts, then run the Vitest suite |
|
|
14
|
+
| `npm run verify:installed -- /path/to/consumer` | Exercise a built package through the consumer's real Cordis resolver; defaults to this checkout |
|
|
15
|
+
| `npm run verify:headless -- /path/to/consumer` | Exercise a consumer containing the official DSH CLI and the installed plugin, with an isolated profile and loopback gateway |
|
|
16
|
+
| `npm run verify` | Run type checks, artifact comparison, the complete Vitest suite and installed-package smoke |
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
`test:ci` runs `check:dist` followed by `npm test`. `verify` runs `typecheck`, `test:ci` and `verify:installed`. CI uses `npm ci --strict-peer-deps` and `npm run verify` on Linux and Windows with Node 22.19 and 24. Inference smoke checks use synthetic credentials and a loopback gateway. `verify:headless` additionally requires the official DSH CLI in the supplied consumer; it creates an isolated home and profile.
|
|
21
19
|
|
|
22
|
-
##
|
|
20
|
+
## Test suite
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
Vitest tests are organized by domain. Results for the history-dashboard migration are tracked separately in [verification notes](verification.md); the table below is a scope reference, not a passing-run claim.
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
All
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
The gateway uses HTTP 401 for model errors, subscription limits and authentication failures. `gateway-error.ts` classifies captured `error.type`/`error.code` first. Untyped quota text is admitted only on HTTP 401/402/403/429; untyped 5xx keeps `SERVER` (504 keeps `TIMEOUT`) even when diagnostics quote earlier quota failures. A generic 401/403 never proves a key is invalid. Only `INVALID_CREDENTIAL` is remembered as a gateway key rejection; quota failures can switch accounts before output but do not blacklist credentials. HTTP 200 stream errors continue through the stream mapper's fallback classification. Retry-After remains in bounded HTTP evidence for diagnosis; the host owns retry scheduling.
|
|
65
|
-
|
|
66
|
-
Discovery and credential/image preparation have a default 60-second deadline. Dispatch has a separate default 30-minute deadline spanning discovery, fallback and streaming. The existing idle watchdog still limits an outstanding stream read. Every external wait observes cancellation, including services that ignore their signal; canceling a catalog waiter does not abort the shared refresh. Prepared capability resolution has its own preparation deadline, and the dispatch timer starts when the prepared stream is consumed.
|
|
67
|
-
|
|
68
|
-
Image count preflight does not estimate encoded bytes on modern hosts. Four shared permits and a 32-task queue bound preparation across simultaneous calls; exact encoded sizes are checked incrementally with unknown sizes contributing zero. A shared 128 MiB lease budget charges each prepared raw image plus occurrence-weighted base64 bytes. Adapter leases last through streaming and release on completion, failure or consumer stop; standalone conversion only holds its lease during conversion. Queue/budget admission fails with `IMAGE_RESOURCE_BUSY`, without account switching. This logical budget excludes decoder RSS, JSON/SDK copies and retained history. A returned raw image exists before its charge is checked, so four active native operations can still produce transient overshoot. Failure aborts queued work. An in-flight service that ignores cancellation retains its permit until it really settles, so cancellation cannot accidentally admit unbounded native work. A permanently stuck service can therefore exhaust these slots and needs host/service recovery. DSH 0.1.5 retains its transient projection policy; later hosts retain durable `IMAGE_OFFLOAD_REQUIRED` retries.
|
|
69
|
-
|
|
70
|
-
`StagedForm` submits settings set/unset operations in one `scope.mutate` with the captured revision. A refused batch leaves drafts and does not write secrets. Successful settings drafts clear even if a separate secret write fails, allowing an idempotent retry. A newer draft typed during a save is retained. Settings and credentials remain separate stores, without a cross-store transaction.
|
|
71
|
-
|
|
72
|
-
Account additions and generated-account removals first confirm a durable `accountOperations` intention in the account's own section/profile. The hidden field stores operation ID, kind and account metadata, never a key. The Host reconciles it at startup, settings/credential connection and committed updates. Already stored addition keys gain their metadata; additions without keys remain visible and can be repaired or removed. Deletion intentions finish credential removal before atomically removing metadata and the intention. Revision guards preserve concurrent edits and later selections; a refused store retains the intention, with at most four passes per trigger and a 30-second deadline per operation. Closing or replacing the connection cancels its waits so a new service can resume. Credential deletion requires an exact generated ID/reference pairing; external or shared legacy references keep their values. Recovery acts only while its service connection is current. Cancelling a wait cannot roll back an already accepted storage write. It cannot recover a key that was never stored, provide isolation against arbitrary simultaneous writes in other profiles, or repair operations predating the journal. Manually sharing a generated reference across profiles also shares its deletion lifecycle.
|
|
73
|
-
|
|
74
|
-
A nonempty gateway listing with no valid model IDs is a discovery failure and preserves served membership. A confirmed empty list clears it. Missing models on a cold or failed listing report `DISCOVERY_FAILED`, while confirmed absence reports `UNKNOWN_MODEL` through the adapter. Mixed valid/invalid rows use valid IDs and expose a warning in `sources.listing.warning`, the settings page and Host logs. The warning includes counts and at most eight row positions, never malformed row contents, and clears after a clean listing. The choice favors usable partial data while making potential membership loss visible. Public disk metadata still does not establish gateway membership after a restart.
|
|
75
|
-
|
|
76
|
-
The public `onCallTrace` observer receives one content-free summary per dispatch: random call ID, model, elapsed and stage milliseconds, attempt count, outcome and final code. A bounded `attemptDetails` array includes each attempt's stages, outcome/code, HTTP status, selected redacted upstream request ID, first text/reasoning/tool-argument delta latency and image pool diagnostics. Queue wait is summed across image tasks and may exceed wall-clock image-stage time. HTTP evidence files carry the same call ID and attempt number. There is no stable account identity in this trace. The plugin forwards it to the host debug logger. Observer failures cannot alter inference. Compile-time `never` checking and runtime rejection guard the SDK event union; unknown host roles are explicitly rejected. The open peer range is an installation policy, while the installed matrix is the finite evidence of compatibility.
|
|
77
|
-
|
|
78
|
-
## Reasoning intent
|
|
79
|
-
|
|
80
|
-
`src/protocol-contract.ts` restricts the experimental `protocolOverrides` surface to DeepSeek V4.1 Flash → Responses. `src/protocol-policy.ts` resolves the wire API, base URL and fresh protocol compatibility profile together on the captured request config, before capacity overrides. The cached catalog remains unmodified. Effort choices stay those advertised by metadata; an unexpected native toggle/budget or source protocol is rejected before inference. Protocol errors do not trigger a second-protocol retry. The installed-host transcript matrix exercises the override as a Chat Completions-declared model through the real Responses SDK, including tool-result continuation and restored replay; focused tests also switch existing histories in both directions and retain only valid native reasoning state.
|
|
81
|
-
|
|
82
|
-
For latency comparisons, fix the account, proxy/network, prompt, model, reasoning effort, output cap and stable `x-opencode-session` header. Interleave protocols and report cold and warm samples separately. Measure first body-text delta, total time, output/reasoning tokens and failures; the existing `GoCallTrace.firstOutputMs` includes reasoning and tool deltas and is not body-text TTFT. Local fixtures establish compatibility, not live gateway speed or its underlying provider. Run paid live benchmarks only when requested.
|
|
83
|
-
|
|
84
|
-
`scripts/benchmark-protocols.mjs` compares the plugin already installed in the macOS desktop profile using the app's actual peer packages. It requires explicit `--live`, performs 20 bounded synthetic calls with a 4,096-token output cap, and writes JSON results under `opencode-protocol-benchmark-<runId>` without changing settings or stored credentials. Automatic fallback is disabled in memory. The output includes first and repeated samples, reasoning/output tokens, route headers, and failures; first-session samples do not prove an upstream cache miss. Run its offline observer/statistics check with `node scripts/benchmark-protocols.mjs --self-test`.
|
|
85
|
-
|
|
86
|
-
`scripts/benchmark-latency.mjs` compares direct gateway fetches with the desktop-installed adapter using byte-identical SDK request bodies and headers, including the selected credential and a fresh shared session header. Run its `--self-test` offline; live runs require the desktop executable with `ELECTRON_RUN_AS_NODE=1`, `--expose-internals`, explicit `--live`, and `--session /absolute/path/to/a/single-step/session.v4.jsonl.zstd`. The `zstd` CLI reads the journal's concatenated frames. The default run uses four alternating pairs of the reconstructed request and two pairs containing only its human message, with a 1,024-token output cap. Use `--control-pairs 0 --fresh-context` to insert an inert prefix per pair and observe cache misses/hits, or `--control-pairs 0 --concurrent-title` to replay the recorded title request concurrently with each main call. The latter adds one 64-token auxiliary generation per main request when that was the recorded cap. Original prompt content, raw headers and credentials remain in memory; reports contain hashes, counters, usage, gateway route IDs, content-free adapter traces and timings only. Undici diagnostic channels measure socket submission, upload completion and response headers; a common SSE observer measures wire thinking/text before SDK parsing, which is timed independently at the adapter's consumer. Socket connection events describe process-level activity and are only attributable during these isolated runs. Automatic retries/account switching are disabled, and a failed main request stops the run. Profile and credential hashes are checked afterward. These runs exercise the real installed adapter and Host packages outside the UI; they cannot recover historical gateway queue time or desktop IPC latency.
|
|
87
|
-
|
|
88
|
-
```sh
|
|
89
|
-
ELECTRON_RUN_AS_NODE=1 '/Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness' scripts/benchmark-protocols.mjs --live
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Use `--profile`, `--resources`, or `--out` to change the desktop profile, application resources directory, or report directory. The selected account's credential is read from the environment or the user's DSH credential store and stays in memory.
|
|
93
|
-
|
|
94
|
-
The model catalog records whether controls are a switch, adjustable effort, or a token budget, independently of pi-ai's wire compatibility hints. `src/reasoning.ts` owns the picker choices and translates a validated selection into Default, Off, On, an explicit effort, or a token budget. Model resolution declares no `defaultEffort`: an omitted user choice remains omitted through the DSH runtime.
|
|
95
|
-
|
|
96
|
-
Before the SDK sends a payload, the shared `onPayload` hook removes automatic thinking controls for Default. For On it retains the SDK's native enable/budget but removes synthetic effort fields. Off and explicit effort keep the SDK's serialization. Other output configuration, rendering and history options are retained, and payload edits do not mutate shared catalog models. Switches keep their previous opaque `high` ID for durable selection compatibility and display it as On. The verified MiMo Flash control override stays in the same reasoning module.
|
|
97
|
-
|
|
98
|
-
Token budgets use pi-ai's `thinkingBudgets` override; the SDK still handles the wire field, context ceiling, and answer room. Only SDK-supported budget protocols expose the control; adaptive Anthropic models retain effort controls. Models declaring both effort and budget keep their efforts and can add numeric budget choices. Standard budget presets retain the historical `minimal`/`low`/`medium`/`high` IDs. Additional presets use durable `budget:N` IDs and are configured in `modelLimits[modelId].thinkingBudgets`. Catalog bounds reach the settings page through the models RPC; numeric choices and request settings are captured together before dispatch.
|
|
99
|
-
|
|
100
|
-
## Bundled pi-ai implementation
|
|
101
|
-
|
|
102
|
-
The development dependency `opencode-go-pi-ai` is an npm alias for `@earendil-works/pi-ai@1.2.0`. esbuild retains the four supported protocol implementations and the OpenCode Go model table, and discards unrelated provider implementations. Public SDK types are flattened into `lib/types/sdk-types.d.ts`; consumers do not need the private alias to resolve them. OpenAI 7.19.0 and Anthropic 0.129.0 remain runtime dependencies at the same versions pi-ai uses. Google 2.21.0 and its required HTTP dependencies are bundled. Bundled code and type licenses ship in `lib/vendor-licenses.txt`.
|
|
103
|
-
|
|
104
|
-
The published package does not depend on pi-ai or Google/protobuf packages, so their install hooks never run in consumers, including when using Gemini. This avoids the pnpm 11 script-approval interruption that triggered issue #43 without changing the host's policy. An npm consumer separately includes public pi-ai 0.85.1 and a peer-only probe, plus OpenAI 6.40.0 and Anthropic 0.124.0. It verifies that the peer retains pi-ai 0.85.1, the consumer retains both older transport SDKs, and the plugin resolves its own OpenAI 7.19.0 and Anthropic 0.129.0. Other plugins' dependencies still follow the user's host trust settings.
|
|
105
|
-
|
|
106
|
-
`src/google-generative-ai.ts` reuses pi-ai's native Google message conversion, tool declarations, streaming events, usage and thought-signature replay. A request-scoped `AsyncLocalStorage` binding carries the captured diagnostic/proxy fetch and Harness User-Agent without replacing global fetch. `scripts/google-fetch-bridge.mjs` substitutes one HTTP fetch call in the bundled Google SDK, with an exact 2.21.0 version check and a single-match source check. It also pins pi-ai 1.2.0's Google client factory to `vertexai: false`, so host `GOOGLE_GENAI_USE_VERTEXAI` / `GOOGLE_GENAI_USE_ENTERPRISE` settings cannot change the gateway's Gemini route. The stream patch keeps Parts within a chunk separate and starts a new block when a later chunk carries a different signature, preserving signed text, thinking and empty text during replay. Continuing deltas still accumulate within their Part, including signatures sent on the first or final delta. Each adapter substitution requires the pinned pi-ai version and exactly one source match. The environment and other Google clients retain their own backend selection. esbuild and Vitest use the same substitutions; review the bridge before changing either SDK pin. The remaining SDK serialization, stream parsing, cancellation and retry handling stay upstream code. Gemini 4 Argon postdates pi-ai 1.2.0, so the wrapper selects its discrete thinking levels explicitly. Default removes Google's nested `thinkingConfig`, while Low/Medium/High retain the metadata-declared levels.
|
|
107
|
-
|
|
108
|
-
The default public base is `https://opencode.ai/inference/go/v1` for model discovery, every inference protocol and usage requests. `src/gateway-url.ts` migrates the exact legacy official base `https://opencode.ai/zen/go/v1` before request paths are constructed. Settings schemas contain only data: the modern Host rebuilds volatile fields and serializes the form again, which drops rehydrated transform callbacks and prevents the desktop page from loading. `readConfig` normalizes live values, and `src/host-settings.ts` normalizes profile writes and rewrites saved aliases on attachment and document changes, with revision checks to preserve concurrent edits. Legacy runtime reads also normalize immediately while the saved migration completes. URL validation, direct catalog construction and metadata conversion apply the migration, including callers that supply raw configuration. The plugin never needs to reach the legacy gateway, even if it stops serving all routes. Custom gateways retain their configured addresses. Directory availability alone does not verify inference routing; a desktop follow-up confirmed the canonical Google route with a bounded real generation and an actual chat response.
|
|
109
|
-
|
|
110
|
-
The [pi-ai 1.2.0 changelog](https://github.com/earendil-works/pi/blob/v1.2.0/packages/ai/CHANGELOG.md) adds per-key OpenRouter catalogs and provider refresh base URLs, fixes Mistral stream timeouts, and retries Anthropic preferred strict-tool requests once without strict mode when grammar limits are exceeded. Its Google adapter is unchanged from 1.1.0 and still rejects custom fetch. Model/compatibility types now come from shared schema modules; the public declaration bundle must retain those definitions without leaking the private SDK alias.
|
|
111
|
-
|
|
112
|
-
DSH requests still convert through `toPiContext`, preserving the existing host input and durable replay contracts. Immediately before calling a provider directly, the adapter applies pi-ai's `normalizeContext`. In 1.1.0, direct providers require `TranscriptContext`; only `Models` streaming entry points normalize legacy Context automatically. Normalizing at this call site preserves the system prompt and tool declarations on both text and image paths without tying the SDK format to the DSH version.
|
|
113
|
-
|
|
114
|
-
This upgrade does not enable developer messages, tool-change blocks, or deferred tool loading. Their existing `UNSUPPORTED_CONTENT` errors remain explicit. The minimum DSH version and peer ranges stay unchanged; new host fixtures verify runtime compatibility rather than expanding the supported content vocabulary.
|
|
115
|
-
|
|
116
|
-
There is one explicit npm prerelease exception: DSH evaluates plugin ranges with prereleases included, whereas npm does not generally accept a future prerelease under `>=0.1.5-rc.1`. Only the tarball-install step uses `--legacy-peer-deps` after the host has passed strict installation. This is not a project `.npmrc` policy and does not affect root installs. The post-install version assertions ensure npm did not replace pinned host packages. Changing the plugin's published version policy is a separate decision.
|
|
24
|
+
| Test file | Coverage |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `plugin.spec.ts` | Cordis mounting/unloading, native SettingsForms/profile writes, hot configuration, RPC and public exports |
|
|
27
|
+
| `accounts.spec.ts` | Account CRUD, 20-account cap, serial writes, failed-write cleanup, fallback/promotion, stale calls and five-minute cooldown |
|
|
28
|
+
| `free.spec.ts` | Dual route lifecycle, public Bearer fallback, saved keys, account retry and credential deadlines |
|
|
29
|
+
| `free-channel.spec.ts`, `free-transport.spec.ts` | Free failure classification, Retry-After/backoff, cancellation, transport isolation and coexistence with Go |
|
|
30
|
+
| `pricing.spec.ts` | Catalog tariff validation and Free-model eligibility; historical amounts come from official CSV |
|
|
31
|
+
| `catalog.spec.ts` | Discovery, model limits/visibility, dual directories, ETag/disk cache, endpoint isolation and bounded transport |
|
|
32
|
+
| `adapter.spec.ts` | Requests, capacity limits, session/attribution headers, immutable request snapshots, cancellation and timeouts |
|
|
33
|
+
| `protocols.spec.ts` | Reasoning levels, protocol overrides, OpenAI/Anthropic/Google serialization and signed Google parts |
|
|
34
|
+
| `conversion.spec.ts` | Independent tool messages, replay signatures, context conversion, durable image offload, per-request budgets and stream contracts |
|
|
35
|
+
| `usage.spec.ts` | Official quota reads, current-account selection, native gateway access and safe error responses |
|
|
36
|
+
| `analytics.spec.ts` | Official daily CSV parsing/aggregation, UTC ranges, provider/model grouping, account isolation, short cache and cancellation |
|
|
37
|
+
| `transport.spec.ts` | Bounded JSON/gzip, classified/redacted HTTP errors, real CONNECT/SOCKS5 proxies and SDK bridge matching |
|
|
38
|
+
| `settings.client.spec.tsx` | Page configuration, typed Save/Reset/refused writes, locale changes, registration and subscription/cancellation lifecycle |
|
|
39
|
+
| `accounts-models.client.spec.tsx` | AccountsCard forms/status/quota, drag/keyboard ordering, model visibility, metadata failures and refresh races |
|
|
40
|
+
| `usage.client.spec.tsx` | Conversation pill, dashboard account/range controls, official amount presentation, quota refresh/visibility and accessibility |
|
|
41
|
+
|
|
42
|
+
All test imports target current modules directly. `vitest.config.ts` has no aliases or compatibility resolver. Its Google SDK loader is the same version-guarded transport patch used by the production build. The UI tests load the published DSH primitives and the installed locale bundle.
|
|
43
|
+
|
|
44
|
+
`tests/setup.ts` gives each test a temporary `DSH_HOME`, provides complete synthetic `/models` entries, allows loopback HTTP fixtures and explicit `.invalid` destinations through the local proxy fixture, and rejects other network requests. `tests/support/` provides current host/account services, ConfigForm/React fixtures, metadata data, loopback gateways and proxies. Fixtures clean up contexts, sockets, timers and temporary homes.
|
|
45
|
+
|
|
46
|
+
## Modules
|
|
47
|
+
|
|
48
|
+
Implementation modules are grouped by domain, with browser CSS and its ambient declaration:
|
|
49
|
+
|
|
50
|
+
| Domain | Modules |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Host composition and settings | `index.ts`, `config.ts` |
|
|
53
|
+
| Inference and model discovery | `adapter.ts`, `catalog.ts`, `conversion.ts`, `google.ts`, `sdk-types.ts` |
|
|
54
|
+
| Account commands and official quota | `accounts.ts` |
|
|
55
|
+
| Official daily CSV history and aggregation | `analytics.ts` |
|
|
56
|
+
| Free backoff, error classification and transport | `free-channel.ts`, `free-policy.ts`, `free-transport.ts` |
|
|
57
|
+
| Browser-safe configuration and RPC contracts | `contracts.ts` |
|
|
58
|
+
| HTTP, proxy transport and redacted errors | `transport.ts` |
|
|
59
|
+
| Browser registration and state | `client/index.ts`, `client/controller.ts` |
|
|
60
|
+
| UI and presentation | `client/Section.tsx`, `client/UsagePill.tsx`, `client/AnalyticsDialog.tsx`, `client/presentation.ts` |
|
|
117
61
|
|
|
118
|
-
|
|
62
|
+
The host uses `settings.configure()` and volatile configuration fields; the browser binds the official `configForms` contract. The page keeps text drafts until Save, model capacities stay typed objects throughout editing, and immediate switches retain their existing behavior. The accounts card owns all credential entry and replacement.
|
|
119
63
|
|
|
120
|
-
|
|
64
|
+
Account commands and automatic primary-account promotion share one in-memory serial queue. Credential writes settle before the next command starts. Metadata changes use a single revision-guarded write; no WAL, startup recovery or conflict retry loop is maintained. Only credentials owned by the removed generated account are deleted. Request generations prevent late fallback outcomes from replacing a newer user selection. Credential, quota and rate-limit failures can try the next account only before output or positive usage, and rejected gateway keys cool down for five minutes. Changing a key or explicitly selecting an account clears its rejection state.
|
|
121
65
|
|
|
122
|
-
|
|
66
|
+
Analytics requests `https://opencode.ai/console/api/v2/usage/export?range=7d|30d|90d` from the Host with the selected account's key. One daily CSV snapshot supplies totals, UTC daily buckets and provider/model detail. Today filters the 7-day snapshot to the current UTC date; absent dates are filled with zero. Input, output, cache read and both 5-minute/1-hour cache-write fields are summed without repricing. Integer `cost_micro_cents` use `1 USD = 100,000,000` units and are presented as the official usage amount, which does not establish extra Go charges.
|
|
123
67
|
|
|
124
|
-
|
|
68
|
+
History queries occur only on open, account/range changes and manual refresh. Official reports and CSVs have a 30-second Host cache isolated by credential, account, network configuration, range and UTC date; forced refresh bypasses it. Queries retain the configured proxy path, cancellation, timeouts and response-size limits. Only official gateway configurations may send keys to Console. Third-party gateways, permission failures, network failures and invalid data produce explicit errors, without a local-history fallback.
|
|
125
69
|
|
|
126
|
-
|
|
127
|
-
npm install --package-lock-only --ignore-scripts --strict-peer-deps
|
|
128
|
-
```
|
|
70
|
+
The browser receives only aggregate numbers and provider/model/day groups. The user's explicit CSV download may contain official member fields. The independent viewing-account selector defaults to the inference account and scopes all three dashboard quota windows to the selected workspace, including other clients; anonymous Free coverage is not guaranteed. Settings, the dashboard, pill and expanded sidebar share warm paper/charcoal surfaces and terracotta accents, following the Host's light/dark mode. Settings map Host control tokens only within the plugin section. Typography prefers locally installed Anthropic Serif Web, Sans Web and Mono Web families, with system fallbacks and CJK serif headings; no font binaries or external font requests are added.
|
|
129
71
|
|
|
130
|
-
|
|
72
|
+
Backend history tests use synthetic CSVs, synthetic keys and loopback services; real user keys are not used in automated tests. The separately recorded Console check establishes source availability for the checked account; automated migration results are recorded separately in the verification notes.
|
|
131
73
|
|
|
132
|
-
|
|
74
|
+
Image count limits are checked before reads. Each request prepares up to four images concurrently and checks its own encoded-payload budget. The host's `requiredImageOffload` / `projectOffloadedImages` protocol owns durable offload marks. There is no plugin-wide preparation queue or payload pool. HTTP failure classification, credential redaction, context-capacity hints, stream deadlines and cancellation remain active; internal call tracing and diagnostic file capture are removed.
|
|
133
75
|
|
|
134
|
-
|
|
76
|
+
## Distribution
|
|
135
77
|
|
|
136
|
-
|
|
78
|
+
The `.` and `./client` exports continue to point to the built host entry and browser factory. Rebuild `lib/` with source changes, then run `npm run check:dist`. Builds do not execute during dependency installation. The private `opencode-go-pi-ai` alias uses `@earendil-works/pi-ai@1.5.0`, which pins `@earendil-works/pi-telemetry@1.5.0` and `@earendil-works/pi-schema@1.5.0` exactly; `package.json` no longer needs `overrides`.
|
|
137
79
|
|
|
138
|
-
|
|
80
|
+
The Google transport bridge is version-guarded for pi-ai 1.5.0 and `@google/genai@2.21.0`. `src/google.ts` delegates simple streaming to the upstream adapter through the request-scoped fetch binding; pi-ai now selects discrete thinking levels for Gemini 4 natively.
|
|
139
81
|
|
|
140
|
-
|
|
82
|
+
SDK declarations bundle pi-schema in place of TypeBox. `scripts/licenses/pi-1.5.0-LICENSE` supplies the pi packages' upstream MIT license omitted from their npm distributions. pi-schema's format checks and value conversion rules include code adapted from TypeBox 1.3.27 (MIT); the build appends the package's `LICENSES/typebox-LICENSE` to its pi-schema notice in `lib/vendor-licenses.txt`.
|