🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

OpenCode 网关适配 viztor/dsh-opencode-patch

DeepSeek Harnessv1.4.1
viztor0 天前有提交已提供中文文档扫描:含敏感能力

OpenCode 跑在 DeepSeek Harness 上——这个 DSH 插件让 OpenCode Zen + Go 免费档模型持续可用:会话亲和、网关来源头、工具 schema 兜底。

40.5/100
综合分
8
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/31 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:engines.node 要求 >=24,不满足 Node 22.19.0。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add viztor/dsh-opencode-patch
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · model
装得上吗
实装验证未通过(repo_missing),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 0 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(repo_missing · 2026/10/22) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

engines.node 要求 >=24,不满足 Node 22.19.0

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-opencode-patch @ 1.4.1
✗Node 引擎要求 >=24 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 15:49:55

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 10 处,展示前 10 条)
  • 写入本地文件
    src/debug.ts:36
    await appendFile(file, `${JSON.stringify(entry)}\n`, "utf-8");
  • 读取密钥环境变量
    src/fetch-patch.ts:262
    ? process.env.OPENCODE_GO_API_KEY
  • 读取密钥环境变量
    src/fetch-patch.ts:263
    : process.env.OPENCODE_API_KEY;
  • 读取本地文件
    src/google-bridge.ts:180
    if (existsSync(path.join(candidate, "package.json"))) {
  • 读取本地文件
    src/google-bridge.ts:210
    const manifest = readFileSync(path.join(root, "package.json"), "utf-8");
  • 读取密钥环境变量
    src/lifecycle.ts:547
    ? process.env.OPENCODE_GO_API_KEY
  • 读取密钥环境变量
    src/lifecycle.ts:548
    : process.env.OPENCODE_API_KEY;
  • 读取本地文件
    src/opencode-store.ts:230
    if (databasePath === ":memory:" || !existsSync(databasePath)) {
  • 读取本地文件
    src/stream-hook.ts:113
    if (VCS_MARKERS.some((marker) => existsSync(`${candidate}/${marker}`))) {
  • 发起网络请求
    src/usage.ts:348
    response = await fetch(url, {
扫描于 2026/11/1(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-client-store@deepseek-ai/dsh-client-ui-primitives@deepseek-ai/dsh-llm-pi-ai@deepseek-ai/dsh-typert-protocol
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 会话亲和
  • 网关来源头
  • 工具schema兜底

README

由 DeepSeek 最新模型翻译生成
English · 简体中文 dsh-opencode-patch OpenCode on DeepSeek Harness网关来源头 · 会话亲和 · 免费层工具回退 · 实时双模式额度计量 快速开始 ·修复的问题 ·界面 ·配置 ·故障排查 ·更新日志 ·贡献指南 dsh-opencode-patch 是一个 DeepSeek Harness 宿主插件,让 OpenCode Zen 与 Go 模型在 DSH 内持续可用。无需遭遇网络拒绝、Cloudflare 挑战、权益不匹配或隐形限制,即可接入 claude-sonnet-4-5、gpt-5.4、gemini-3.8-flash、deepseek-v4.1-flash、muse-spark-1.3-contributor-free、qwen3.8-flash 以及 OpenCode 目录中的其余模型。 默认状态。 把 DSH 直接指向 OpenCode、不装任何插件,模型是完全不能用的——不是某一种形状不能用,而是全部: - 请求不会被识别为"编码 agent"发出的。
展开完整文档(README 剩余 1 节)
English · 简体中文

dsh-opencode-patch
OpenCode on DeepSeek Harness网关来源头 · 会话亲和 · 免费层工具回退 · 实时双模式额度计量

快速开始 ·修复的问题 ·界面 ·配置 ·故障排查 ·更新日志 ·贡献指南

dsh-opencode-patch 是一个 DeepSeek Harness 宿主插件,让 OpenCode Zen 与 Go 模型在 DSH 内持续可用。无需遭遇网络拒绝、Cloudflare 挑战、权益不匹配或隐形限制,即可接入 claude-sonnet-4-5、gpt-5.4、gemini-3.8-flash、deepseek-v4.1-flash、muse-spark-1.3-contributor-free、qwen3.8-flash 以及 OpenCode 目录中的其余模型。

默认状态。 把 DSH 直接指向 OpenCode、不装任何插件,模型是完全不能用的——不是某一种形状不能用,而是全部:

- 请求不会被识别为"编码 agent"发出的。 DSH 发的是自己的 User-Agent,不带 x-opencode-client、x-opencode-project,也不带 x-opencode-session;网关看到的就是一次匿名 SDK 调用:免费层模型返回 403 FreeTierError,流量还要受厂商对"不表明身份的客户端"所设的滥用规则约束。
- 没有会话 id 的一轮会被拒、或失去关联。 每一轮都必须带一个稳定的 ses_… 形状的 id,而 DSH 在子代理、后台评估以及 Auto Review 这类模式下会完全省略 sessionId。
- 免费层的 /responses 请求体缺少 read 与 bash 会被拒,而 DSH 是刻意不发这两个工具的。
- 目录很单薄。 裸 /models 列表只有 id,几乎没有别的信息,所以选择器里是一堆没有名字、没有价格、没有上下文窗口的行。

这些能用之后剩下的是另一个问题,而且与账号无关:OpenCode 的模型分布在四种不同的 API 形状上,而 DSH 是按 provider 行选择传输协议的——一条路由只能说一种形状。所以走 Responses / Messages / Mistral 的模型在基础问题解决之后就会返回 500。这正是插件按模型而不是按 provider 路由的原因。

插件在网络层补齐所有缺失的协议要素——且仅针对 OpenCode 路由(opencode / opencode-go / opencode-responses / opencode-anthropic / opencode-google)。其余全部流量(DeepSeek、OpenAI、Anthropic、GitHub)原样通过。

三条主线。

1. 最小侵入。 不做全局补丁:只拦截本插件声明的路由,其他厂商——DeepSeek、OpenAI、Anthropic、GitHub——的请求原样通过。计量器离"彻底消失"只差一个开关,而不是离"勉强忍受"隔着一个页面。
2. 原生 DSH 插件。 一个 apply()、一张绑定自己命名空间的设置卡、用 ctx.inject 声明服务、按宿主自己的方式填充插槽,文案随宿主语言切换。没有私有钩子,不改宿主代码。
3. OpenCode API 兼容。 网关真正检查的那些特征在网络层还原——与 CLI 同形状的 ses_… 会话 id、官方来源头、父会话血统,以及免费层的 read/bash 工具 schema 回退。

亮点

- 🔑 确定性的 ses_<12hex><14base62> 会话哈希,跨轮次、子代理与分叉保持 KV 缓存亲和
- 🌐 网关来源恢复——User-Agent、x-opencode-client、x-opencode-project、父会话谱系
- 🧰 免费层 read + bash 工具 schema 回退,让免费层的请求体带上它的端点所要求的工具定义——这去掉的是 403 的一个成因,而不是全部:网关的那道闸不在请求里,实测如此
- 📇 基于 OpenCode 官方目录(models.opencode.ai,即 models.dev 发布的那份注册表)的模型目录,带离线预置与后台 SWR 刷新——名称、上下文窗口、价格
- ⭕ 实时双模式停靠栏计量——Go 额度环(5 小时 / 每周 / 每月)或 Zen 按量计费胶囊,外加会话消耗与模型费率
- 🕵️ 严格凭据隔离——Zen 密钥(oc_sk_…)绝不查询 Go 额度端点

目录

1. 快速开始
2. 修复的问题
3. 支持的模型与协议
4. 界面
5. 配置参考
6. 故障排查
7. 兼容性与验证
8. 深入解析 — 协议内部实现,已移出本 README
9. 署名与许可

🚀 快速开始

1. 安装到你的 DSH Web profile(Node 24+):

cd ~/.dsh/profiles/web
npm install dsh-opencode-patch

包名在所有用到它的地方都是 dsh-opencode-patch:你安装的依赖、profile 里的 bundle 条目,以及宿主解析的那一行。

2. 启用 bundle——把该包加入 profile 的 dsh.profile.bundles 数组:

// ~/.dsh/profiles/web/package.json
{
"dependencies": {
"dsh-opencode-patch": "^0.12.0",
},
"dsh": {
"profile": {
"bundles": ["dsh-opencode-patch"],
"patchReload": "live",
},
},
}

3. 添加凭据,让额度计量能解析到密钥——在 DSH Credentials 或你的环境变量中存储 OPENCODE_GO_API_KEY(Go 订阅,sk-…)和/或 OPENCODE_API_KEY(Zen 按量计费,oc_sk_…)。

4. 重启 dsh web。 宿主 bundle 只在启动时导入(hmr root: []),因此要重启才会加载 lib/index.mjs;客户端 UI 变更(lib/client.js)只需刷新浏览器。

完成——OpenCode 补丁设置卡片会出现在 _Settings → Plugins_ 下,一旦有 OpenCode 模型激活,计量表就会挂载到输入框停靠栏。

🔌 修复的问题

| 没有补丁时 | 使用 dsh-opencode-patch 后 |
| Zen 免费模型报 403 FreeTierError | 自动恢复网关来源头与工具回退 |
| 一条路由只能说一种形状——基础问题解决后,其余模型返回 500 | 逐模型路由——按目录里每个模型自己声明的 SDK 派发到对应端点 |
| 会话 ID 被拒并返回 400 MissingSessionID | 确定性的 ses_… 会话哈希与跨轮次亲和 |
| 子代理丢失对话上下文 | 父会话跟踪(x-opencode-parent-session-id、x-parent-session-id) |
| Auto Review 调用报 TRANSPORT: Connection error | 回退会话轮次捕获,在评估调用之间保留轮次状态 |
| 额度与余额不可见 | 实时双模式停靠栏计量,显示 Go 额度或 Zen 按量计费 |
| Zen 密钥在 Go 用量上触发 403 EntitlementError | 严格凭据隔离,让 Zen 密钥不接触 Go 端点 |
| 所有项目共用一个 "global" 遥测桶 | 动态工作区归属,由当前 session.header.cwd 解析 |
| 网关 /models 返回截断且无名称的列表 | 目录补全(models.opencode.ai):显示名、上下文窗口与价格 |

🧭 支持的模型与多协议路由

两种端点,两种凭据形状。 OpenCode 的目录在两个层级上定义端点:provider 默认端点——Zen 是 https://opencode.ai/zen/v1,Go 是 https://opencode.ai/zen/go/v1——以及逐模型的推理端点,目录里设置时会覆盖默认值(CLI 读 model.api.url,取不到就回落到 provider 默认)。插件两个都不钉死:它匹配的是 opencode.ai/zen 这个标记,所以走默认端点的模型和走自己端点的模型都会被补丁覆盖。

这些端点的认证有两种,因为它们说三种线格式:OpenAI 那两个平面发 Authorization: Bearer <key>,Anthropic 平面发 x-api-key: <key>。插件两种都读——先 Authorization,再 x-api-key / api-key——所以凭据无论由哪个平面带过来都能被捕获,Go 额度查询也仍然找得到密钥。

网关提供四种线路家族,而 OpenAI 自己就占了两种:Chat Completions 与 Responses 是两种不同的线路格式,不是同一个东西的两个名字。需要 Responses 的模型在 completions 端点上不工作,而网关不会回退——它直接返回 500。

DSH 能说其中四种,插件就把这四种都路由掉。Google Generative AI 走插件自己挂的路由 opencode-google ——它曾经是唯一没有路由的一种,现在不是了。见下表。

1. OpenCode Zen (provider: opencode) — 按量计费与免费额度

- Anthropic Messages (https://opencode.ai/zen/v1/messages):claude-sonnet-4-5、claude-opus-4-7、claude-haiku-4-5、qwen3.8-flash
- OpenAI Responses (https://opencode.ai/zen/v1/responses):gpt-5.4、gpt-5.2、gpt-5.1-codex-max、muse-spark-1.3、space-bunny-free,以及免费层的 muse-spark-1.3-contributor-free
- OpenAI Chat Completions (https://opencode.ai/zen/v1/chat/completions):deepseek-v4.1-flash、kimi-k2.5、kimi-k3、minimax-m2.5、glm-5.2,外加免费层的 nemotron-3-ultra-free、ling-3.0-flash-fin-free、mimo-v2.6-flash-free
- Google Generative AI (https://opencode.ai/zen/v1/models/:streamGenerateContent):gemini-3.8-flash、gemini-3.1-pro、gemini-3.5-flash-lite

2. OpenCode Go (provider: opencode-go) — 订阅额度

- Google Generative AI(https://opencode.ai/inference/go/google/v1beta/models/:streamGenerateContent):gemini-4-argon-contributor,由内部适配器 opencode-go-google 服务。在现有 opencode-go 提供商下配置该模型即可,适配器继承该提供商的 API Key 引用(默认 OPENCODE_GO_API_KEY),支持图片附件和带签名的工具调用回放。只挂载已配置的模型,可用范围仍由 Go 套餐决定。Go 没有旧版 Google 接口,因此 endpoint: legacy 也使用此地址。

- OpenAI Chat Completions(https://opencode.ai/zen/go/v1/chat/completions):deepseek-v4-flash, deepseek-v4-flash-vision-exp, deepseek-v4-pro, deepseek-v4.1-flash, glm-5.2, glm-5.3, glm-5.3-flash, hy3, hy4-preview, kimi-k2.6, kimi-k2.7-code, kimi-k3, longcat-2.0, mimo-v2.5, mimo-v2.5-pro, mimo-v2.6-flash, mimo-v2.6-pro, qwen3.6-plus, qwen3.7-max, space-bunny, space-bunny-free, step-5-preview-free
- OpenAI Responses(https://opencode.ai/zen/go/v1/responses):gpt-5.6-luna, gpt-6-luna, grok-4.5, grok-4.6, grok-4.7, muse-spark-1.2-contributor, muse-spark-1.3-contributor
- Anthropic Messages(https://opencode.ai/zen/go/v1/messages):claude-haiku-5-5, minimax-m2.7, minimax-m3, qwen3.7-plus, qwen3.8-flash, qwen3.8-max
- 由实时三窗口额度计量监控(5 小时滚动、每周、每月)。完整集合随内置目录发布——参见权威模型目录。

3. 模型的协议是怎么定的 —— 以及为什么你什么都不用配

Zen 的 provider 级 SDK 是 @ai-sdk/openai-compatible。models.dev 只在该模型需要不同 SDK 时才逐模型标注 provider.npm —— 所以这个字段的存在本身就是信号,它决定走哪条线路协议。没有任何手工匹配:

| models.dev provider.npm | 模型数 | 协议 | 服务自 |
| _(缺失)_ | 27 | OpenAI Chat Completions | 你配置的路由 |
| @ai-sdk/openai | 31 | OpenAI Responses | opencode-responses |
| @ai-sdk/anthropic | 17 | Anthropic Messages | opencode-anthropic |
| @ai-sdk/google | 8 | Google Generative AI | opencode-google |
| @ai-sdk/mistral | 1 | _(本插件不服务的方言)_ | 不提供 |

数量为 models.opencode.ai 中 opencode 的 82 个在用模型,统计于 2026-10-23 —— 其余已废弃或下架,补丁只内置网关仍在服务的部分。同样这 82 个模型离线内置在 src/catalog-data.ts,因此在第一次 catalog 刷新之前它们每一个路由都是正确的;用 pnpm run catalog:shim 重新生成该文件。

插件把这两条内部路由同时挡在模型选择器和 _Settings → Models_ 之外。三条性质今天就成立,还有一条尚未成立:

- 你的挑选仍然有效。 选择器显示的就是你列出的模型,每个模型都会自动匹配到正确的协议。OpenCode 的模型分布在三种形状上——OpenAI Chat Completions(默认)、OpenAI Responses、Anthropic Messages——需要后两种的模型会被派发到对应路由。不需要手工声明第二条路由。
- 永远不会提供跑不通的模型。 那 8 个 @ai-sdk/google 模型由插件自己的适配器服务(路由 opencode-google),所以它们不再被剔除——插件曾经没有对应协议,现在有了。真正会被剔除的是 @ai-sdk/mistral 的那一个:它的方言网关怎么回答还没有测过,所以宁可不提供,也不送它去一个凭空想出来的地方。
- 一份凭据。 所有路由模型共用你已配置的 opencode key,经凭据服务解析,不会重新问你要。

如果你更想自己声明路由:opencode-responses(以及你用上 Anthropic 平面模型后的 opencode-anthropic)可以写进 profile 的 llm-pi-ai providers 块里,并列出它服务的模型。声明是一个选择,不是要求:

opencode-responses:
api: openai-responses
baseURL: https://opencode.ai/zen/v1
headers:
authorization: Bearer unused # 由 fetch 补丁换成你的 key models:
- id: muse-spark-1.3-contributor-free
name: Muse Spark 1.3 Free
contextWindow: 1048576
maxTokens: 131072
input: [text, image]

这条路由由插件替你注册,所以上面那段配置是可选的。responses-provider.ts 会在进程内挂载宿主自己的 llm-pi-ai:隔离 authorization 与 settings 两个接缝,并在一层只转发 adapter 注册的 llm 门面之后挂载——因此它既不会重复登记整个 catalog 目录、settings 命名空间,也不会多注册任何一条 sign-in flow。这一版是对着真实 harness 验证的,不是桩:路由注册成功,宿主自己的 41 条 catalog 与 41 条 sign-in flow 原封不动,卸载时该路由被撤回。

这些路由继承你的凭据:每一条都沿用你 opencode 路由已经声明的同一个 apiKeyEnv,所以自定义的 key 引用不需要你再说一遍。你在 profile 里已经声明过的路由会被尊重——插件不会覆盖你的模型列表。

若宿主没有已加载的 llm-pi-ai 条目,插件不会注册任何东西,只会在日志里说明;此时请在 profile 里显式声明该路由。

4. 覆盖的执行模式

| 模式 | 补丁做什么 |
| 交互式多轮对话 | 通过每会话稳定的 ses_… id 提供 KV 提示缓存亲和 |
| 子代理与分叉 | 子、父会话都参与哈希;谱系由父级请求头携带 |
| Agent 团队 | 跨编排轮次保留共享工作区的归属信息 |
| 实验性 Auto Review | 即使后台审计调用省略 sessionId,仍会得到确定性的轮次状态、请求头与工具回退 |

5. 目录:合并了什么,谁说了算

模型清单由四个来源拼成,每个来源回答的是不同的问题:

| 来源 | 回答 |
| 内置 shim | 一次网络请求都还没有时能提供什么——冷启动、离线 |
| models.opencode.ai | 规范参数、价格与显示名 |
| 网关的 /models | 这个账号实际能用什么 |
| 发现装饰 | discoverModels 该回答什么 |

合并是增量式的:适配器给的行保留,规范行只在缺失时追加,只有当按 provider 记录的退役名单点名某个模型时才省略它——那是事实,不是猜测。显示名与价格取自目录(models.opencode.ai),因为网关列表只给 id,别的几乎没有。

有两点你在使用中会注意到。冷启动永远不为空——内置 shim 在第一次刷新前就能回答,选择器立刻有模型可选。而且目录里没有条目的模型照样出现,费率位置显示 —:既不猜,也不会退回去显示上一个模型的名字。

两个生成文件都在 CI 里校验(catalog:shim、limits:shim);厂商数据变动时它们以非零码退出——这是唯一能发现厂商注册表在你背后变了的办法。

→ 协议路由、合并与界面的技术细节: docs/protocol-routing-and-merge.md · English

🖥 界面

两个界面,同一个读数。两者都是纯视图,数据来自宿主。

| 界面 | 位置 | 显示什么 |
| 计量表触发按钮 | 输入框停靠栏,模型选择器旁 | Go:圆环 + 该窗口的百分比。Zen:本会话消费额,不画圆环 |
| 计量表面板 | 点击触发按钮 | 三个窗口、月度额度、本会话消耗、Zen 余额、操作链接 |
| 设置卡片 | _Settings → Plugins → OpenCode 补丁设置_ | 九个控件,上方另有一份实时 Go 用量摘要 |

悬停触发按钮解释它自己的数字;点击打开面板。下面逐节展示每个界面,逐状态的行为见 docs/quota-meter.zh-CN.md。

设置卡片 — _Settings → Plugins → OpenCode 补丁设置_

四个分区共九个控件——都是用户真正会做出的决定。所有控件都基于平台自身的原语渲染(Switch、Tag、Button、宿主 token),每个配置项都带提示以及恢复默认的操作。

| 分区 | 控件 | 默认 | 作用 |
| 网关请求 | 恢复 User-Agent(默认开启) | on | 恢复官方 OpenCode CLI 的 User-Agent,使 Cloudflare WAF 校验通过 |
| 网关请求 | 注入客户端来源头(默认开启) | on | 在网关流量上注入 x-opencode-client(以及来源请求头集合) |
| 网关请求 | 附带工作区项目标识(默认开启) | on | 用当前文件夹名标记 x-opencode-project;关闭则省略该请求头 |
| 模型与免费额度 | 用 OpenCode 官方目录补全模型信息(默认开启) | on | 把目录的上下文上限、模态与思考档位补进模型信息,并让网关 /models 列表带上完整目录。不会往选择器里添加模型——选择器只显示已声明的;要添加请用卡片的检查目录 |
| 模型与免费额度 | 自动补全核心工具(默认开启) | on | 补上免费层 /responses 请求体所需的 read + bash schema |
| 配额计量 | 开启输入区用量计量(默认开启) | on | 在输入框停靠栏挂载实时计量表——Go 额度环,或 Zen 会话消耗 |
| 配额计量 | 显示会话消耗与模型费率(默认开启) | on | 追加显示本会话累计花费与当前模型每百万 Token 费率 |
| 账户与端点 | API 端点 | auto | 请求发往哪个端点家族:自动(跟随目录) · 旧端点(zen/v1) · 新端点(inference/v1) |
| 账户与端点 | 凭据来源 | auto | 多个密钥同时可用时以哪个为准:自动 · 优先实时请求 · 优先已声明密钥 |
| 账户与端点 | 读取 OpenCode 安装版的密钥(默认关闭) | off | 允许本插件读取 OpenCode 自己保存的凭据,且仅作最后手段——默认关闭 |

选择端点与凭据

一个请求发往哪里由两个问题决定,答案就在账户与端点分区里。

发往哪个端点家族。 网关在两套端点上都应答——较早的 /zen/v1 与较新的 /inference/v1——而两者的授权是彼此独立的:在一边可用的账户不保证在另一边可用。auto 会跟随网关自己的目录,目前它指向较新的一套,因此目录迁移会带着你一起走;legacy 与 modern 则固定其一,适用于账户只在较早一套上可用,或你想确认较新的一套是否可用的情况。

以哪个凭据为准。 keySource 决定插件可见的多个凭据源的优先级——auto 优先使用你声明过的密钥,其次是从实时请求中捕获的密钥,最后是声明的凭据引用;request 把捕获到的密钥提到最前;configured 则相反。其下的 readOpencodeStore 允许插件读取 OpenCode 自己保存的凭据,且仅作最后手段。两者默认分别为 auto 与关闭,因此在你说要改之前一切照旧。

覆盖类配置项(字面字符串、标记、路由列表)刻意只留在配置里,让默认值适用于所有有文档记载的配置——参见配置参考。

卡片在控件上方还带一份实时的 Go 用量摘要——和输入框计量表同一个读数,但用官方控制台的排版:每个窗口一行,剩余单独放在右侧。

Go 用量 状态正常 ● 5 小时 0% 已用 · 4小时58分钟后重置 100% 剩余 ● 每周 28% 已用 · 3天2小时后重置 72% 剩余 ● 每月 14% 已用 · 11月7日8点55分重置 86% 剩余月度额度 mimo-v2.6-pro · Go $60 · Plus $120 ⓘ

「剩余」是百分比,不是美元数:/usage 每个窗口只给一个百分比、完全没有余额接口,而套餐档位也无法探测——任何美元余额都会是猜的。这一点由 ⓘ 说明。读不到配额时它明说读不到,并且不打印任何数字,而不是打一排会被当成真实读数的 0%。

输入框停靠栏计量表

计量表挂载在 conversation.composer.dock 中 DSH 原生 ContextMeter 旁。逐状态的行为说明(触发按钮的三种状态、两个面板、每一行的含义、三种「没有数字」的区别)见 docs/quota-meter.zh-CN.md。

┌─────────────────────────────────────────────────────────────────┐
│ Type a message... │
│ │
│ [+] Attach [DeepSeek V4.1 Flash ⌄] [⬆]│
└─────────────────────────────────────────────────────────────────┘
[ ⭕ 73% Context ] [ ⭕ 42% Go Quota ] ← when OpenCode Go is active
[ ⭕ 73% Context ] [ ⭕ $0.00 ] ← 使用 OpenCode Zen 时

模式 A — OpenCode Go (opencode-go)

- 自适应环:实时 SVG 环,显示能回答问题的那个窗口。已经用尽的窗口——受限或到达上限——优先显示,从宽到窄(每月 → 每周 → 5 小时),因为月上限能解释一次拒绝,而 5 小时窗口解释不了。否则显示 5 小时窗口:它最早重置,是还能行动的那个。免费模型上环形以灰色空心显示——套餐上限与一笔无法产生的账单无关,对着 $0.00 亮红色会被读成"你的钱用完了"。
- 语义色:低于 80% 为绿色(--dsw-alias-state-success-primary),≥80% 为琥珀色(--dsw-alias-state-warn-primary),达到上限为红色(--dsw-alias-state-error-primary)。
- 点击面板:三行窗口,各带实时重置倒计时与一条进度条;一行会话消耗,写的是当前选中的模型;一行 Zen 余额;一条受限告警;以及可直接处理的链接。悬停触发器显示 Tooltip,列出全部三个窗口(5 小时 11% · 每周 33% · 每月 16%)——触发器只能印一个数字,而下一个问题永远是"另外两个呢?"。
- 目录里没有价格的模型显示 —,不是 Free。 面板始终显示选择器上的模型名,即使目录里还没有它的条目(目录按计划同步)——显示上一个模型的名字比显示没有价格更糟。

┌──────────────────────────────────────────────┐
│ OpenCode Go [Go Plan]│
├──────────────────────────────────────────────┤
│ • 5 hours ███████░░░░░░░░░ 42% │
│ Resets 3h 12m │
│ • Weekly ███░░░░░░░░░░░░░ 18% │
│ Resets 5d 8h │
│ • Monthly █████████████░░░ 65% │
│ Resets 22d 4h │
├──────────────────────────────────────────────┤
│ 月度额度 │ │ mimo-v2.6-flash Go $60 · Plus $120│ ├──────────────────────────────────────────────┤ │ 当前会话消耗 │ │ deepseek-v4.1-flash · $0.15 / $0.6 per 1M │ │ $0.42 │ │ 可用 Zen 余额 │ │ 请求将自动从 Zen 余额中扣除 就绪 │ ├──────────────────────────────────────────────┤ │ ⟳ 更新于 08:30 升级套餐 控制台 ›│ └──────────────────────────────────────────────┘

月度额度,以及为什么它是总额而不是余额。 三个窗口是某个模型月度美元额度的比例——官方原话:_"Usage limits are defined as monthly dollar amounts… 5-hour — 20% of the monthly limit; weekly — 50%; and monthly — 100%."_ 所以计量表把这笔额度打印在窗口下面:mimo-v2.6-flash 是 Go $60 · Plus $120。它由官方 Go 文档生成(pnpm run limits:shim,CI 定时校验),因为页面明说"usage limits may change"——手写表一个版本内就会过期,而过期的美元数字看起来很权威。

它同时显示两个档位而不是只显示一个,因为档位查不到:/limits、/plan、/subscription、/account、/credits 全部 404,/models 也没有额度字段。猜一个档位,金额就会差 2–3 倍。

它刻意不是剩余额度。GET /zen/go/v1/usage 不接受 model 参数,所以返回的百分比是账号级的,而额度是按模型的——两者相乘得到的数字没有指代对象。真实余额在控制台,那里是准确的。

模式 B — OpenCode Zen (opencode)

Zen 路线上不出现任何 Go 的数字:根本不画圆环(没有可量的量规就是装饰),标签是消费额而不是百分比,Go 套餐被限流也不会把 Zen 按钮染成告警色,悬停则带上价格(当前会话消耗 $0.00 · 按量计费)。Go 的窗口是关于一条本路线永不结算的套餐的事实,所以在这里不出现。

- Zen 触发器:标签是本会话累计花费(未计价时为 $0.00,计价后如 $0.42),且不画圆环——圆环是量规,而 Zen 没有可量的窗口。这个数字是唯一能拿到的真实数字:OpenCode 的 Zen 余额只能通过 console 的 server action 读取,API 密钥读不到。
- 按量计费面板:带 Pay-as-you-go 徽标的头部、会话消耗行(价格开关开启时),以及一个链接——OpenCode 控制台,标为充值:按量计费的人点进去就是要充钱,而充值本身没有独立的地址。

┌───────────────────────────────────────────────┐
│ OpenCode Zen [Pay-as-you-go] │
├───────────────────────────────────────────────┤
│ Session Spend │
│ Space Bunny Free · 免费 $0.00│ ├───────────────────────────────────────────────┤ │ ⟳ 更新于 08:30 控制台 ›│ └───────────────────────────────────────────────┘

Zen 余额与溢出。 若配置了 OPENCODE_API_KEY(或 oc_sk_…),Zen 按量计费会被自动检测。Zen 面板不显示余额行:该余额只能通过 console 的 server action 读取,需要浏览器会话,因此面板直接链接到 OpenCode 控制台,而不是冻结一个无法保持最新的数字。余额行放在 Go 面板上——那里它回答的是一个面板真能回答的问题:超出配额的 Go 请求是否真的会从该余额扣费。

⚙ 配置参考

仅配置项 (cordis.patch.yml)

这些项存在于 schema 中,却不渲染任何控件——每一项都是字面值、标记或引用,其默认值适用于所有有文档记载的配置。它们仍可在该行的 config 中编辑;cordis.patch.yml 是参考。

| 配置项 | 默认值 | 保留在配置中的原因 |
| providers | opencode, opencode-go, opencode-responses, opencode-anthropic | 要拦截的路由 id;必须覆盖本层声明的每一条路由 |
| gatewayUrls | opencode.ai/zen | 标记网关流量的 URL 子串;只有镜像或中继才会改它们 |
| userAgent | 空(= 规范 CLI UA) | 字面覆盖;默认值就是网关所期望的值 |
| originClient | cli | x-opencode-client 的字面值 |
| sessionIdEnv | OPENCODE_SESSION_ID | 指定一个仅当调用方提供会话 id 时才使用的环境变量名 |
| freeModelMarker | free | 模型 id 子串; 强制启用回退,'' 关闭回退 |
| usageBaseURL | https://opencode.ai/zen/go/v1 | 端点覆盖;从组合中自动发现 |
| debug / debugFile | false / — | 诊断用 JSONL 日志,不是谁会在 UI 里调节的行为 |

cordis.patch.yml — the plugin's row; every key is optional.
- insert:
- id: dsh-opencode-patch
name: "dsh-opencode-patch"
config:
providers:
- opencode
- opencode-go
- opencode-responses
- opencode-anthropic
gatewayUrls:
- opencode.ai/zen
sessionIdEnv: "OPENCODE_SESSION_ID"
freeModelMarker: "free"
usageBaseURL: "https://opencode.ai/zen/go/v1"
endpoint: "auto" # auto | legacy | modern
keySource: "auto" # auto | request | configured
injectUserAgent: true
injectOriginHeaders: true
originClient: "cli"
injectProject: true # attach workspace folder (or 'global'); false omits the header
injectCoreTools: true
enrichModels: true # merge catalog specs into model info + gateway /models listings
usageEnabled: true # off = no meter and no price row
File-level only debug options:
debug: false
debugFile: "/tmp/dsh-opencode-debug.jsonl"

宿主重载规则: 任何宿主变更(lib/index.mjs)之后都要重启 dsh web;客户端 UI 变更(lib/client.js)刷新浏览器即可。

🛠 故障排查

| 症状 | 可能原因 | 解决方法 |
| 免费模型报 403 FreeTierError | 网关请求头被剥离,或缺少工具定义 | 保持恢复 User-Agent、注入客户端来源头与自动补全核心工具开启 |
| 400 MissingSessionID | 未附带会话请求头 | 确认 dsh-opencode-patch 已列入 profile 的 dsh.profile.bundles |
| Auto Review 报 TRANSPORT: Connection error | 更新后宿主进程未重启 | 停止并重启 dsh web,让新的 lib/index.mjs 加载 |
| Go 模型始终不显示额度环 | 解析不到 Go 凭据,或当前激活的网关不是 opencode-go | 在 DSH Credentials 中存储 OPENCODE_GO_API_KEY,并经 opencode-go 路由 |
| 目录中的模型在 Settings → Fetch 里缺失,或已下线的模型仍然存在 | 宿主模块过期、补全关闭,或适配器用自带目录作答 | pnpm run build、重启 dsh web、保持用 OpenCode 官方目录补全模型信息开启、从匹配的路由获取、搜索精确 id(如 space-bunny-free) |
| 弹出面板以红色显示“已达限额” | 滚动 / 每月窗口已用到 100% | 打开 OpenCode 控制台并启用 _使用余额(Use balance)_,以溢出到 Zen 额度 |
| 非 OpenCode 模型行为异常 | 与本补丁无关 | 发往其他网关的流量原样通过 |

📜 兼容性与验证

已在 DeepSeek Harness 0.2.1 与 0.2.2 上验证 —— alpha 与 rc 两个通道(Node 24+)

Harness 按 alpha 与 rc 两个通道发布,它们是平行的发布线而非版本先后:semver 中 0.2.1-rc.2 排序在 0.2.1-alpha.5 之上。本插件针对所支持版本线的两个通道——最新的 rc(0.2.1-rc.5)与最新的 alpha(0.2.2-alpha.2)一视同仁——因为宿主可能跑在任一通道上,而只盯着当前钉住的那个通道,正是插件在另一条轨道上悄悄停止加载的原因。只有版本钉选处会写出单一版本(毕竟只能装一个);@deepseek-ai/dsh-typert-protocol 的 peer 范围才是代码声明自己真正支持什么的地方:

=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0

第一段覆盖了 0.2.1 线的两个通道:下界 alpha.1 排序低于同线的所有 rc,因此无需单独枚举 rc。第二段不是冗余——除非同一 major.minor.patch 的某个比较符带有预发布号,semver 会把预发布版本排除在外,所以只写 <0.3.0 会悄悄丢掉每一个 0.2.2- 构建,alpha 与 rc 都一样。两段都止于 0.3.0,下一条线因此是一个单独的决定,而不是悄悄的放宽。

| 层面 | 目标 |
| Harness 版本线 | 0.2.1 与 0.2.2,alpha 与 rc 通道均可(peer:>=0.2.1-alpha.1 <0.3.0 \|\| >=0.2.2-0 <0.3.0) |
| 插件包 | dsh-opencode-patch |
| 宿主 profile | DSH Web profile(patchReload: live) |
| 声明的路由 | opencode、opencode-go、opencode-responses、opencode-anthropic |
| 网关 | opencode.ai/zen/v1(/responses、/chat/completions、/messages、:streamGenerateContent)、zen/go/v1(/chat/completions) |
| 模型目录 | 由 models.opencode.ai/api.json 生成;下线判定直接跟随目录自身的 status: "deprecated" 标记,不维护任何手工 id 列表 |
| 上游 pi | 不随包携带。 桥接在运行时加载 harness 已安装的那份 @earendil-works/pi-ai,因此 harness 升级不会与本插件锁定的副本产生版本错位 |
| 验证关卡 | vp check 干净、961 个确定性测试全绿、完整 schema 校验、消费者安装 + 加载(scripts/check.ts) |

🔍 深入解析

请求头注入矩阵、会话谱系、工作区归属、API 层级与目录内部实现,都在 docs/deep-dive.md。本 README 只讲你看得见的界面和要配的东西。

👥 署名与许可

灵感来自 @nobu121 的 nobu121/dsh-opencode-session,该项目开创了 OpenCode on DSH 的会话 ID 处理。本插件由 @viztor 独立实现:沿用了这个思路,其余部分都是重写的——Zen 免费层网关兼容、分层子代理谱系、动态工作区项目归属、实时双模式 Go 额度与 Zen 余额监控,以及原生 Web UI 集成。

链接: npm · 仓库 · 问题 · 更新日志 · 贡献指南 · OpenCode · models.dev

以 MIT License 授权。
预览分享卡片长什么样 ↓viztor/dsh-opencode-patch
分享 · DeepSeek Harness Hub
viztor/dsh-opencode-patch

OpenCode 跑在 DeepSeek Harness 上——这个 DSH 插件让 OpenCode Zen + Go 免费档模型持续可用:会话亲和、网关来源头、工具 schema 兜底。

回到顶部