# dsh-web-search-opencode-go [English](README.md) | 中文 **修复 DSH `web_search` 走 OpenCode Go / OpenCode Zen 时的 `MissingSessionID` 报错。** 网关会拒绝缺少 `x-opencode-session` 的 Anthropic Messages 请求: ```text Error from provider (Console Go): Request is missing x-opencode-session and cannot be routed efficiently. Please see https://opencode.ai/docs/go/#where-can-i-use-it ``` 本仓库是 [`@deepseek-ai/dsh-web-search-deepseek`](https://www.npmjs.com/package/@deepseek-ai/dsh-web-search-deepseek) 的**同名 drop-in 补丁分支**,适用于 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)。 它会自动注入: - `x-opencode-session` —— 当前 DSH agent 会话 id(或配置的 id / 插件级 UUID 兜底); - `x-opencode-client: dsh`。 这样内置 `web_search` 工具即可恢复正常,且**不需要修改官方 DSH 安装目录**。 **一句话用法:** 在 DSH 里存好 OpenCode Go key → 设置 `web-search-deepseek.baseURL` → 运行安装脚本 → 重启 `dsh web` → 照常使用 `web_search`。详细步骤见[使用方法](#使用方法)。 ## 这个补丁改变了什么 这**不是**新的 CLI,也**不是**新的 `web_search` 命令。安装并重启 `dsh web` 后: - 你现有的 `web-search-deepseek` 配置保持不变; - agent 平时的每一次 `web_search` 调用都会走补丁后的 provider; - 补丁 provider 自动补上 OpenCode Go / Zen 需要的路由头。 不需要改 profile patch,不需要新增工具,也不需要改提示词。 ## 问题原因 DSH 内置搜索提供方请求的是 Anthropic 兼容 Messages 端点: ```text POST {baseURL}/messages ``` 如果你这样指向 OpenCode Go: ```yaml web-search-deepseek: baseURL: https://opencode.ai/zen/go/v1 ``` 上游提供方只会发送常规请求头(`x-api-key`、`authorization`、`anthropic-version` 等), 而 OpenCode Go 还要求一个会话路由头,缺失就返回 `MissingSessionID` / HTTP 400。 OpenCode Go 本身支持原生 `web_search_20250305`,缺的只是这个路由头。 ## 修复内容 本分支保留官方提供方逻辑,新增: - 对 `opencode.ai` 端点自动注入 `x-opencode-session` / `x-opencode-client`; - 额外的 `headers`、`sessionId` 配置,便于兼容其他网关; - 安装脚本会把补丁包复制到 DSH web profile 中 bundle 本来就会解析的路径: ```text ~/.dsh/profiles/web/node_modules/@deepseek-ai/dsh-web-search-deepseek ``` DSH 安装目录(`/opt/homebrew/...`、`npm -g` 等)里的官方包**不会被改动**。 ## 快速开始 需要 Node.js 20+(或可用的 `dsh` + `pnpm`),并已存在 DSH web profile。 有两种安装方式;**方式 A** 就是插件市场使用的路径。 ### 方式 A —— 作为 DSH bundle 安装(推荐) ```bash dsh plugin --profile web add github:leeyoung1/dsh-web-search-opencode-go # 然后重启 dsh web ``` 本包声明了 `dsh.bundle`,所以 `dsh plugin` 会自动把它加入 `dsh.profile.bundles`。它的 `cordis.patch.yml` 会禁用官方 `web-search-deepseek` 行,并在同一位置插入补丁 provider。 npm 包发布后,命令可以更短: ```bash dsh plugin --profile web add dsh-web-search-opencode-go # 然后重启 dsh web ``` ### 方式 B —— drop-in 复制(离线 / 不用 pnpm) 把补丁包复制进 profile 的 `@deepseek-ai` 槽位,遮蔽官方包;不需要包管理器, macOS、Linux、Windows 通用。 macOS / Linux: ```bash git clone https://github.com/leeyoung1/dsh-web-search-opencode-go.git cd dsh-web-search-opencode-go ./mount.sh # 然后重启 dsh web ``` Windows(PowerShell 或 cmd): ```powershell git clone https://github.com/leeyoung1/dsh-web-search-opencode-go.git cd dsh-web-search-opencode-go node .\bin\dsh-web-search-opencode-go.mjs # 然后重启 dsh web ``` `mount.sh` 只是 POSIX 便捷包装,调用的是同一个 Node 安装脚本。 ### 非默认 profile / DSH home macOS / Linux: ```bash DSH_PROFILE_DIR=/path/to/profile ./mount.sh # 或:DSH_HOME=/path/to/dsh-home ./mount.sh ``` Windows: ```powershell $env:DSH_PROFILE_DIR = "C:\path\to\profile" node .\bin\dsh-web-search-opencode-go.mjs ``` ### 常用参数(方式 B) ```text --dry-run 只显示将要进行的修改,不写 profile --uninstall 把补丁复制件移走,并恢复之前的条目 --help 查看用法与环境变量 ``` 最后**必须重启 `dsh web`**,因为 DSH 只在启动时加载插件。 ## 使用方法 ### 1. 在 DSH 里存好 OpenCode Go API key 打开 **设置 → Models**,把 OpenCode Go 的 key 存成以下任一个名字: - `DEEPSEEK_API_KEY`(provider 默认),或 - `OPENCODE_GO_API_KEY`(然后在下面的配置里写 `apiKeyEnv: OPENCODE_GO_API_KEY`)。 每次搜索都会重新解析 key,所以轮换 key 不需要重启。 ### 2. 把内置搜索 provider 指向 OpenCode Go 编辑 `~/.dsh/settings.yaml`: ```yaml web-search-deepseek: baseURL: https://opencode.ai/zen/go/v1 apiKeyEnv: DEEPSEEK_API_KEY # 默认值;OPENCODE_GO_API_KEY 也可用 model: deepseek-v4-flash # 默认值 ``` ### 3. 安装补丁并重启 按上面的[快速开始](#快速开始)安装,然后重启 `dsh web`。 ### 4. 正常使用 没有新命令。直接对 agent 说: ```text 搜索一下 DeepSeek Harness GitHub 的最新信息 ``` 或者让 agent 调用: ```text web_search: DeepSeek Harness GitHub ``` 预期:正常返回结果,不再出现 `MissingSessionID`。每次搜索会以 `web/deepseek-search-llm-request` 事件记录在 DSH 会话日志中。 ## 配置 你现有的配置无需改动: ```yaml web-search-deepseek: baseURL: https://opencode.ai/zen/go/v1 apiKeyEnv: DEEPSEEK_API_KEY # 默认值;OPENCODE_GO_API_KEY 也可用 model: deepseek-v4-flash # 默认值 ``` 可选的新字段: ```yaml web-search-deepseek: baseURL: https://opencode.ai/zen/go/v1 headers: x-opencode-client: dsh # 覆盖任意自动生成的标头 sessionId: my-fixed-session # 显式指定 OpenCode 路由会话 ``` `x-opencode-session` 的优先级: 1. 显式配置的 `headers['x-opencode-session']` 2. `sessionId` 配置 3. 当前 DSH agent 会话 id 4. 插件级 UUID 兜底(agent 会话之外的直接调用) `x-opencode-client` 默认为 `dsh`,同样可以被覆盖。 ## 安装方式说明 支持两种安装方式: - **DSH bundle(方式 A)**:`package.json` 声明 `dsh.bundle.patch = ./cordis.patch.yml`。`dsh plugin add` 会把包装进 `dsh.profile.bundles`;patch 禁用官方 `web-search-deepseek` 行,并插入本 provider,settings 命名空间(`web-search-deepseek`)与 provider id (`deepseek-official`)保持不变。 - **drop-in 复制(方式 B)**:Node 安装脚本把本包复制到 `/node_modules/@deepseek-ai/dsh-web-search-deepseek`。Node 会优先 解析这个路径,而不是共享的 `profiles/node_modules`,于是原有 bundle 行会 加载到补丁 provider。 两种方式都保留你现有的 `web-search-deepseek` 配置,不需要改 settings。 drop-in 方式下,如果目标路径已存在,脚本会先把它移到 `dsh-web-search-deepseek.unpatched-`,而不是直接删除。 DSH 升级或 `pnpm`/`npm` 重装恢复了官方包之后,重新运行安装脚本并重启 `dsh web` 即可。 ## 卸载 / 回滚 任意系统都可以用跨平台卸载命令: ```bash npx dsh-web-search-opencode-go --uninstall # 或在克隆目录中: node ./bin/dsh-web-search-opencode-go.mjs --uninstall # 重启 dsh web ``` 它会把补丁复制件移到 `dsh-web-search-deepseek.uninstalled-`, 并在存在 `.unpatched-*` 备份时恢复最近的备份;没有备份时 Node 会重新解析 到官方包。 手动等价操作: - macOS / Linux: ```bash rm -rf ~/.dsh/profiles/web/node_modules/@deepseek-ai/dsh-web-search-deepseek # 重启 dsh web ``` - Windows PowerShell: ```powershell Remove-Item -Recurse -Force "$env:USERPROFILE\.dsh\profiles\web\node_modules\@deepseek-ai\dsh-web-search-deepseek" # 重启 dsh web ``` ## 兼容性 - DSH `0.1.x` 系列(已在 `0.1.1-rc.2` 验证)。 - 与 `@deepseek-ai/dsh-web-search-deepseek@0.1.1-rc.2` API 兼容。 - OpenCode Go / OpenCode Zen 的 Anthropic 兼容端点。 - Node.js 20+。 - macOS、Linux、Windows。安装脚本只做文件复制,不使用符号链接或管理员专属 API;CI 会在三种系统上运行安装测试。 ## 常见问题 | 现象 | 原因 | 处理 | |---|---|---| | 安装后仍报 `MissingSessionID` | 没有重启 `dsh web` | 重启 `dsh web`。 | | `WEB_PROVIDER_CREDENTIAL_MISSING` | `DEEPSEEK_API_KEY` 没有存密钥 | 在 DSH 设置 → Models 里存密钥,或设 `apiKeyEnv: OPENCODE_GO_API_KEY`。 | | `DeepSeek search request failed` / HTTP 401/403 | 密钥与端点不匹配 | 用 OpenCode Go 密钥配 `opencode.ai`,或把 `baseURL` 改回 DeepSeek 官方端点并配 DeepSeek 密钥。 | | 提供方不可用 | `baseURL` 无法解析 | 使用带 `/v1` 的完整基址,例如 `https://opencode.ai/zen/go/v1`。 | | DSH 升级后搜索又坏了 | profile 恢复了官方包 | 重新运行安装脚本(`./mount.sh`、`npx dsh-web-search-opencode-go`)并重启。 | | Windows 安装时报 `EPERM` / `EBUSY` | `dsh web` 正在运行,profile 文件被锁定 | 先停止 `dsh web`,重新运行安装脚本,再启动。 | ## 开发 ```bash npm test # 标头 + 跨平台安装脚本测试(无外部依赖) npm run link-deps # 可选:链接官方包,便于在克隆目录直接导入完整 provider node ./bin/dsh-web-search-opencode-go.mjs --dry-run ``` 测试只导入无依赖的 `lib/headers.js`。只有需要在克隆目录中导入完整 `lib/index.js` 时才需要 `link-deps`;安装后的副本会通过 profile 的 `node_modules` 父目录解析官方包。 ## 仓库元信息(便于搜索) 建议的 GitHub 仓库名、描述与 topics: - **仓库名:** `dsh-web-search-opencode-go` - **描述:** `Fix DSH web_search through OpenCode Go / Zen: auto-inject x-opencode-session. Drop-in patched fork of @deepseek-ai/dsh-web-search-deepseek.` - **Topics:** `dsh`, `deepseek-harness`, `deepseek`, `opencode`, `opencode-go`, `opencode-zen`, `web-search`, `websearch`, `dsh-plugin`, `x-opencode-session`, `MissingSessionID`, `cross-platform`, `windows`, `macos`, `linux` 可直接执行的 `gh` 与 `npm` 命令见 [docs/publishing.md](docs/publishing.md)。 ## 许可证与归属 MIT。提供方实现派生自 DeepSeek 的 [`@deepseek-ai/dsh-web-search-deepseek`](https://www.npmjs.com/package/@deepseek-ai/dsh-web-search-deepseek)(同样为 MIT), 原始许可证保留在 [LICENSE](LICENSE)。 本仓库是非官方社区补丁,与 DeepSeek、OpenCode 无隶属关系。