DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Web Search Opencode Ds — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
W

dsh-web-search-opencode-ds

Web Search Opencode Ds

OpenCode 作为 DeepSeek Harness 的网络搜索提供程序:通过 OpenCode 兼容 Anthropic 的 Messages 端点运行 DeepSeek 的服务器端 web_search,并提供独立的设置页面。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:lldwb/dsh-web-search-opencode-ds#0f4a61bd4a84117ef42f8f9a31b9801ded1f9eb2
README兼容性版本

兼容性与来源证明

Web Search Opencode Ds 以 dsh-web-search-opencode-ds 发布,当前版本为 0.2.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/8

版本

0.2.0stable
2026/10/8

相关插件

正在加载相关插件…

最新版
0.2.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/11
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 search-research 分类下经过校验的插件。

Weknora@wxg-prc-cpg/dsh-weknora适用于 DeepSeek Harness (dsh) 的 WeKnora 知识检索工具:通过自有知识库进行语义搜索、文档阅读以及 RAG/代理回答。Free Searchdsh-free-searchDeepSeek Harness 的免费网页搜索:24 个引擎(Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel 无需密钥;通过 MCP 使用 Zhihu 全局/站内搜索,以及 Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao,需密钥;OpenAI/Gemini/ClaudeDejadsh-dejaDeepSeek Harness 的 deja-vu 记忆:其他 40 个编码代理的会话历史,可搜索,并在每个步骤前调用——本地索引,无需 LLM。Builtin Browserdsh-builtin-browser适用于 DeepSeek Harness 的共享真实浏览器插件:安装即用——可由人类接管的可见原生浏览器,并由代理通过 CDP 驱动。DOM 级交互(兼容 React/Vue)、按任务隔离会话、Cookie 持久化(dsh_browser_auth)、C

README

dsh-web-search-opencode-ds

把 OpenCode 注册为 DeepSeek Harness (dsh) 的网页搜索提供方: 让模型侧的 web_search 工具经 OpenCode 调用 DeepSeek 官方的服务端搜索, 并在 dsh 的 设置 → 插件 里提供一张和官方「网页搜索」同款的配置页。

本仓库是一个 dsh bundle,而且是双面的一个:index.js 是 Host 半(注册 opencode-ds provider、 声明 Config schema),client.js 是浏览器半(画那张设置页)。两半由同一个包交付。

名字里没有 go:Go 套餐只是同一个端点家族里的一个选项(goMode 开关),不是这个插件的身份。

包名 / Loader 行 iddsh-web-search-opencode-ds
provider idopencode-ds
设置命名空间web-search-opencode-ds(= Loader 行 id)
默认端点https://opencode.ai/zen/go/v1(Go 套餐,包月)
备用端点https://opencode.ai/zen/v1(按量计费)

为什么是 bundle 而不是另写一个搜索后端:在 dsh 里,ctx.web 这一层已经定义了 WebSearchProvider 契约,DeepSeek 的服务端 web_search 又是 OpenCode 直接提供的原生工具。 插件要做的只是把请求按 OpenCode 的 wire format 发出去、把结果映射回 WebSearchSource, 而不是自己去抓网页、拼摘要。


1. 实测验证结论

以下每一条都是当天对线上端点实打实请求出来的,不是从文档抄的。

观察结果
POST /zen/go/v1/messages + model: deepseek-v4-flash + tools:[{type:'web_search_20250305'}]HTTP 200,返回真实 web_search_tool_result(本次 10 条结果)
同上,但不带 x-opencode-sessionHTTP 400 {"type":"error","error":{"type":"MissingSessionID",...}}
只带 Authorization: Bearer(不带 x-api-key)HTTP 401 AuthError: Missing API key.
只带 x-api-keyHTTP 200
GET /zen/go/v1/models200,43 个模型,含 deepseek-v4-flash
GET /zen/v1/models200,85 个模型,也含 deepseek-v4-flash
POST /zen/v1/messages(按量计费端点)HTTP 402 Insufficient account funds —— 路由与鉴权都通,只是这个账户没有按量余额
候选会话创建路径(/sessions、/session、/zen/v1/sessions…)全部 404 —— 根本没有「先建会话」这一步

由此得到的硬结论

  1. x-opencode-session 是强制头,而且由客户端自己生成。 默认每次搜索新生成一个 UUID v4 (sessionMode: 'per-request'),'stable' 则全程复用同一个。既然没有注册端点、响应里也没有 会话 id,「先创建会话」这条分支不存在,不需要实现。
  2. 真正鉴权的是 x-api-key。 最初的需求写的是只用 Authorization: Bearer,但那样会被 401 拒绝。 本插件两个头都发,这样网关两种行为都活得下来。
  3. 两个端点共用一套 wire format。 goMode 只改 base URL,请求体、头、模型全都不变; deepseek-v4-flash 在两个目录里都存在,所以切模式不需要换模型。
  4. 按量计费端点要账户有余额。 本机账户只有 Go 套餐,所以 /zen/v1 稳定返回 402。 这是账户事实,不是插件 bug —— 插件会把 402 单独翻译成「余额不足,要么充值、要么把 goMode 打回开启」的提示,而不是笼统报一个 HTTP 错误。

一个必须知道的限制:响应里没有 snippet

web_search_result 条目只带 title、url、page_age,外加一个不透明的 encrypted_content, 没有摘要文本。摘要只可能出现在 text 块的 citations[].cited_text 里。

插件的处理:有 cited_text 就按 url 拼成 snippet,没有就干脆不返回 snippet 字段, 而不是拿标题或正文去伪造一段。搜索结果里 snippet 缺失是预期行为。


2. 安装

需要 dsh 桌面版,且 plugin_manager 可用。

2.1 克隆到本地再安装(推荐,最稳)

git clone https://github.com/lldwb/dsh-web-search-opencode-ds.git
cd dsh-web-search-opencode-ds
pnpm install          # 装唯一的运行时依赖 @deepseek-ai/schemastery,见 §10
plugin_manager { "action": "install_bundle", "target": "<你克隆到的绝对路径>" }

plugin_manager 会把这个包写进当前 profile 的 dsh.profile.bundles,并跑一次 pnpm。

2.2 为什么必须自己跑一次 pnpm install

这是本插件与纯配置型 bundle 最大的不同:它有真实依赖。

plugin_manager install_bundle 对 link: 形式的依赖不会安装被链包自己的依赖, 而 dsh 的 @deepseek-ai/* 包又不从 profile 目录解析(见 §10)。所以 @deepseek-ai/schemastery 必须装进这个包自己的 node_modules,Node 才能相对 index.js 找到它。 忘了这一步的症状是启动时报 Cannot find module '@deepseek-ai/schemastery'。

pnpm-lock.yaml 已随仓库提交,所以装到的版本是确定的。

2.3 本地开发时

profile 用 link: 依赖指向工作副本:

// ~/.dsh/profiles/<profile>/package.json
"dependencies": { "dsh-web-search-opencode-ds": "link:E:/dsh-plugins/dsh-web-search-opencode-ds" },
"dsh": { "profile": { "bundles": [ /* … */ "dsh-web-search-opencode-ds" ] } }

