dsh-opencode-go 0.1.21 → 0.1.22

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.
Files changed (48) hide show
  1. package/README.en.md +128 -167
  2. package/README.md +126 -158
  3. package/THIRD_PARTY_NOTICES.md +3 -1
  4. package/docs/development.md +56 -6
  5. package/docs/fork-review-2026-09-25.md +191 -0
  6. package/docs/independent-package.md +2 -2
  7. package/docs/verification.md +154 -0
  8. package/lib/build-info.json +8 -1
  9. package/lib/client.js +412 -262
  10. package/lib/index.js +6763 -428
  11. package/lib/types/account-manager.d.ts +23 -0
  12. package/lib/types/account-operations.d.ts +31 -0
  13. package/lib/types/account-policy.d.ts +16 -0
  14. package/lib/types/account-recovery.d.ts +2 -0
  15. package/lib/types/account-selection.d.ts +30 -0
  16. package/lib/types/account-service.d.ts +12 -0
  17. package/lib/types/accounts-contract.d.ts +38 -0
  18. package/lib/types/accounts.d.ts +5 -0
  19. package/lib/types/adapter.d.ts +30 -10
  20. package/lib/types/call-trace.d.ts +54 -0
  21. package/lib/types/catalog-manager.d.ts +20 -0
  22. package/lib/types/catalog.d.ts +5 -3
  23. package/lib/types/client/accounts-controller.d.ts +6 -17
  24. package/lib/types/client/host-compat.d.ts +7 -0
  25. package/lib/types/client/locales.d.ts +9 -0
  26. package/lib/types/client/section-controller.d.ts +11 -46
  27. package/lib/types/client/staged-form.d.ts +1 -3
  28. package/lib/types/client/usage.d.ts +1 -1
  29. package/lib/types/config-contract.d.ts +69 -0
  30. package/lib/types/config.d.ts +12 -53
  31. package/lib/types/conversion/context.d.ts +5 -1
  32. package/lib/types/conversion/image-pool.d.ts +24 -0
  33. package/lib/types/conversion/replay.d.ts +1 -1
  34. package/lib/types/conversion/stream.d.ts +1 -1
  35. package/lib/types/gateway-diagnostics.d.ts +22 -0
  36. package/lib/types/gateway-error.d.ts +2 -0
  37. package/lib/types/host-settings.d.ts +11 -0
  38. package/lib/types/index.d.ts +1 -1
  39. package/lib/types/model-metadata.d.ts +3 -1
  40. package/lib/types/models-contract.d.ts +7 -0
  41. package/lib/types/protocol-contract.d.ts +5 -0
  42. package/lib/types/protocol-policy.d.ts +4 -0
  43. package/lib/types/reasoning.d.ts +36 -6
  44. package/lib/types/request-control.d.ts +2 -0
  45. package/lib/types/sdk-types.d.ts +1568 -0
  46. package/lib/types/settings-bridge.d.ts +22 -0
  47. package/lib/vendor-licenses.txt +103 -0
  48. package/package.json +6 -2
package/README.md CHANGED
@@ -2,246 +2,214 @@
2
2
 
3
3
  [English](README.en.md)
4
4
 
5
- 功能:让你在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 中完美使用 OpenCode Go 订阅模型,支持流式回复、工具调用和图片输入。
5
+ 在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 中使用 OpenCode Go 订阅模型,支持流式回复、思考模式、工具调用和图片输入。插件自动同步模型列表与容量信息,并提供多账号管理、订阅用量显示和网络代理设置。
6
6
 
7
- 插件会自动添加 OpenCode Go 所需的会话请求头、读取网关模型目录,并显示订阅用量,无需给模型配置协议、模态、上下文长度、最大输出token
7
+ 适用于 DSH `0.1.5-rc.1` 及以上版本。
8
8
 
