dsh-tavily-web-search
已验证dsh-tavily-web-search · v0.8.0 · MIT · Web 界面
Tavily-backed WebSearchProvider with a pool-only multi-key settings UI, round-robin search, and official per-key usage inspection.
安装
dsh plugin add dsh-tavily-web-search 用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。
源码
发布到 npm 但没有公开仓库。安装前请检查包内容。
标签
说明文档
dsh-tavily-web-search
Tavily 支持的 WebSearchProvider,用于 DeepSeek Harness 的 web 能力缝(ctx.web)。
它把模型侧 web_search 工具的后端从 DeepSeek 官方搜索 换成 Tavily —— 每次搜索直接调用 POST https://api.tavily.com/search,不再走 DeepSeek API(不再消耗 DeepSeek 的模型 token/配额)。其他一切不变:web_search / web_fetch 工具照旧,LLM、会话等不受影响。
当前版本适配 DSH 0.2.0-rc.1(
@deepseek-ai/dsh-*0.2.0-rc.1 /@deepseek-ai/cordis4.0.4)。从 0.7.0 升级到 0.8.0 只改了「兼容声明」:DSH 0.2.0 启动前会校验每个 profile 插件的
peerDependencies是否满足当前运行时(见下方「与 DSH 0.2.0 的兼容」)。插件用到的所有 API 在 0.1.7 → 0.2.0 之间没有变化,因此 host/client 两半的实现保持原样。
特性
- 多 Key 池:在 Web 设置页添加、重命名、替换、启停和删除多个 Tavily API Key。
- 轮询搜索:搜索在「启用且已配置」的 Key 之间轮询(round-robin);被停用的 Key 不参与搜索。
- 用量查询:每个 Key 均可点击「查询用量」,调用 Tavily 官方
GET /usage读取实时积分用量,界面显示 已用 / 总量 和进度条(如79 / 1000 积分)。- 停用的 Key 仍可查询用量,只是不参与搜索。
- 凭据安全:Key 值通过凭据服务(
ctx.credentials)存储,永不写入配置文件,也不会返回浏览器;配置里只保存 Key 的显示名称、生成的凭据引用和启用状态。 - 超时保护:
timeoutMs会与调用方的取消信号合并,超时报中文错误。 - 中文报错/提示:插件产生的错误与提示均为中文,便于排查。
工作原理
- 插件导出一个
Configschema 和一个apply,注册 id 为tavily的WebSearchProvider(通过ctx.web.registerSearchProvider)。 - bundle patch 把
web服务的searchProvider从deepseek-official改为tavily,并插入本插件的行web-search-tavily。 - 每次
web_search调用 → 直接向 Tavily REST API 发请求 → 结果映射为 DSH 标准WebSearchResult(url / title / snippet / publishedAt)。 - 模型侧的
web_search工具本身(@deepseek-ai/dsh-tool-web)完全不动,所以模型看到的能力没有任何变化。
DSH 0.1.7 起沿用至今的配置模型
自 0.1.7 起(0.2.0 未变)取消了「插件注册设置命名空间」的旧模型(ctx.settings.installSection / ctx.settingsScope):
- 插件自己的
Config就是配置界面。配置服务的describe()按 profile 行 id 暴露每个插件条目的 schema 与实时取值,浏览器端用ctx.configForms.get('<行 id>')拿到共享表单。 - 因此行 id = 设置命名空间:本插件的行 id 是
web-search-tavily,客户端TAVILY_NS与之一致。 - 只有声明为
.volatile()的字段才会被渲染为可编辑项,并且每次操作都读取实时值(无需重启、无需重挂插件)。 - 保存走
mutate(ops, revision)的路径写入 + 版本栅栏,一次保存是一次原子写入。 - 本插件自己提供设置页面,所以
apply里调用ctx.settings.configure({ auto: false }, ctx.fiber),避免配置服务再自动生成一个重复的页面。
与 DSH 0.2.0 的兼容
DSH 0.2.0 新增了一道启动前置校验:在挂载任何插件之前,launcher 会读取每个 profile 行(以及每个 bundle)的
package.json,把它声明的 @deepseek-ai/dsh / @deepseek-ai/dsh-* peer 依赖与当前运行时版本做
semver 比对;只要有一个区间不满足,该行就被静默禁用(dsh --dump-config 会打印
disabling profile plugin ...)。这正是 0.7.0 在 0.2.0-rc.1 上失效的原因:它的 peer 区间是
^0.1.7-alpha.1,而 0.2.0-rc.1 不在其中。
因此 0.8.0 的改动集中在 manifest:
| 项 | 0.7.0 | 0.8.0 |
|---|---|---|
peerDependencies 的 dsh 区间 |
^0.1.7-alpha.1 |
^0.2.0-rc.1 |
@deepseek-ai/cordis |
^4.0.3 |
^4.0.4 |
@deepseek-ai/schemastery |
^3.18.3 |
^3.18.4 |
engines.dsh |
无 | >=0.2.0-rc.1 <0.3.0 |
engines.dsh目前只是声明性元数据(0.2.0 的 launcher 不读取engines),真正决定行是否挂载的是peerDependencies。两者写同一个区间,是为了让「只读 manifest」和「实际校验」得出同一结论。
插件用到的 host/client API 在 0.1.7 → 0.2.0 之间没有破坏性变化,所以 lib/index.js(host 半,手写维护)与
src/client/ 的实现无需改动。唯一的构建侧调整是 tsdown.config.ts 把已弃用的
external / noExternal 换成现在的 deps.neverBundle / deps.alwaysBundle(产物逐字节等价)。
浏览器半的模块表(platform seed)在 0.2.0 与 0.1.7 相同,仍是
react / react/jsx-runtime / react-dom / react-dom/client / @deepseek-ai/cordis /
@deepseek-ai/dsh-client-store / @deepseek-ai/dsh-client-ui-slots /
@deepseek-ai/dsh-client-ui-primitives / @deepseek-ai/dsh-client-ui-dockkit。
lib/client.js 只 require 其中的 @deepseek-ai/dsh-client-ui-primitives;其余 dsh 包(renderer、
settings、locale、api-remotes、credentials)都是仅类型导入,编译后被擦除。
验证兼容性
npm run verify # 5 道闸门,见下
verify-compat.mjs—— 直接调用 DSH 自己的evaluatePluginCompatibility(dsh-app-boot导出, 也就是启动校验用的同一个函数),断言本包的 manifest 能通过 0.2.0-rc.1 的前置校验;同时守住 peer 区间不再回退到 0.1.x。verify-client-manifest.mjs—— 用dsh-client-modules真正的parseDshClient校验dsh.client声明,并检查lib/client.js的每个require都落在平台种子或声明的external里。verify-bundle.mjs—— 产物的 loader 交接、平台种子、旧 API 残留。verify-client.mjs—— 浏览器半运行时检查:注意它不再手抄SettingsFormModel,而是从@deepseek-ai/dsh-client-ui-primitives的真实产物里就地提取该实现来跑,避免转录副本与线上实现漂移。smoke.mjs—— host 半集成测试:真实ctx.web+ctx.webServer+ 真实Configschema, 覆盖 provider 选择、轮询、结果映射、超时与/api/tavily/usage路由。
API Key 配置(推荐:Web 设置页)
配置路径:设置 → Tavily 搜索(settings.section 槽位,与「飞书通知」同级)。API Key 池为空或全部停用时,搜索不可用。
- 支持添加、重命名、替换、启停和删除多个 API Key;搜索在启用且已配置的 Key 之间轮询。
- Key 是只写控件:通过凭据服务(
ctx.credentials)存储,永不写入配置文件,也不会返回浏览器。 - 每个 Key 可以按需调用 Tavily 官方
GET /usage查询实时积分用量、上限和搜索用量。 - 同时可以配置 接口地址 / 搜索深度 / 最大结果数,下一次搜索立即生效。
安装
1. 打包
npm install
npm run build # 生成 lib/client.js
npm pack # 生成 dsh-tavily-web-search-<version>.tgz
2. 装进 profile
把 tgz 安装为 profile 的依赖,并加入 bundle 列表(否则插件的 cordis.patch.yml 不会生效):
cd "$DSH_HOME/profiles/web"
pnpm add file:/path/to/dsh-tavily-web-search-0.8.0.tgz
package.json:
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-tavily-web-search" // ← 新增,放在 dsh-web-app 之后
]
}
}
3. 迁移旧 Key 池(从 0.6.x 升级时)
0.6.x 的 Key 池存在旧的 $DSH_HOME/settings.yaml 里,0.1.7 已不再读取该文件。把该 section 原样搬进 profile 的 cordis.patch.yml(凭据引用不变,因此已存的密钥继续可用):
- id: web-search-tavily
name: dsh-tavily-web-search
config:
keys:
- id: mth3iduzu7kb77
name: 我的
ref: TAVILY_API_KEY_MTH3IDUZU7KB77
enabled: false
4. 重启生效
重启 dsh web。此后模型侧每次 web_search 都会走 Tavily。
配置项
| 键 | 默认值 | 含义 |
|---|---|---|
keys |
[] |
API Key 池的非敏感元数据;Key 值存储在凭据服务中 |
endpoint |
https://api.tavily.com/search |
Tavily 搜索端点 |
searchDepth |
advanced |
搜索深度:basic / advanced |
maxResults |
8 |
每次搜索返回的最大结果数 |
timeoutMs |
30000 |
单次请求超时(毫秒),与调用方取消信号合并 |
验证
安装并重启后,让模型做一次 web_search(例如查一个时效性问题)。如果调用成功,说明已走 Tavily;失败时错误信息为中文且以 Tavily ... 开头。
文件
dsh-tavily-web-search/
├── package.json # 插件清单 + bundle patch + dsh.client 声明
├── cordis.patch.yml # 把 searchProvider 指向 tavily 并插入插件行
├── lib/
│ ├── index.js # TavilySearchProvider 实现(host 端,手写维护)
│ ├── index.d.ts # 类型声明
│ ├── client.js # 浏览器端 bundle:设置页 Tavily tab(tsdown 构建)
│ └── types/client/ # 客户端类型声明
├── src/
│ ├── index.ts # node 入口(转出 lib/index.js)
│ └── client/ # 浏览器端源码(tsdown 构建)
│ ├── index.ts # 客户端插件主体:注册 settings.section 槽位
│ ├── service.ts # TavilyTabController(共享表单 + 凭据/用量管理)
│ ├── TavilyTab.tsx # 设置页 Tavily 卡片 UI
│ ├── TavilyTab.module.css
│ └── locales.ts # 中英文案(settings.tavily 命名空间)
├── scripts/
│ ├── build.mjs # 构建包装(Windows 代码页处理)
│ ├── verify-compat.mjs # manifest 是否通过 DSH 0.2.0 启动前置校验
│ ├── verify-client-manifest.mjs # dsh.client 声明 + 模块表请求可解析
│ ├── verify-bundle.mjs # bundle 静态检查(handoff / 平台模块 / 无旧 API)
│ ├── verify-client.mjs # 浏览器半运行时检查(跑真实 SettingsFormModel)
│ ├── smoke.mjs # host 半集成测试(真实 web 缝 + webserver + 路由)
│ └── test-search.mjs # 真实 Tavily 搜索/用量探测(需要真实凭据)
├── tsdown.config.ts # 浏览器 bundle 配置(CSS Modules 内联)
└── README.md
开发
npm install
npm run typecheck # tsc -p tsconfig.typecheck.json
npm run build # tsdown → lib/client.js
npm run verify # manifest 兼容 + 客户端清单 + bundle 静态 + 浏览器半运行时 + host 半集成
npm pack