2.4 改动如何生效

  • Host 半 / patch 改动:plugin_manager set_bundle 先 enabled:false 再 enabled:true, 会返回 "application":"applied" 并热应用,不需要重启。 (install_bundle 在无变化时返回 "restart-required",那个不会热应用。)
  • Client 半改动:client 插件的 HMR 接收器是活的,会直接重载;只有需要重建 bundle 时才要刷新页面。

3. 凭据配置

provider 在每次搜索前重新解析密钥,所以轮换密钥不需要重启。

方式 A:写进 DSH 凭据库(推荐)

在插件的设置页里填 API Key 并保存即可 —— 它走的是 DSH 的 credentials 域,不会写进设置文件。

也可以直接写 ~/.dsh/.credentials.yaml 的 refs::

refs:
  OPENCODE_API_KEY: sk-...

两个引用名都会被尝试,顺序是:设置里 apiKeyEnv 指定的那个 → OPENCODE_API_KEY → OPENCODE_GO_API_KEY。所以旧版本存在 OPENCODE_GO_API_KEY 下的密钥改名后照样能用。

方式 B:进程环境变量

export OPENCODE_API_KEY=sk-...        # 或 OPENCODE_GO_API_KEY

方式 C:插件 config 字面量

在 cordis.patch.yml 里给这一行加 apiKey: sk-...。字面量优先级最高,但会明文落在配置文件里, 不建议。