9
- ## 功能说明
9
+ 安装兼容性已覆盖十个宿主版本,从 `0.1.5-rc.1` 到 `0.2.1-alpha.1`,具体版本见[兼容矩阵](docs/development.md#installed-package-matrix)。后续宿主版本仍需验证;目前会明确拒绝 developer 消息、动态工具增删和延迟工具加载。
10
10
 
11
- - **会话请求头**:每次请求包含 Harness User-Agent 和 `x-opencode-session`。同一会话保持稳定 ID,支持网关路由和提示词缓存优化;实际命中率取决于上游服务。
12
- - **流式与历史**:支持流式输出、工具调用及历史回放,协议请求由 pi-ai 执行。
13
- - **图片输入**:支持目录中声明图片能力的模型。
14
- - **模型容量覆盖**:可按模型覆盖上下文窗口和最大输出,空值继承在线目录。
15
- - **逐模型开关**:每个模型独立控制会话中的显示状态,修改立即生效;普通模型默认开启,过时模型默认关闭,也可单独开启。
16
- - **网络代理**:在设置页配置 HTTP(S) 或 SOCKS5 代理,统一用于对话、模型目录更新与订阅用量查询。
17
- - **提示与缓存**:插件不增加隐藏系统提示;会话 ID 用于网关路由。
11
+ ## 安装
18
12
 
19
- ## 安装与使用
13
+ ### 在 DSH 中安装
20
14
 
21
- 支持 DSH `0.1.5-rc.1` 及以上版本,包括 alpha、rc 和正式版,并持续跟随宿主版本更新维护兼容性。
22
-
23
- 已验证版本:`0.1.5-rc.1`、`0.1.5-rc.2`、`0.1.6-alpha.1`、`0.1.6-alpha.2`、`0.1.7-alpha.1`、`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.2` 和 `0.2.1-alpha.1`。
24
-
25
- ### 在 DSH 中安装(推荐)
26
-
27
- 1. 打开 DSH 的 **插件** 页面,点击右上角 **添加插件**。
15
+ 1. 打开 **插件 → 添加插件**。
28
16
  2. 输入 `dsh-opencode-go`,点击 **安装**。
29
- 3. 安装成功后,如果出现 **立即启用**,点击即可。
17
+ 3. 安装完成后点击 **立即启用**。
30
18
 
31
- ![在 DSH 插件页添加、安装并启用 dsh-opencode-go](docs/assets/install-via-dsh.gif)
19
+ ![在 DSH 中安装插件](docs/assets/install-via-dsh.gif)
32
20
 
33
- 然后打开 **设置 → OpenCode Go**,填入 API Key 并保存,或在「账号」中添加账号,即可在会话中选择 OpenCode Go 模型。
34
-
35
- 也支持在添加插件时直接输入 Git 仓库地址:
21
+ 也可以在添加插件时输入 Git 仓库地址:
36
22
 
37
23
  ```text
38
24
  https://github.com/Duskriver/dsh-opencode-go
39
25
  ```
40
26
 
41
- 当前主分支附带编译好的插件,安装时无需本地构建,也无需为本插件修改 `allowBuilds`。固定到旧提交的 Git 地址仍沿用旧提交的安装方式,请更新到当前主分支。
42
-
43
- 若当前 DSH 没有「添加插件」入口,可使用下面的命令行方式。
44
-
45
- ### 命令行安装(备选)
27
+ ### 命令行安装
46
28
 
47
29
  ```sh
48
30
  dsh plugin --profile web add dsh-opencode-go
49
31
  ```
50
32
 
51
- 安装后启动或重启 `dsh web`,然后:
33
+ 安装后启动或重启 `dsh web`。Web 和 Headless 使用各自的 profile,分别安装和更新。
52
34
 
53
- 1. 打开 **设置 → OpenCode Go**。
54
- 2. 填入 OpenCode Go API Key 并保存。
55
- 3. 在会话的模型选择器中选择 OpenCode Go 模型。
35
+ ## 开始使用
56
36
 
57
- ### 无头模式
37
+ 1. 打开 **设置 → OpenCode Go**,填入 API Key 并保存,或在「账号」中添加账号。
38
+ 2. 在会话模型选择器中选择 **DSH OpenCode Go** 下的模型。
39
+ 3. 开始对话;支持思考的模型可选择其提供的思考档位,支持图片的模型可直接接收图片。
58
40
 
59
- 安装到 Headless profile:
41
+ 在设置页刷新模型列表即可同步最新目录。每个模型旁的开关控制它是否出现在选择器中,修改后立即生效。模型的上下文窗口和最大输出默认使用目录配置,也可逐个修改并保存。
60
42
 
61
- ```sh
62
- dsh plugin --profile headless add dsh-opencode-go
63
- ```
43
+ 思考选项中的 **默认** 使用服务商设置;**Off** 明确关闭思考。只有开关的模型显示 **On / Off**,支持强度的模型显示其可用档位,预算式模型显示具体的 token 数值。
64
44
 
65
- 将以下内容保存为 `headless.patch.yml`,选择默认模型:
45
+ 预算式模型提供 1,024 / 2,048 / 8,192 / 16,384 tokens 等常用选项。在设置页选择模型,展开“思考预算”,输入数值、点击“添加”并保存,即可在会话中选择自定义预算。可用范围随模型而定;SDK 会根据剩余输出空间缩小实际预算。
66
46
 
67
- ```yaml
68
- - id: agent-default-model
69
- config:
70
- provider: dsh-opencode-go
71
- model: deepseek-v4.1-flash
72
- ```
47
+ 插件跟随 DSH 的界面语言,支持中文和英文。
73
48
 
74
- 在 Bash 或 Zsh 中读取 API Key,然后运行任务:
49
+ ### 查看订阅用量
75
50
 
76
- ```sh
77
- read -s OPENCODE_API_KEY
78
- export OPENCODE_API_KEY
79
- dsh --profile headless --patch ./headless.patch.yml "你好"
80
- ```
51
+ 点击会话输入区旁的用量胶囊,查看当前账号的 5 小时、周和月用量及重置时间。用量每分钟刷新,也可手动刷新。
81
52
 
82
- 模型 ID 须在当前网关目录中可用。Web 和 Headless 使用各自的 profile,需要分别安装插件。
53
+ 在 **高级设置 → 额度显示** 中选择:
83
54
 
84
- 如需从源码构建并安装本地包:
55
+ - **自动**:使用本插件的模型时显示,默认选项。
56
+ - **常驻**:使用其他模型时也显示。
57
+ - **关闭**:隐藏用量显示并停止轮询。
85
58
 
86
- ```sh
87
- npm ci
88
- npm run compile
89
- npm pack
90
- dsh plugin --profile web add ./dsh-opencode-go-0.1.21.tgz
91
- ```
59
+ ![订阅用量](image.png)
92
60
 
93
- 源码开发时显式运行 `npm run compile`;普通用户直接安装预编译产物,无需 `--legacy-peer-deps`。多版本 DSH 兼容性测试使用独立环境,不参与普通安装或构建。Headless 用户将 `web` 换成 `headless`。
61
+ ### 管理多个账号
94
62
 
95
- ### 开发与验证
63
+ 在「账号」中添加、重命名或更换 Key,展开账号行可查看详细用量。拖动行首手柄调整顺序,第一行成为当前账号。
96
64
 
97
- ```sh
98
- npm run compile # 更新 lib/,与源码一起提交
99
- npm test # 基础功能测试(自动重新构建)
100
- npm run check:dist # 检查已提交产物是否与源码一致
101
- npm run test:compat # 同一安装包在 9 套独立 DSH 环境中测试
102
- npm run test:install # npm / pnpm 无额外构建授权的 Git 安装检查
103
- npm run verify # 执行以上全部检查
104
- ```
65
+ 开启 **自动切换** 后,当前账号额度耗尽或 Key 不可用时,插件会在开始输出前按列表顺序尝试其他账号。也可以在用量胶囊中点击 **切换**,直接选择后续请求使用的账号。
66
+
67
+ 新增或删除账号中途关闭页面、断开连接时,宿主会在后续启动或设置、凭据更新时继续恢复。未能写入 Key 的新增账号会保留在列表,可补填 Key 或删除;恢复不会覆盖期间手动选择的当前账号。
105
68
 
106
- 兼容性与安装检查会下载依赖,使用系统临时目录并在结束后清理。只检查一个宿主可运行 `npm run test:compat -- v017-rc2`。维护测试版本的方式见[开发与测试说明](docs/development.md)。
69
+ ## 高级用法
107
70
 
108
- ## 升级插件
71
+ ### Headless 模式
109
72
 
110
- 更新 Web profile 中的插件到 npm 最新版本:
73
+ 安装插件:
111
74
 
112
75
  ```sh
113
- dsh plugin --profile web update dsh-opencode-go --latest
76
+ dsh plugin --profile headless add dsh-opencode-go
114
77
  ```
115
78
 
116
- 完成后重启 `dsh web` 并刷新浏览器。Headless 用户将 `web` 换成 `headless`;如果两个 profile 都安装了插件,需要分别升级。
117
-
118
- 桌面版升级后,请完全退出并重新打开 DeepSeek Harness,以加载更新后的插件代码。
119
-
120
-
121
-
122
- Headless 或手动配置可在插件的 `config` 中填写:
79
+ 将以下内容保存为 `headless.patch.yml`:
123
80
 
124
81
  ```yaml
125
- apiKeyEnv: OPENCODE_API_KEY
126
- accounts:
127
- - id: primary
128
- name: 主账号
129
- apiKeyEnv: OPENCODE_API_KEY
130
- - id: backup
131
- name: 备用账号
132
- apiKeyEnv: OPENCODE_GO_BACKUP_KEY
133
- autoSwitch: false
82
+ - id: agent-default-model
83
+ config:
84
+ provider: dsh-opencode-go
85
+ model: deepseek-v4.1-flash
134
86
  ```
135
87
 
136
- 分别通过凭据服务或环境变量提供两个引用的 Key。`apiKeyEnv` 指向首选账号;省略 `accounts` 保留旧版单 Key 行为,`accounts: []` 表示已移除全部账号。
88
+ 在 Bash 或 Zsh 中输入 Key 后运行任务:
137
89
 
138
- 「账号」卡片默认可收起:折叠时显示账号数量、首选账号、可用数量与统一的刷新时间(当天只显示时刻,悬停给出完整日期时间)。展开后每个账号占一行,行内显示 Key 状态、加粗的 5 小时额度条(12px 通栏,25%/50%/75% 刻度,≥80% 转琥珀、满额转红)与重置倒计时;各列位置固定(手柄 / 名称 / Key 状态 / 额度条 / 百分比 / 重置倒计时 / 详情箭头),账号名过长时省略并悬停显示全名,因此不同长度的账号名不会挪动后面的列;点开行尾箭头可查看周/月额度,以及重命名、替换 Key、删除操作。按住行首手柄上下拖动(或聚焦手柄后按 ↑ / ↓)即可调整顺序,**从上到下依次尝试**:第一行即首选账号,松手后它同时成为新的首选;自动回退开启时按同一顺序尝试其他账号。
90
+ ```sh
91
+ read -s OPENCODE_API_KEY
92
+ export OPENCODE_API_KEY
93
+ dsh --profile headless --patch ./headless.patch.yml "你好"
94
+ ```
95
+
96
+ 将 `model` 换成设置页中可用的模型 ID。示例文件见 [examples/headless.patch.yml](examples/headless.patch.yml)。
139
97
 
140
- ## 网络代理
98
+ ### 网络代理
141
99
 
142
- 打开 **设置 → OpenCode Go → 高级设置 → 代理地址**,填写代理 URL 后点击 **保存**。例如:
100
+ 在 **设置 → OpenCode Go → 高级设置 → 代理地址** 中填写并保存,例如:
143
101
 
144
102
  ```text
145
103
  http://127.0.0.1:7890
146
104
  socks5://127.0.0.1:1080
147
105
  ```
148
106
 
149
- 也支持 HTTPS 代理,以及 `http://用户名:密码@主机:端口`、`socks5://用户名:密码@主机:端口` 形式的认证代理;用户名和密码中的特殊字符需要 URL 编码。
150
-
151
- 保存后,后续对话、模型列表、模型元数据下载和用量查询立即使用新代理,无需重启。清空地址并保存使用默认网络设置;「重置」恢复配置中继承的值。代理连接失败会报告错误,不会自动改为直连。
152
-
153
- 代理连接由运行 DSH 的机器发起。若 DSH 部署在服务器上,`127.0.0.1` 指服务器自身。无头模式也可以在插件配置中设置 `proxyURL`。
107
+ 支持 HTTP、HTTPS、SOCKS5 和带用户名、密码的代理 URL。保存后,后续对话、模型目录更新和用量查询使用新代理。代理运行在 DSH 所在的机器上;远程部署中的 `127.0.0.1` 指服务器自身。
154
108
 
155
- ## 订阅用量显示
109
+ ### 手动配置
156
110
 
157
- 在「设置 → OpenCode Go → 高级设置 → 额度显示」中选择并保存:**自动(默认)**仅在选中本插件的 DSH OpenCode Go 模型时显示;**常驻**在使用其他模型(包括宿主自带的 `opencode-go`)时也显示;**关闭**隐藏胶囊并停止轮询。停用 OpenCode Go 后所有模式均隐藏。显示时点击胶囊展开用量面板:首行是当前使用的账号(状态点 + 名称 + 首选标签 + 「切换」),点「切换」后卡片内容变为账号列表(当前账号带勾,↑ / ↓ 或点击选择,Esc 返回额度视图);这里切换的是"现在用哪个账号的额度",额度消耗顺序仍由设置页那列顺序决定。三个窗口各占一行(名称、进度条、百分比),重置时间在下方,刷新时间在卡片底部。
111
+ 在 **高级设置 → DeepSeek V4.1 Flash 协议** 中可选择 **Responses(实验性)** 并保存,便于比较同一模型的不同协议。默认 **自动** 跟随模型目录;改回自动即可恢复。选择只影响新请求,不会切换已准备或正在执行的调用,也不会在协议错误后自动改用另一协议。
158
112
 
159
- 用量每分钟刷新。临时网络或服务错误会保留同一账号的上次数据,并标明刷新失败、更新时间和错误原因;可在用量弹层中立即重试。首次获取失败或鉴权失败时不显示旧额度。模型目录、模型配置和用量的 JSON 请求遇到短暂连接重置时会在原有超时范围内额外重试一次;这不能保证故障中的网络恢复可用。
160
-
161
- ![OpenCode Go usage display](image.png)
162
-
163
- ## 界面语言
164
-
165
- 插件跟随 Harness 的界面语言,提供中文和英文文案,不另存一套语言设置。未手动指定语言时,Web 版按浏览器语言列表匹配中英文(浏览器通常跟随系统);支持系统语言桥接的桌面版由宿主提供系统语言。没有匹配的语言时使用英文。
166
-
167
- 在 Harness 中手动选择的语言优先,切换后插件即时更新,保留未保存的表单内容。模型名称和 ID 保留原名;用量日期和容量数字按当前界面语言格式化。自动语言在启动时识别:Web 版更改浏览器语言后需刷新页面,桌面版更改系统语言后需重启 Harness。
168
-
169
- ## 模型开关
170
-
171
- 在 **设置 → OpenCode Go** 中,每个模型右侧的开关决定它是否出现在会话模型选择器中。开关立即保存,无需再点“保存”;容量和 API Key 的修改仍需保存。普通模型默认开启,过时模型默认关闭。你可以单独开启任意过时模型,也可以关闭普通模型。新出现且未单独配置的模型同样按此规则处理。
172
-
173
- 手动配置时,在插件的 `config` 下添加 `modelVisibility`,使用真实模型 ID 替换示例中的占位符:
113
+ 目前仅支持 `deepseek-v4.1-flash` 的 Responses 覆盖,沿用当前账号、代理、会话标识与用量处理。[issue #45](https://github.com/Duskriver/dsh-opencode-go/issues/45) 报告了更低延迟,但它不是网关的稳定性能承诺,也不能据此确认底层服务商;是否更快请以自己的测试为准。无需覆盖时省略以下配置:
174
114
 
175
115
  ```yaml
176
- modelVisibility:
177
- your-model-id: false
178
- your-deprecated-model-id: true
116
+ - id: opencode-go
117
+ config:
118
+ protocolOverrides:
119
+ deepseek-v4.1-flash: openai-responses
179
120
  ```
180
121
 
181
- 只有列出的 ID 被显式覆盖。开关只影响模型选择器;已有会话仍可调用网关提供的隐藏模型,设置页也保留完整模型列表。
182
-
183
- 旧配置中的 `showDeprecatedModels` 和 `visibleModelIds` 不再控制显示状态。请使用逐模型开关或 `modelVisibility`;旧字段可以保留,不会妨碍插件加载。
122
+ 将该模型的值设为 `null` 会明确选择自动,即使继承的配置启用了 Responses;设置页的「恢复默认」会移除当前层覆盖,恢复继承值。其他模型或协议组合会被拒绝。
184
123
 
185
- ## 图片数量上限
124
+ 在 patch 文件中添加 `opencode-go` 配置块,可与上面的默认模型配置一起使用:
186
125
 
187
- 在「设置 → OpenCode Go → 高级设置」中可以设置 `maxImages`,填写正整数后保存即可生效,无需重启。默认不设置,不限制图片张数;清空或重置会移除用户覆盖,重新继承基础配置(基础配置也未设置时没有张数上限)。
188
-
189
- 数量按单次请求携带的完整历史统计,包括工具输出里的图片;同一附件出现多次也分别计数。例如设置为 `30` 时,30 张正常发送,31 张会先卸载最旧的 1 张,再继续请求。卸载将图片内容替换为文字占位,原始附件仍保留,但模型在该次请求中看不到被卸载图片的内容。
190
-
191
- DSH 0.1.5 的卸载只影响本次请求;DSH 0.1.6 及以上版本通过宿主的图片卸载机制记录卸载状态并重试,调高或清空上限不会自动恢复已卸载的历史图片。现有图片载荷、像素和单图字节预算仍独立生效,可能需要卸载更多图片。`maxImages` 是可选的兼容设置,不会改变上游服务自身的限制。
192
-
193
- ## 常见问题
194
-
195
- ### 与宿主的 OpenCode Go 共存及升级迁移
196
-
197
- 从 0.1.17 起使用独立的 `dsh-opencode-go` provider,模型选择器中显示为 **DSH OpenCode Go**;宿主 pi-ai 的 `opencode-go` 可以同时使用。请在插件设置页配置 API Key,然后选择 **DSH OpenCode Go** 下的模型。0.1.16 及以前版本使用 `opencode-go`,这些版本的 headless 配置也应使用旧标识。
198
-
199
- 升级前保存为 `provider: opencode-go` 的会话、Agent 预设和 headless 默认模型,需要重新选择 **DSH OpenCode Go**,或将 provider 改为 `dsh-opencode-go`。API Key、模型设置和元数据缓存继续沿用。旧会话内容保留;跨 provider 切换时,DSH 会按其规则去除旧适配器的专用回放元数据。
126
+ ```yaml
127
+ - id: opencode-go
128
+ config:
129
+ apiKeyEnv: OPENCODE_API_KEY
130
+ accounts:
131
+ - id: primary
132
+ name: 主账号
133
+ apiKeyEnv: OPENCODE_API_KEY
134
+ - id: backup
135
+ name: 备用账号
136
+ apiKeyEnv: OPENCODE_GO_BACKUP_KEY
137
+ autoSwitch: true
138
+ proxyURL: http://127.0.0.1:7890
139
+ refreshMinutes: 60
140
+ modelVisibility:
141
+ deepseek-v4-pro: false
142
+ modelLimits:
143
+ deepseek-v4.1-flash:
144
+ maxTokens: 8192
145
+ qwen3.7-plus:
146
+ thinkingBudgets: [4096, 6000]
147
+ maxImages: 30
148
+ ```
200
149
 
201
- ### 没有出现预期的模型
150
+ 按需保留配置项,并通过 DSH 凭据服务或环境变量提供对应的 Key。`apiKeyEnv` 选择当前账号,`accounts` 的顺序决定自动切换顺序。
202
151
 
203
- 先在 **设置 → OpenCode Go** 检查该模型的开关是否开启。过时模型默认关闭,单独打开它的开关后即可出现在会话模型选择器中,无需开启其他全局选项。
152
+ | 配置项 | 用途 |
153
+ | --- | --- |
154
+ | `baseURL` | OpenCode Go 网关地址,默认 `https://opencode.ai/zen/go/v1` |
155
+ | `usageDisplay` | 额度显示模式:`auto`、`always` 或 `off` |
156
+ | `proxyURL` | 网络代理;空字符串使用默认网络设置 |
157
+ | `refreshMinutes` | 模型目录缓存时长,默认 60 分钟;设置页可随时手动刷新 |
158
+ | `modelVisibility` | 按模型 ID 控制选择器中的显示状态 |
159
+ | `protocolOverrides` | 实验性协议覆盖;目前仅支持 `deepseek-v4.1-flash: openai-responses`,省略或模型值为 `null` 时自动跟随目录 |
160
+ | `modelLimits` | 按模型覆盖 `contextWindow`、`maxTokens`,或用 `thinkingBudgets` 添加思考预算选项;空值使用默认设置 |
161
+ | `maxImages` | 单次请求历史中的图片数量上限,默认不设上限;超过时先卸载最旧图片 |
162
+ | `streamIdleTimeoutMs` | 等待下一个流事件的最长时间,默认 300000 毫秒 |
163
+ | `requestPreparationTimeoutMs` | 目录查询及每次尝试的凭据、图片准备时限,默认 60000 毫秒 |
164
+ | `requestTimeoutMs` | 一次发送的完整时限,包含目录查询、账号切换和流式输出,默认 1800000 毫秒;预先准备的调用从发送时计时 |
204
165
 
205
- 先确认插件已启用且 API Key 已配置,再刷新设置页中的模型列表。设置页读取或刷新列表时会请求网关 `/models`,并同步 [models.dev 的 OpenCode Go 配置](https://models.dev/api.json)。会话模型选择器遵守目录缓存时长,切换模型开关不会强制重新请求网关。模型的协议、上下文长度、输出上限和图片能力来自在线配置,新模型无需等待本插件或 pi-ai 发布新版本。
166
+ 图片卸载会保留原始附件,并将请求中的旧图片替换为文字占位;调高上限不会自动恢复已卸载的历史图片。
206
167
 
207
- 网关和在线配置已收录、且使用 Anthropic Messages、OpenAI Chat Completions 或 OpenAI Responses 协议的新模型,在下次设置页刷新或目录缓存到期后即可被发现。设置页刷新会绕过已有缓存,并通知已打开的会话模型选择器使用同一份新目录;直接请求尚未缓存的新模型也会立即重新同步。设置页显示完整模型列表。
168
+ 图片数量超限会在读取附件前返回卸载请求;图片准备在同一插件模块内共享四个执行名额和最多 32 个等待名额,精确字节超限时停止安排剩余图片。正在发送的图片请求共享 128 MiB 的已准备原始数据与 base64 预算;这不是进程总内存上限。排队或共享预算超限会返回 `IMAGE_RESOURCE_BUSY`,可在其他请求结束后重试。数量与字节限制可能需要宿主分次卸载后重试。
208
169
 
209
- 网关已公布 ID 但尚无有效协议/能力配置的模型会在设置页标注“配置缺失”,开关保持关闭且不可操作,不进入对话模型选择器,避免一个未配置的模型阻断整个列表;直接调用时会说明原因。配置补齐后,刷新列表即可使用。仅凭模型 ID 无法可靠推断调用方式。上游新增全新协议或协议特例时,仍可能需要适配。
170
+ 首次查询目录失败会报告 `DISCOVERY_FAILED`;已有目录时保留之前确认过的模型。网关明确返回空列表才会清空目录。列表中仅部分行格式错误时,仍可使用有效模型,设置页与日志会提示被忽略的行数。高级表单的普通配置项一次提交并检查版本;凭据由独立服务保存,凭据保存失败时保留其草稿,重试只提交未成功的部分。
210
171
 
211
- 如果在线配置获取失败,没有可用缓存或内置配置的模型会标注“配置暂不可用”,页面会显示配置源错误。请检查运行 DSH 的设备能否访问 `https://models.dev/api.json`,并查看具体错误后刷新重试。已有模型列表在重试期间保留上次的失败提示,成功后自动清除;已配置的模型继续可用。
172
+ ### 导出错误诊断
212
173
 
213
- 模型具有推理能力但没有可调节的推理档位时(如 `union-alpha`),仍可正常选择和使用,只是不显示推理强度选项。
174
+ 需要排查请求失败时,在启动 DSH 前设置诊断目录:
214
175
 
215
- MiMo V2.6 Flash 的网关目录尚未列出可调节档位,插件按 OpenCode Go 实测提供 **Off / Low / Medium / High**:默认不发送 `reasoning_effort`,保留网关默认思考;Off 发送 `none`,其余发送对应值。仅对这个已验证的型号和协议补充映射,不扩展到其他 MiMo 型号。Low / Medium / High 已验证可正常请求并返回思考内容,但不保证实际思考量随档位递增。
176
+ ```sh
177
+ export DSH_OPENCODE_GO_DEBUG_DIR=/tmp/dsh-opencode-go-debug
178
+ dsh web
179
+ ```
216
180
 
217
- 在线目录中的 effort 列表决定可选强度。仅有 toggle 或 budget 声明时,插件只对已有原生开关或预算协议提供相应控件,不为普通 OpenAI 兼容协议猜测 `off` 或 `high` 参数。明确的空控制列表不会因为模型具有推理能力就自动增加 Off。
181
+ Windows PowerShell:
218
182
 
219
- 提供可调节档位的模型,如果其传输协议在未选择档位时会显式关闭思考(`deepseek`、`zai`、`qwen`、`qwen-chat-template`),还会声明一个默认档位(模型支持 `high` 时用 `high`,否则用它提供的最高档位)。用户未选择档位时 DSH 使用该默认值,因此留空也会带上推理档位,而不是关闭思考。由服务商自行决定的协议不声明默认值,行为不变;显式选择的档位始终优先。
183
+ ```powershell
184
+ $env:DSH_OPENCODE_GO_DEBUG_DIR = "$env:TEMP\dsh-opencode-go-debug"
185
+ dsh web
186
+ ```
220
187
 
221
- 在线配置暂时不可达时,优先复用之前成功获取的配置(包括重启前的磁盘缓存),以 pi-ai 内置配置作为备用。网关目录刷新失败时,已有请求和设置页均保留本次运行中上次成功获取的列表。任一来源刷新失败,设置页都会显示警告、失败原因,以及模型名单和模型配置各自上次成功检查的时间。首次读取网关失败时,不会仅凭元数据缓存生成模型列表。
188
+ 复现后,错误信息会给出 JSON 文件路径。记录包含模型、请求参数摘要、HTTP 状态、上游日志与路由编号及错误响应,便于提交 [问题反馈](https://github.com/Duskriver/dsh-opencode-go/issues)。分享前检查服务返回的错误内容;清空环境变量并重启 DSH 即可关闭诊断。
222
189
 
223
- 模型配置自动保存到 `$DSH_HOME/cache/dsh-opencode-go/models.dev.api.json`,未设置 `DSH_HOME` 时位于 `~/.dsh/cache/dsh-opencode-go/models.dev.api.json`。缓存仅包含公共元数据、ETag 和上次成功检查时间,不包含 API Key 或网关模型名单。重启后的普通读取先确认网关名单,再使用磁盘中的配置,同时后台校验元数据;后台完成后同步模型选择器。缓存损坏时重新联网获取,无法写入时仍可使用在线结果。设置页刷新始终等待在线校验,失败会保留旧配置并显示原因,不会把缓存命中标记为在线刷新成功。需要清除磁盘缓存时,可退出 DSH 后删除该文件。
190
+ DSH debug 日志另有每次发送的调用编号,以及各次尝试的阶段耗时、HTTP 状态、上游请求编号、首次输出等待时间与错误码,包含 HTTP 200 后的流中断;图片请求还记录排队累计等待与资源占用峰值。错误文件带有相同调用编号与尝试序号,便于关联排查。这些摘要不记录提示词、Key、代理地址或原始会话编号。
224
191
 
225
- `refreshMinutes` 控制成功刷新后的目录缓存时长。刷新失败后,下一次读取会按 5、10、20、40、60 秒的退避间隔尝试恢复,最长等待间隔为 60 秒;没有读取时不会后台轮询。设置页主动刷新和未知模型的即时发现不受这个间隔限制。取消模型解析或生成时,会立即结束当前调用的目录等待,其他调用仍可继续使用同一次共享刷新。
192
+ ## 更新与卸载
226
193
 
227
- 已验证的模型配置在缓存到期后的 5 分钟内可直接用于生成,同时触发一次共享后台刷新。这个窗口按两种来源各自上次成功检查的时间计算,失败重试不会延长它;超过窗口后,请求等待下一次到期刷新,刷新仍失败时保留已有回退行为。没有磁盘缓存的首次加载、未知模型和手动刷新会等待在线结果。模型名单请求限时 10 秒,体积更大的模型配置下载单独限时 30 秒,并协商 gzip 压缩以减少慢速连接的传输量。若宿主因 HTTP/2 兼容问题返回未解压的 gzip 数据,插件会在同一超时预算内异步解压,原始数据和解压结果均受 16 MiB 限制。模型名单和用量接口继续使用非压缩传输。
194
+ 更新到 npm 最新版本:
228
195
 
229
- 同一会话继续、重试以及恢复后的请求沿用宿主保存的会话 ID。分叉和子会话使用各自的 ID,不复用父会话标识;没有会话 ID 的独立请求每次生成随机标识。
196
+ ```sh
197
+ dsh plugin --profile web update dsh-opencode-go --latest
198
+ ```
230
199
 
231
- ## 卸载
200
+ 更新后重启 `dsh web` 并刷新页面;桌面版完全退出后重新打开。Headless 用户将 `web` 换成 `headless`。
232
201
 
233
- 从对应 profile 移除插件,再重启应用:
202
+ 卸载:
234
203
 
235
204
  ```sh
236
205
  dsh plugin --profile web remove dsh-opencode-go
237
- # 或
238
- dsh plugin --profile headless remove dsh-opencode-go
239
206
  ```
240
207
 
241
- ## 反馈
242
-
243
- 遇到 bug 或有功能建议请提 issue。
208
+ 从 `0.1.16` 及更早版本升级时,在旧会话或 Agent 预设中重新选择 **DSH OpenCode Go**;手动配置使用 `provider: dsh-opencode-go`。
244
209
 
245
- ## 许可证
210
+ ## 更多
246
211
 
247
- [MIT](LICENSE)
212
+ - [开发与测试](docs/development.md)
213
+ - [验证记录](docs/verification.md)
214
+ - [问题与建议](https://github.com/Duskriver/dsh-opencode-go/issues)
215
+ - [MIT 许可证](LICENSE)
@@ -1,5 +1,7 @@
1
1
  # Third-party notices
2
2
 
3
- The adapter, settings UI, and `src/conversion/{context,stream,replay}.ts` derive from DeepSeek Harness, copyright (c) 2026 DeepSeek, under the MIT license included in LICENSE. The conversion modules are maintained in this package because the published DSH pi-ai package does not export its conversion helpers. Wire protocol implementations remain supplied by `@earendil-works/pi-ai`, installed under the plugin's `opencode-go-pi-ai` npm alias.
3
+ The adapter, settings UI, and `src/conversion/{context,stream,replay}.ts` derive from DeepSeek Harness, copyright (c) 2026 DeepSeek, under the MIT license included in LICENSE. The conversion modules are maintained in this package because the published DSH pi-ai package does not export its conversion helpers.
4
+
5
+ The host bundle includes the required portions of `@earendil-works/pi-ai@1.1.0` and `partial-json`; SDK declarations include pi-ai, pi-telemetry and TypeBox types. Their original MIT licenses are reproduced in `lib/vendor-licenses.txt`. The pi packages' license comes from the [upstream v1.1.0 license](https://github.com/earendil-works/pi/blob/v1.1.0/LICENSE), which their npm distributions omit. OpenAI and Anthropic transport SDKs remain separate runtime dependencies.
4
6
 
5
7
  The GitHub icon in the settings footer comes from Simple Icons, distributed under CC0 1.0 Universal.
@@ -13,9 +13,9 @@ The root package contains one coherent DSH 0.1.6-alpha.1 development environment
13
13
  | `npm test` | Rebuild, then run the core Vitest suite |
14
14
  | `npm run test:compat` | Pack once and test the installed artifact across every supported host fixture |
15
15
  | `npm run test:compat -- v015-rc1 v017-rc2 v021-alpha1` | Test only the named fixtures; unknown names fail |
16
- | `npm run test:install` | Test npm and pnpm 11.7.0 Git installs of prebuilt artifacts without plugin build approval |
16
+ | `npm run test:install` | Test npm Git installation and fresh pnpm 11.7.0 Git/tarball installs with no script approvals, plus consumer type resolution |
17
17
  | `npm run test:install -- npm` / `-- pnpm` | Run just one package manager; unknown names fail |
18
- | `npm run verify` | Run core, compatibility, and Git-installation checks |
18
+ | `npm run verify` | Run core, compatibility, and installation checks |
19
19
 
20
20
  The checks use loopback gateways and local fixtures, not paid inference or an installed user profile. Compatibility and installation checks need registry access; installation checks also require Git. Temporary consumers are created outside the repository and removed on success or failure. Tests never implicitly skip a missing host environment.
21
21
 
@@ -25,7 +25,7 @@ The default Git branch ships `lib/` so a GitHub URL, an npm release, and an npm
25
25
 
26
26
  After source or build-tool changes, run `npm run compile` and commit the regenerated `lib/` with those changes. `npm run check:dist` checks missing, changed, and extra artifacts against an independent rebuild. CI uses `npm run test:ci` so it checks the committed files before running tests, instead of silently replacing stale files first. CSS module filenames are repository-relative, CSS export keys are sorted, and declaration line endings are fixed to LF so artifacts are independent of the checkout path and operating system.
27
27
 
28
- The Git-installation regression creates a fresh repository containing the shipped artifacts but no `src/`, `scripts/`, `tests/`, or `node_modules/`, then installs it with both package managers. Each installed package must expose its host and client entrypoints, declarations, build metadata, and importable host module, and must not declare scripts that trigger Git preparation or dependency installation hooks. pnpm receives no approval for this plugin; only unrelated Google/protobuf scripts are explicitly skipped. The cold Git identity changes for each temporary repository, preventing a previously approved Git build from hiding a missing approval. Consumer profiles and their trust settings are never modified by these tests.
28
+ The installation regression creates a fresh repository containing the shipped artifacts but no `src/`, `scripts/`, `tests/`, or `node_modules/`, then installs it with both package managers. Each installed package must expose its host and client entrypoints, declarations, build metadata, and importable host module, and must not declare scripts that trigger Git preparation or dependency installation hooks. Fresh pnpm consumers install both the Git artifact and a packed npm artifact with `strictDepBuilds=true`, separate empty stores and isolated user configuration. They receive no `allowBuilds` entries, including Google/protobuf skips. The fixtures assert that the private SDK alias, Google SDK and protobufjs are absent, and type-check exported model types without access to development dependencies. The cold Git identity changes for each temporary repository. Consumer profiles and their trust settings are never modified by these tests.
29
29
 
30
30
  ## Installed-package matrix
31
31
 
@@ -43,11 +43,59 @@ Local compatibility runs are serial by default. Set `DSH_COMPAT_CONCURRENCY` to
43
43
 
44
44
  All host JavaScript imports use ordinary Node resolution. The fixtures do not redirect DSH imports to alternate packages or load the plugin from the source checkout. The client fixture uses the consumer's React, store, and UI primitives, with a CSS loader for published host styles. It verifies the installed browser factory, settings registration, catalog injection, rendering, CSS, and cleanup. Host fixtures retain text streaming, real image processing, history/offload, limits, reasoning, live settings, and profile-bundle checks. Each host also runs all three wire protocols through prompt and tool declaration checks, a streamed tool call, JSON-restored assistant replay, tool-result continuation, and a one-shot request with no tools.
45
45
 
46
- ## Isolated pi-ai dependency
46
+ ## Architecture and ownership
47
47
 
48
- The runtime dependency `opencode-go-pi-ai` is an npm alias for `@earendil-works/pi-ai@0.87.1`. All plugin imports, including declaration types and lazy API factories, use the alias. It keeps this plugin's SDK requirement separate from the host's public `@earendil-works/pi-ai` name, so an older plugin that declares pi-ai only as a peer is not redirected by our dependency. The npm and pnpm Git-installation checks include a public pi-ai 0.85.1 and a peer-only probe, and verify that the probe retains 0.85.1 while this plugin resolves its own 0.87.1.
48
+ `src/index.ts` composes the host services. `src/config-contract.ts` is the browser-safe configuration vocabulary; both faces import it instead of maintaining separate interfaces. Version-dependent settings attachment lives in `src/host-settings.ts` and `src/client/host-compat.ts`. `src/settings-bridge.ts` owns section/profile selection and the applied/rejected/unknown write verdict: modern acknowledgments are authoritative, while older hosts require a committed-state check.
49
49
 
50
- 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 0.87.1, 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.
50
+ `GoCatalogManager` owns one configuration-keyed catalog per mount. Inference, model discovery and the settings model service share that catalog directly. The inference adapter retains its standalone catalog fallback for public callers. A superseded catalog cannot send a late route-refresh notification.
51
+
52
+ The browser sends typed `opencodeGoAccounts.execute` commands for account additions, removals, selection, naming, ordering, automatic switching and key replacement, including staged key drafts. `GoAccountManager` serializes these commands with recovery; both use `accountOperationPatch` to finish the same durable intention. A client-generated addition ID makes RPC retries idempotent. The UI owns drafts, busy state and quota display; the host owns credentials and revision-guarded metadata writes. Add account operations to the shared command contract and host manager, rather than creating another browser write path.
53
+
54
+ `src/account-policy.ts` decides whether a failed request may try another account and whether a gateway key should be remembered as rejected. Error classification stays in `src/gateway-error.ts`; stream lifecycle and dispatch stay in `src/adapter.ts`. Both terminal stream errors and thrown errors use the same policy, which blocks fallback after any output, positive token usage or cancellation.
55
+
56
+ ## Failure boundaries and resource policy
57
+
58
+ 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.
59
+
60
+ 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.
61
+
62
+ 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.
63
+
64
+ `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.
65
+
66
+ 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.
67
+
68
+ 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.
69
+
70
+ 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.
71
+
72
+ ## Reasoning intent
73
+
74
+ `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.
75
+
76
+ 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.
77
+
78
+ `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`.
79
+
80
+ ```sh
81
+ ELECTRON_RUN_AS_NODE=1 '/Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness' scripts/benchmark-protocols.mjs --live
82
+ ```
83
+
84
+ 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.
85
+
86
+ 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.
87
+
88
+ 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.
89
+
90
+ 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.
91
+
92
+ ## Bundled pi-ai implementation
93
+
94
+ The development dependency `opencode-go-pi-ai` is an npm alias for `@earendil-works/pi-ai@1.1.0`. esbuild retains the three 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. Bundled code and type licenses ship in `lib/vendor-licenses.txt`.
95
+
96
+ The published package does not depend on pi-ai, so it no longer introduces pi-ai's unrelated Google SDK and protobufjs install hooks. 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.
97
+
98
+ 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.
51
99
 
52
100
  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.
53
101
 
@@ -71,6 +119,8 @@ After changing the root lockfile, verify a clean `npm ci --strict-peer-deps` and
71
119
 
72
120
  The GitHub workflow runs core and Git-installation checks on Linux and Windows with Node 22.19.0 and 24. Core tests, npm installs, and pnpm installs run as independent jobs, so one slow installation does not consume another check's time allowance. Installation jobs need no root `npm ci`: their runner uses only Node built-ins, and the fresh Git fixture supplies committed artifacts and must not need build dependencies or plugin build approval. The complete installed-host matrix runs separately on Linux/Node 24.
73
121
 
122
+ Each isolated installation consumer installs the root's pinned TypeScript version solely to check the plugin's public declarations. That check resolves its compiler from the consumer, so it also runs when the checkout has no `node_modules`. Bundled license text uses LF regardless of the source checkout's line endings, keeping Windows artifact checks reproducible.
123
+
74
124
  Installation jobs reuse the npm download cache and a separate pnpm store, preferring cached packages while still fetching missing data. They never restore the checkout's `node_modules` or `lib/`. CI keeps the npm cache, isolated consumers, and the cached pnpm store under `RUNNER_TEMP`, on the runner's work volume. `DSH_PNPM_STORE_DIR` selects the pnpm store; local runs use the system temporary directory and the default package caches unless overridden.
75
125
 
76
126
  Every Git-installation run reports fixture preparation, installation, artifact verification, cleanup, and total elapsed time. GitHub job summaries include a phase table. CI also enables npm's internal timing records and uploads the `*-timing.json` files for seven days, for diagnosing dependency resolution and extraction; a timeout may prevent the still-running process from writing its final timing file. The 15-minute job limit remains unchanged.