dsh-plugin-deepsearch
Verifieddsh-plugin-deepsearch · v0.2.0 · MIT · Web UI
Switch DSH's built-in web_search between the DeepSeek Search API (/v1/tools/search) and the default account search, with live fallback, a settings page and a sidebar switch.
Install
dsh plugin add dsh-plugin-deepsearch Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-plugin-deepsearch
给 DSH 内置的 web_search 加一个开关:走 DeepSeek Search API(POST /v1/tools/search),还是走 DSH 默认的账号搜索。附带自动回退、设置页、侧栏开关和模型工具。
English | 中文说明
- 开关 ON(
deepseek-api) — 内置web_search改由 DeepSeek Search API 提供服务。这是付费接口:成功请求由 DeepSeek 计费,开启前请以 DeepSeek 控制台中的当前价格为准。 - 开关 OFF(
builtin) — DSH 默认路线:由账号在服务端完成搜索(一次搜索消耗一次模型轮次)。 - 切换立即生效,重启后仍保留:状态落盘在
$DSH_HOME/deepsearch-mode.json。 - 不会让搜索不可用。 没有 key、401、网络错误、429/5xx 重试用尽时,提供方会回退到之前的(或其他可用的)搜索提供方,并在
lastError里说明原因。 - 零运行时依赖 —— 只用
node:内置模块和全局fetch,没有构建步骤。 - 设置页与侧栏开关支持中英双语。
它做了什么
插件由两半组成,必须配合工作:
| 半侧 | 文件 | 职责 |
|---|---|---|
| Host | index.js |
注册模型工具 deepsearch、注册搜索提供方(默认 id deepseek-search-api)、将 web.searchProviderId 切到本插件/切回、暴露 /deepsearch/ 下的 4 个 HTTP 路由、解析 API key。 |
| 浏览器 | client.js |
通过 window.__ModuleLoader__.load(...) 加载的手写 bundle:设置页 tab + 侧栏底部开关。 |
cordis.patch.yml 是 bundle patch:用 dsh plugin add(或从插件市场)安装时,包会装进 profile 的 node_modules(并记在 profile package.json 的 dsh.profile.bundles 里),bundle 层在启动时应用它——不需要再手工改 profile 的 patch。
三个入口
| 入口 | 位置 | 用途 |
|---|---|---|
| 设置页 | 设置 → 内置插件 →「DeepSeek 搜索」 | 开关、状态详情、测试接口、API key 编辑 |
| 侧栏开关 | 左侧栏底部常驻 | 一键切换,显示当前路线(API / builtin) |
| 模型工具 | deepsearch(status / on / off / search / fetch / check) |
在对话里切换路线或直接发起搜索 |
安装
从插件市场安装
在 DSH 插件市场里搜索 dsh-plugin-deepsearch(或「DeepSeek 搜索」)并安装。市场会用包里的 dsh.bundle.patch 自动注册 Host 半侧。安装后,设置页 tab 出现在 设置 → 内置插件 →「DeepSeek 搜索」(英文界面为 Settings → Built-in plugins → DeepSeek Search);第一次安装后可能需要刷新一次页面,浏览器才会加载到新的 client bundle。
从命令行安装
# 装进默认 profile
dsh plugin add dsh-plugin-deepsearch
# 或显式指定 profile:`web` 对应 dsh web 服务端
dsh plugin --profile web add dsh-plugin-deepsearch
桌面端(Desktop app) 使用 desktop profile / 应用内的插件市场 UI 安装(桌面端会用自己的 DSH home 管理 profile,不需要手输用户目录路径)。插件的浏览器半侧声明了 dsh.client.platform: "web",桌面端的 web 壳同样会加载它。
如果是从仓库源码安装而不是从 registry 安装:先 npm pack,再用 dsh plugin add 安装生成的 tgz。
从 0.1.x 升级
0.1.x 没有 bundle patch,是手工安装的:在 profile 的 cordis.patch.yml 里加一条 insert:
- insert:
- id: deepsearch
name: dsh-plugin-deepsearch
0.2.0 起带上了 dsh.bundle.patch(包根目录的 cordis.patch.yml)。dsh plugin add 或插件市场安装不会往 profile patch 里写 insert 记录:它把包装进 profile 的 node_modules,记到 profile package.json 的 dsh.profile.bundles 里,再由 bundle 层在启动时应用包自带的 cordis.patch.yml。在以 bundle 方式安装 0.2.0 之前,请先删掉手工加的那条 insert——手写的 insert 加上 bundle 安装会把同一个插件加载两次。$DSH_HOME 下的开关状态文件与 key 文件会保留,所以升级后开关状态和 key 都还在。
profile 名字因客户端而异:dsh web 服务端用 dsh plugin --profile web add dsh-plugin-deepsearch;桌面端用 desktop profile 和它的插件市场 UI。不要手写完整 profile 路径,让 dsh plugin 自己解析。
卸载
从 profile 卸载这个包(或在插件市场里卸载)即可,插件不会往 profile 里加别的文件。$DSH_HOME 下的 deepsearch-mode.json(状态)、deepsearch-diag.json(诊断)和可选的 deepsearch-key.txt(key 文件)可以删掉,也可以留着以后重装用。
配置
配置来自 profile patch 中本插件条目的 config 块;所有值都会被规范化,非法值回退默认值而不会抛错:
- insert:
- id: deepsearch
name: dsh-plugin-deepsearch
config:
apiKeyEnv: DEEPSEEK_API_KEY
count: 8
retryCount: 1
所有 key 都是可选的。下表与 Host 的配置 schema 一致,bundle 安装也可以携带同样的 config。
| 配置项 | 默认值 | 规范化 / 含义 |
|---|---|---|
apiKey |
'' |
内联 API key。字符串,去首尾空白;空字符串表示未设置。不推荐:它会留在 patch 文件里。任何路由都不会回显它。 |
apiKeyEnv |
'DEEPSEEK_API_KEY' |
要解析的凭据引用 / 环境变量名。必须匹配 /^[A-Za-z_][A-Za-z0-9_]*$/,否则使用默认值。 |
baseURL |
'https://api.deepseek.com' |
API 根地址。去首尾空白;必须能解析为 http(s) URL;末尾斜杠会被去掉。 |
searchPath |
'/v1/tools/search' |
搜索接口路径(拼在 baseURL 后)。去空白、强制以 / 开头;含 ? 或 # 的值会被拒绝;空值回退默认。 |
fetchPath |
'/v1/tools/fetch' |
抓网页接口路径(规则同 searchPath)。 |
keyFile |
'' |
文件形式的 key 路径。'' 表示 $DSH_HOME/deepsearch-key.txt;~/... 展开到用户主目录;相对路径解析到 $DSH_HOME 下;其他按绝对路径使用。 |
count |
8 |
搜索结果条数。整数,夹取到 1..50。 |
needContent |
false |
是否让搜索接口返回正文(只影响直接调用 deepsearch search)。只有严格的 true 才开启。 |
timeoutMs |
30000 |
单次 HTTP 请求超时。整数,夹取到 1000..120000。 |
retryCount |
1 |
首次之外的重试次数(针对 408/429/5xx)。整数,夹取到 0..3。 |
retryDelayMs |
1200 |
两次重试之间的等待时间。整数,夹取到 100..10000。 |
maxFetchChars |
20000 |
fetch / 请求正文的 search 工具最多返回的字符数。整数,夹取到 1000..200000。 |
providerId |
'deepseek-search-api' |
注册的搜索提供方 id。必须匹配 /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,且不能与已存在的其他提供方冲突(本插件自己的重复注册除外)。 |
fallbackProvider |
'' |
关闭开关时优先回退到的提供方 id。空字符串表示自动判断(先前使用的提供方,然后是第一个可用的非本插件提供方)。 |
fallbackOnError |
true |
Search API 调用失败时是否回退到其他提供方。只有严格的 true 才开启。 |
language |
'auto' |
auto / en / zh。auto 依次读取 DSH_LANGUAGE、DSH_LOCALE、LANG、LC_ALL(中文 locale 解析为 zh,其余为 en)。 |
checkQuery |
'DeepSeek' |
「测试接口」按钮使用的查询词。去空白、非空、最长 128 个字符。 |
规范化后的 config 会通过插件状态(以及 deepsearch 工具的 status 动作)只读暴露,不含 apiKey。key 本身永远不会出现在诊断、日志或任何响应体里。
API Key
Search API 需要 DeepSeek 官方 API key。按以下顺序解析,命中即停:
- patch
config里的apiKey(内联,不推荐)。 - DSH 凭据:
apiKeyEnv(默认DEEPSEEK_API_KEY)对应的凭据引用——与 DSH 自带的 设置 → 内置插件 → 网页搜索 页保存的是同一个引用,本插件复用它。 - 环境变量
process.env[apiKeyEnv]。 - key 文件(
keyFile,默认$DSH_HOME/deepsearch-key.txt,第一行是 key)。设置页可以帮你保存/清除这个文件。 $DSH_HOME/.env里的一行DEEPSEEK_API_KEY=sk-...(变量名跟随apiKeyEnv)。
在设置页或 deepsearch status 里确认结果:key.configured 表示是否找到 key,key.kind 是 config、credentials、env、file、env-file 之一,key.source 给出具体来源(环境变量名或文件路径);key.hint 会用当前界面语言给出同样的说明。
key 处理规则:
- key 只在发起请求时读取,不会被打印、记录日志、写进诊断文件,也不会被任何路由返回。
- 设置页提供密码输入框 + 保存 / 清除 按钮。保存会把 key 写到配置的 key 文件(尽力设置文件权限
0600);保存后不会再渲染出 key 的值。 - 没有 key 也不会坏:开关可以保持 ON,提供方会回退到默认账号搜索并说明原因。
切换与回退
- 打开开关(ON)时,如果当前激活的搜索提供方不是本插件,会先把它记为
previousProviderId,再把web.searchProviderId设为本插件的提供方。 - 关闭开关(OFF)时按以下顺序恢复:记住的前一个提供方(若仍注册)→ 配置的
fallbackProvider→ 第一个已注册、不是本插件且未被标记不可用的提供方 → 最后退而使用记住的前一个提供方(即使它已不在注册表里,作为最佳猜测)。如果没有任何其他提供方,保持当前提供方并返回错误,绝不清空 id。插件不会硬编码deepseek-official。 - 提供方级错误回退: 若
fallbackOnError为真且 Search API 调用失败(缺 key、401、网络错误、重试用尽),同样的解析逻辑会选一个其他提供方并返回其结果,记录kind: 'provider.fallback'。fallbackOnError: false时始终抛出原始的结构化错误。 - 取消和超时永不回退 —— 调用方已取消或请求已超时后,不会偷偷再跑一次账号搜索。
- 提供方的
available()恒为true:缺 key 或 API 故障不会让内置web_search消失,只会降级到回退。
设置页与侧栏开关
- 设置 → 内置插件 →「DeepSeek 搜索」:开关(
role="switch"并带 ARIA 属性)、状态行、「测试接口」按钮、详情网格(模式、当前提供方、key 来源、搜索/抓取接口、结果条数、最近调用、最近错误)、API key 编辑区、无 key 时的提示,以及诊断里的接线警告。页面每 5 秒轮询一次状态。 - 侧栏底部开关:一键切换,显示当前走
API还是builtin路线,带本地化 tooltip。每 8 秒轮询一次。
所有页面文案都来自插件自己的 dsh-plugin-deepsearch locale 词典(中文 / 英文),会跟随 DSH 的语言设置。
模型工具
Host 注册一个面向模型的工具,名字是 deepsearch:
| 动作 | 作用 |
|---|---|
status |
返回当前模式、提供方路由、key 状态(不含 key)、接口地址、最近结果/错误。 |
on / off |
与 UI 开关走同一套逻辑切换路线。 |
search |
直接调用 Search API,参数 { query, count?, needContent? };开启回退时失败会自动回退。 |
fetch |
通过 /v1/tools/fetch 抓取一个 URL,返回截断后的正文和元数据。 |
check |
用一次最小查询验证接口连通性,供「测试接口」按钮和快速自检使用。 |
也可以直接在对话里说「打开 / 关闭 DeepSeek 搜索」,agent 会调用 deepsearch 工具切换;工具描述里会写明设置页的英文位置,以及配置写在 profile patch 里。
HTTP 路由
浏览器半侧通过 /deepsearch/ 下的四个路由与 Host 通信:
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/deepsearch/state |
状态快照(不含 key)。 |
POST |
/deepsearch/mode |
设置模式:{ "mode": "on" } / { "mode": "off" }。 |
POST |
/deepsearch/check |
单飞的接口连通性检查。 |
POST |
/deepsearch/key |
保存/清除 key 文件:{ "action": "save", "key": "..." } / { "action": "clear" }。绝不回显 key。 |
这些路由不走 DSH connection 鉴权,所以 Host 自行校验:只接受约定的 method;POST 必须 content-type: application/json、浏览器 Origin 与 Host 同源;拒绝 Sec-Fetch-Site: cross-site;/check 单飞(同时只允许一个请求)。这能挡一般 CSRF,但不替代鉴权——DSH 的 web 服务仍应只监听本机。
安全与可靠性
apply()永不抛错;坏配置会被规范化,而不是让宿主崩溃。- API key 不会被记录日志、回显、由路由持久化,也不在状态快照里;唯一的写入是显式保存动作(文件权限
0600,Windows 上尽力而为)。 - 取消和超时不会触发回退搜索;回退目标失败时以结构化错误结束,而不是在别处静默重试。
- 重试只会在
408/429/5xx上做retryCount次额外尝试,间隔可配置;401映射为凭据错误,不会进入重试循环。 lastError用英文 scope 字符串记录,并在下一次成功调用时清掉,避免页面一直显示过期错误。- 零运行时依赖、没有构建步骤:只用 Node 内置模块和全局
fetch。
兼容性
- DSH:
>=0.1.7-rc.1 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0(声明在package.json的engines.dsh里)。显式预发布分支让0.2.0-rc.2这类宿主能被正确解析;单个宽范围会静默排除预发布版本。 - Node: Host 半侧与测试套件要求
>=20(已在 Node 24 上验证)。 - Profile:
web(浏览器访问的 DSH)与桌面端(Desktop app);浏览器半侧声明dsh.client.platform: "web"。 - 无第三方包、无 post-install 脚本,不需要
allowBuilds之类的构建授权。
开发与测试
仓库是零依赖的纯 ESM 包,跑测试不需要安装任何东西。所有测试文件都是普通 Node 脚本,打印 ok/FAIL,失败时以非零码退出(不用测试框架);测试全程离线,host/client 测试会 mock fetch。
node test/package.test.mjs # 清单、bundle patch、文档与版本一致性
node test/host.test.mjs # Host 半侧:假 Cordis ctx + mock fetch
node test/client.test.mjs # 浏览器 bundle:假 module loader / react / locale
或者按顺序全部跑:
npm test
npm publish 会通过 prepublishOnly 跑同一套测试。CI 只需在 Node 20/22/24 上跑 npm test,不需要 npm install 步骤,就足以保证这个包始终处于可收录状态(见 PUBLISHING.md)。
文件
| 文件 | 作用 |
|---|---|
index.js |
Host 半侧:deepsearch 工具、搜索提供方、路线切换、HTTP 路由、key 解析。 |
client.js |
浏览器半侧:设置页 tab + 侧栏开关(手写 bundle,无构建步骤)。 |
cordis.patch.yml |
Bundle patch:dsh plugin add 时注册 Host 半侧。 |
package.json |
包清单、dsh.bundle / dsh.client 元数据、版本唯一来源。 |
README.md / README.zh.md |
英文 / 中文文档(本文件与英文版)。 |
CHANGELOG.md |
版本历史。 |
PUBLISHING.md |
维护者清单:身份替换、npm 发布、市场投稿。 |
LICENSE |
MIT。 |
icon.svg |
插件市场使用的小方图标。 |
test/ |
打包、Host、浏览器三套测试。 |
许可证
MIT。Copyright (c) 2026 SeaViod。
问题或 bug 反馈:提交 issue。