4. 设置页(GUI)

装好后打开 设置 → 插件,官方「网页搜索」卡片下面会多出一张 「网页搜索(OpenCode)」(plugins.item 槽位,order: 41,官方那张是 40)。

页面上有五个控件:

控件字段说明
API KeyapiKey只写不读。写进凭据库;留空表示不改动现有密钥
接口地址baseURL留空则按下面的模式自动决定
单次请求最多搜索次数maxUses一次请求在必须作答前最多搜几次
覆盖官方网页搜索配置overrideOfficial见 §4.1
使用 OpenCode Go 套餐goMode见 §4.2

页面只在 Host 真的提供了这个命名空间时才挂载,所以没装插件的部署上看不到任何痕迹。

4.1 开关一:是否覆盖官方配置(overrideOfficial)

这个开关不需要重启,立即生效,因为 provider 在每次搜索时才决定怎么走:

取值行为
开(默认)用本页配置的端点与密钥,自己调 OpenCode
关把搜索原样转交给随附的 deepseek-official provider

「关」的意义是:官方那套配置(接口地址 https://api.deepseek.com/anthropic、DEEPSEEK_API_KEY、 它自己的搜索预算)继续说了算,本插件完全不插手。

实现方式不是去改 web.searchProvider —— 那个字段不是 .volatile(),进程启动时就固化了, 运行时改不了;而且没有固定值时两个 provider 都可用会直接撞上 WEB_PROVIDER_AMBIGUOUS。 真正的做法是:本插件作为被选中的 provider,在 search() 里把请求委托给 ctx.web.searchProviders.get('deepseek-official')。这是一个活的决定,所以开关立刻生效。

如果 deepseek-official 没有挂载,search() 会明确报错说明「没有可转交的对象」,而不是静默失败。

4.2 开关二:Go 模式 vs 按量计费(goMode)

取值端点计费
开(默认)https://opencode.ai/zen/go/v1OpenCode Go 包月套餐
关https://opencode.ai/zen/v1默认按量计费 API,按次扣费

注意:按量计费端点需要账户有余额。没有余额时它会回 HTTP 402,插件会把这条错误单独 翻译成「余额不足」的说明。如果你的账户只有 Go 套餐,就保持这个开关开启。

接口地址栏如果填了具体值,永远优先于这个开关(留空才是「按模式决定」)。


5. 配置项参考

设置页只能改 .volatile() 字段;下表其余项是加载期配置,只能写 cordis.patch.yml。

字段默认值volatile说明
apiKey—✅(secret)字面量密钥,优先级最高,不会被表单持久化
apiKeyEnvOPENCODE_API_KEY✅(credential-ref)凭据引用名
baseURL空✅空 = 按 goMode 决定
modeldeepseek-v4-flash✅Anthropic 格式模型名
apiVersion2023-06-01✅anthropic-version 头
maxTokens4096✅生成上限
maxUses5✅服务端搜索次数上限
timeoutMs30000✅单次尝试超时
includeAnswerfalse✅是否把模型正文放进 content
overrideOfficialtrue✅见 §4.1
goModetrue✅见 §4.2
retries1❌首次之外的重试次数
sessionModeper-request❌per-request | stable
queryTemplatePerform a web search for the query: {query}❌提示词模板

重试策略

重试的状态码:408 409 425 429 500 502 503 504。网络错误、超时,以及 400 MissingSessionID 也算可重试。401/403 和 402 不重试 —— 重试不会让密钥变好,也不会让账户有钱。 退避为 500ms × 尝试序号,且可被调用方的 AbortSignal 打断。


6. DSH 如何选中这个 provider

ctx.web 在每次调用时解析提供方:

  • 配置了 id 且已注册且 available() → 用它
  • 配置了 id 但没注册 → WEB_PROVIDER_CONFIGURED_MISSING
  • 配置了 id 但不可用 → WEB_PROVIDER_CONFIGURED_UNAVAILABLE
  • 没配 id,恰好一个可用 → 用它
  • 没配 id,多个可用 → WEB_PROVIDER_AMBIGUOUS
  • 没配 id,没有可用 → WEB_PROVIDER_UNAVAILABLE

本插件的 bundle patch 固定了 web.searchProvider: opencode-ds,所以它一定是被选中的那个; 「用不用官方配置」再交给 overrideOfficial 决定。

⚠️ id 定向 patch 会整体替换该行的 config,不做深合并。 随附的 web 行目前没有 config, 所以只写 searchProvider 不会丢东西。但如果将来有更高优先级的层(比如 profile 自己的 cordis.patch.yml)给 web 行加了 fetchProvider,那一层必须同时重写两个字段。

层序:所有 bundle patch → profile 自己的 cordis.patch.yml → --patch 覆盖。 所以 profile 里若也写了 web 行,会覆盖本 bundle 的固定值。

环境变量覆盖

DSH_WEB_SEARCH_PROVIDER=opencode-ds 与配置里的 searchProvider 等价(不是隐藏的优先级链)。


7. 回退到随附的 deepseek-official

三种方式,任选一种:

  1. 最省事:设置页里把「覆盖官方网页搜索配置」关掉。官方的端点与密钥立刻重新生效。
  2. 把 profile 的 cordis.patch.yml 里加上 web 行并把 searchProvider 改成 deepseek-official。
  3. plugin_manager set_bundle dsh-web-search-opencode-ds enabled:false 整个停用。

8. 自检

端点验证脚本

# bash / Git Bash / WSL
OPENCODE_API_KEY=sk-... ./scripts/probe-opencode.sh "你的查询" go
OPENCODE_API_KEY=sk-... ./scripts/probe-opencode.sh "你的查询" metered
# Windows PowerShell
$env:OPENCODE_API_KEY = 'sk-...'
.\scripts\probe-opencode.ps1 "你的查询" go
.\scripts\probe-opencode.ps1 "你的查询" metered

脚本会断言 200 / 400 / 401 三种情形,再检查响应里有没有 web_search_tool_result、 server_tool_use、usage.server_tool_use.web_search_requests。

  • 退出码 0 = 全部符合预期(按量模式下的 402 会单独标成 UNFUNDED(402) 并仍然退 0)
  • 1 = 有偏差
  • 2 = 缺凭据或缺工具

单元测试(不需要网络)

node --test test/parse.test.mjs      # 40 个用例

确认某次搜索到底是谁服务的

随附的 deepseek-official 在派发前会往会话里追加 web/deepseek-search-llm-request 事件, 本插件从不写这个事件。所以在会话日志里 (~/.dsh/sessions/<slug>/<sessionId>/session.v4.jsonl.zstd,注意是多帧 zstd, 每个 append 一帧,必须按帧魔数 28 B5 2F FD 切开分别解压):

搜索产生了结果,而这次调用没有对应的 web/deepseek-search-llm-request ⇒ 就是本插件服务的。


9. 故障排查

现象原因与处理
页面压根不出现Host 没提供命名空间。Config.listConfigs 里该行 status 必须是 "schema"(不是 "absent")。"absent" 意味着插件没声明 Config。
页面出现但插件列表里没有Loader 没重读 profile。set_bundle 关再开一次。
WEB_PROVIDER_CONFIGURED_MISSING固定了 opencode-ds 但插件没注册上 —— 看 Host 日志里插件是否加载失败。
401密钥不对,或者用错了模式(Go 套餐的密钥不等于按量计费可用)。
402按量计费端点余额不足。充值,或把 goMode 打回开启。
400 MissingSessionIDx-opencode-session 被中途剥掉了。插件每次都生成,看到这个说明有代理在改请求。
抓不到 snippet预期行为,见 §1。响应里本来就没有摘要。
Cannot find module '@deepseek-ai/schemastery'插件目录里没跑过 pnpm install,见 §2。

10. 设计说明

为什么除了 schemastery 之外必须是零 @deepseek-ai/* 依赖。 DSH 自己的包不从 profile 目录解析(@deepseek-ai/dsh-web、@deepseek-ai/dsh-credentials 在 profile 下都是 MODULE_NOT_FOUND),所以 profile 装的插件 import 不到它们。 @deepseek-ai/schemastery 是公开发布的 MIT 包,装进本包自己的 node_modules, 是 Node 相对本文件唯一能解析到的那个 —— 而声明 Config 又必须要它。

为什么 Config 用 .volatile()。 DSH 的设置服务只把活跃 profile 条目上的 volatile 字段投影成表单,并通过 profile 的 Cordis patch 持久化。没有 Config → 没有命名空间 → 设置页无从挂载;字段不 volatile → 表单里看不到。 所以「能不能配」完全由 schema 上的 .volatile() 决定。

为什么 configure({ auto: false })。 自带页面的插件要显式关掉 schema 自动生成页面。它注册在 ctx.inject(['settings'], …) 的可选子级里 —— 这样没有 settings 服务的 profile 也能正常跑, 而且策略绑在插件自己的 fiber 上,Settings 服务迟到或换实例也会采用。

为什么「覆盖官方配置」用委托而不是改配置。 web.searchProvider 不是 volatile,构造时就固化,运行时改不动;改成别的 id 还会在两个 provider 都可用时撞上 WEB_PROVIDER_AMBIGUOUS。委托是唯一既立即生效又不动别人配置的做法。

为什么结果不二次截断。 maxResults 的裁剪归 ctx.web 这一层管(capSources),所以插件的 truncated 恒为 false, 不会把本来正确的长度再砍一刀。


11. 参考

  • OpenCode Go 文档:https://opencode.ai/docs/go/
  • OpenCode Zen 文档:https://opencode.ai/docs/zen/
  • web_search_20250305 工具语义(Anthropic Messages)
  • DSH ctx.web 服务契约(WebSearchProvider / WebSearchSource)
  • DSH 设置子系统:@deepseek-ai/dsh-settings、@deepseek-ai/dsh-client-ui-settings-web-search

12. 已知限制

  • 配置整块替换:Cordis 的 id 定向 patch 会替换该行的整个 config,不做深合并。 bundle 里固定了 web.searchProvider: opencode-ds;如果你自己的 cordis.patch.yml 里也有 web 行, 它层级更高,会整体覆盖本 bundle 的固定值(包括把 fetchProvider 一起抹掉)。 此时请把 searchProvider 一并写进你自己的那一行,或删掉自己的行交给本 bundle 管。
  • 响应里没有摘要:OpenCode 返回的 web_search_result 只有 title / url / page_age, 没有 snippet。插件不会伪造摘要,所以结果里 snippet 缺失是预期行为(见 §1)。 想要摘要就把 includeAnswer 打开,模型正文会作为 WebSearchResult.content 返回。
  • 按量计费端点要余额:goMode: false 走 /zen/v1,账户没钱会返回 HTTP 402。 只有 Go 套餐的账号请保持 goMode 开启。
  • 不校验远端目录:插件不检查 model 在目标端点的模型清单里是否存在,写错了要到实际调用才报错。
  • Go / 按量是两个独立权益:同一个 OpenCode 账号上,Go 套餐的密钥不等于按量计费可用,反之亦然。
  • 端点行为、模型目录都可能随时变动;§1 的实测结论标注了日期,请以你的实际请求为准。

License

MIT — 见 LICENSE。