npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zzy001/dsh-web-search-tavily

v0.3.0

Published

Multi-key Tavily search provider for DeepSeek Harness (ctx.web) with a live settings card in the web plugin configuration page

Readme

dsh-web-search-tavily

0.2.0 命名对齐0.1.xtavily-search 已全面对齐官方 web-search-* 族,更名为 web-search-tavily。从 0.1.x 升级需将 $DSH_HOME/settings.yaml 中的 tavily-search: 键手动改为 web-search-tavily:(或在设置卡片重新填入),patch 会自动清理旧 tavily-search 残留。

DeepSeek Harnessdsh)提供基于 Tavily 的联网搜索能力。

  • 多 key 轮询:支持配置 1..n 个 Tavily API key,按轮询调度;某个 key 触发 429(免费额度耗尽/限流)时自动冷却并切换到下一个 key,把多个免费账号的月额度叠加起来。
  • 可视化配置:安装后在 设置 → 插件 → 插件配置 出现「Tavily 搜索」卡片,可增删 key、填密钥(只写输入框,永不回传)、调搜索参数,全部热生效无需重启
  • 零侵入:注册到官方 ctx.web 能力 seam,模型侧 web_search 工具 schema 不变,内置 DeepSeek 搜索被替换。

兼容性

| 项 | 值 | | ---------------- | ---------------------------------------------------------------------------- | | DeepSeek Harness | 0.1.0-rc.8next,developer preview,接口可能破坏性变更;rc.6 仍兼容) | | Node.js | >=20 | | 安装 | dsh plugin(pnpm profile) |

工作原理

  1. 插件注册一个 WebSearchProvider(id: tavily)到 ctx.web,patch 把 searchProviderdeepseek-official 改为 tavily。内置 web-search-deepseek 插件保持注册(它的设置卡片继续可用),只是不再被选中。
  2. keys[] 组成轮询池:每次搜索按顺序取下一个可用 key;429 → 该 key 冷却(默认 60s)→ 换下一个;全部失败时抛出结构化错误(只含 key 的 id,不含密钥)。
  3. web-search-tavily 设置 namespace 通过 installSettingsSection 注册,schema 即表单;用户改动经 $DSH_HOME/settings.yaml 热加载,provider 下次搜索即用新配置。

rc.6 / rc.8 差异rc.6@deepseek-ai/dsh-host-apiproxy 对「设置页插件配置卡片」有一份硬编码 allowlist,本插件携带守卫式补丁在首次启动时把 web-search-tavily 加入该列表;rc.7+ 已移除该 allowlist,改为动态注册自动暴露,补丁在 rc.8 上自动成为 skipped-version 无操作(日志为 allowlist was removed… patch not needed)。详见 allowlist 补丁

安装

方式 A:本地目录(开发/自用,推荐)

先构建产物:

npm install
npm run build

然后安装进 web profile:

dsh plugin --profile web add ./dsh-web-search-tavily

本地目录安装走 pnpm link,不需要 allowBuilds 授权。

方式 B:发布到 npm 后

dsh plugin --profile web add @zzy001/dsh-web-search-tavily

方式 C:GitHub(需要授权构建)

dsh plugin --profile web add "github:zzy-cl/dsh-web-search-tavily#<commit-sha>"

pnpm ≥10 首次安装会拒绝运行 git 依赖的 prepare 构建脚本。按 dsh 打印的提示,把包键 @zzy001/dsh-web-search-tavily 加入该 profile 的 pnpm-workspace.yaml

allowBuilds:
  '@zzy001/dsh-web-search-tavily': true

然后重新执行 add允许构建 = 允许该包代码在安装时于你机器上执行,仅对可信源码使用;更稳妥的做法是用方式 B(npm 分发预构建产物)或方式 D(tarball,无需授权)。

方式 D:tarball(无构建授权)

npm pack   # 或 pnpm pack
dsh plugin --profile web add ./zzy001-dsh-web-search-tavily-0.3.0.tgz

所有 dsh plugin add 方式都需要本机有 pnpm(dsh CLI 不内置 pnpm,profile 由 pnpm 管理): npm install -g pnpmcorepack enable pnpm

使用 npx @deepseek-ai/dsh 启动的用户

如果 dsh 是通过 npx @deepseek-ai/dsh web 运行的(插件装在 profile,内置包从 npx 缓存解析),安装流程:

npm install -g pnpm
npx @deepseek-ai/dsh plugin --profile web add "D:\...\dsh-web-search-tavily"   # 本地目录,或 npm 包名/tarball/github:
npx @deepseek-ai/dsh web     # 第 1 次启动:自动对 dsh 安装目录(npx 缓存)应用 allowlist 补丁
npx @deepseek-ai/dsh web     # 第 2 次启动:设置页卡片出现

allowlist 补丁会定位dsh 进程实际加载的 @deepseek-ai/dsh-host-apiproxy 副本(解析链:进程入口 → 插件目录 → $DSH_HOME/profiles/* → npx 缓存),不会误打仓库里的 devDependency 副本。若卡片未出现,用 dsh-web-search-tavily status 确认 packageRoot 指向 dsh 安装目录。

免 pnpm 快速试跑(仅验证搜索,无设置卡片):仓库根有 dev.cordis.yml,用它做 --patch overlay:

$env:TAVILY_API_KEY = "tvly-你的key"
npx @deepseek-ai/dsh web --patch "D:\项目合集\dsh-plugins\dsh-web-search-tavily\dev.cordis.yml"

安装后

  1. 重启一次 dsh(allowlist 补丁在启动时应用,卡片下次启动才被服务)。

  2. 验证补丁与配置层:

    dsh --profile web --dump-config        # 应看到 web-search-tavily 行、web.searchProvider: tavily、web-search-deepseek 行仍启用
    pnpm --dir "$DSH_HOME/profiles/web" exec dsh-web-search-tavily status
  3. 打开 Web UI http://127.0.0.1:3080 → 设置 → 模型:填入 DeepSeek API key(聊天仍走 DeepSeek,只有搜索走 Tavily)。

发布

官方没有独立的插件市场;分发方式就是 npm 注册表(bundle 本质是带 dsh.bundle 清单的 npm 包)与 GitHub,发现性靠 GitHub 仓库的 dsh-plugin topic。

发布到 npm(推荐)

npm login
npm publish          # 自动跑 prepare → tsdown → 发布预构建 lib + cordis.patch.yml + bin

发布前用 npm pack --dry-run 复核产物。发布后用户安装即方式 B,无需 allowBuilds(装的是预构建代码)。

发布到 GitHub

git remote add origin [email protected]:zzy-cl/dsh-web-search-tavily.git
git push -u origin master

给仓库打 topics(GitHub 仓库页 Settings → Topics):dsh-plugindeepseek-harnesstavilyweb-search。用户通过 github:zzy-cl/dsh-web-search-tavily#<commit-sha> 安装(方式 C,需要 allowBuilds 授权,因为 git 安装会跑 prepare 构建)。

配置

环境变量(开箱即用)

bundle 默认带一个 main key 引用 TAVILY_API_KEY 环境变量:

# Windows PowerShell
$env:TAVILY_API_KEY = "tvly-你的key"
# POSIX
export TAVILY_API_KEY="tvly-你的key"

设置页卡片(推荐,支持多 key)

安装并重启后:设置 → 插件 → 插件配置 → Tavily 搜索

  • API Keys(轮询池):添加/移除 key 行,每行填 id(统计/报错里的名字)+ 可选的 apiKeyEnv环境变量名,不是密钥)+ 只写密钥输入框(留空保持当前密钥,提交后不再回传)。密钥存入顶层 apiKeys{} 字典,部分保存深度合并,改一个 key 不影响其他 key。
  • 卡片中可改:搜索深度 basic|advancedtopictime_rangeinclude_domains/exclude_domainsinclude_answermaxResults(1–20)、429 冷却 cooldownMsbaseURL
  • 改动写入 $DSH_HOME/settings.yaml热生效,无需重启;密钥按 key 显示"已配置/未配置"徽标(值永不回传)。
  • 卡片对 apiKeyEnv实时校验:把 tvly-… 密钥字面量填进该栏会标红并阻止保存(见 Troubleshooting 第一条)。

基础配置中的 key(如 main$TAVILY_API_KEY)会始终参与轮询;若在卡片里给同一 id 填新密钥则覆盖环境变量。密钥与 env 引用的优先级:apiKeys{} 内联 > apiKeyEnv 环境变量。

搜索参数说明

| 设置项 | Tavily 参数 | 说明 | | ---------------- | ----------------- | ---------------------------------------------------------------- | | keys[] | — | 轮询池名单(id + 可选 apiKeyEnv);密钥在 apiKeys{} 字典里 | | apiKeys{} | — | id → 密钥 的顶层字典(secret 脱敏,UI 只写) | | baseURL | — | 默认 https://api.tavily.com | | searchDepth | search_depth | basic(1 积分)/ advanced(2 积分) | | topic | topic | general/news/finance/... | | timeRange | time_range | day/week/month/year | | includeDomains | include_domains | 仅这些域名 | | excludeDomains | exclude_domains | 排除这些域名 | | includeAnswer | include_answer | 生成的回答映射为模型可见 content | | maxResults | max_results | 请求未带 maxResults 时的默认条数 | | cooldownMs | — | 429 后该 key 冷却毫秒数(默认 60000) |

使用验证

在 Web UI 发起需要联网的问题(例如「搜索今天的人工智能新闻」),确认:

  • web_search 工具调用返回 Tavily 结果(含 answer 与 citations);
  • dsh 进程终端出现轮询/切换日志(形如 [web-search-tavily] ... key 'main' ...);
  • 多个 key 时把某个 key 手动填错或耗尽,观察到自动切换。

Troubleshooting

1. 「provider unavailable」/ 搜索报 WEB_PROVIDER_CREDENTIAL_MISSING 或无可用 key

最常见原因:把 Tavily 密钥字面量tvly-…)填进了 apiKeyEnv 字段。

# ❌ 错误:apiKeyEnv 是环境变量名,不是密钥
web-search-tavily:
  keys:
    - id: main
      apiKeyEnv: tvly-dev-xxxxx

# ✅ 正确 A:密钥放顶层 apiKeys{} 字典
web-search-tavily:
  apiKeys:
    main: tvly-dev-xxxxx

# ✅ 正确 B:apiKeyEnv 指向真实存在的环境变量
#    且启动 dsh 前设置 $env:TAVILY_API_KEY = "tvly-dev-xxxxx"
web-search-tavily:
  keys:
    - id: main
      apiKeyEnv: TAVILY_API_KEY

插件自 0.1.0 起对此做了三重防护:设置卡片实时标红并阻止保存;启动时在 dsh 日志输出配置诊断([web-search-tavily] 配置诊断: key 'main': apiKeyEnv 填入了疑似密钥字面量…);搜索报错消息直接指向 web-search-tavily settings 排查。

2. 日志出现「key 解析结果: N 个警告」

说明有 key 未解析到凭证(env 不存在 / apiKeys 未配置 / 被过滤)。按警告文案逐条修复;警告会在配置修正后自动消失(无需重启)。

3. 所有 key 报 429 后仍失败

免费额度耗尽或限流,属预期行为:默认冷却 60s 后自动重试,可调 cooldownMs,或往轮询池加 key。

4. 设置卡片不出现

dsh-web-search-tavily status 确认 allowlist 补丁状态(见 allowlist 补丁);首次安装需重启 dsh 两次。

allowlist 补丁

它做什么:把 web-search-tavily 追加进已安装的 @deepseek-ai/dsh-host-apiproxy/libWEB_SETTINGS_NAMESPACES 数组,使设置页服务该 namespace。只插入 , "web-search-tavily" 一个片段,幂等。

守卫

  • 仅当安装版本为 0.1.0-rc.6 时执行;rc.7+ 上自动 skipped-versionallowlist was removed in rc.7+),仅打印 info,不告警不破坏任何东西。
  • 幂等:重复 apply 返回 already-applied;restore 只移除自己插入的片段。
  • 写入采用临时文件 + rename;discoverJsFiles 防符号链接环。

命令(在 profile 目录下):

pnpm --dir "$DSH_HOME/profiles/web" exec dsh-web-search-tavily status   # patched/clean/...
pnpm --dir "$DSH_HOME/profiles/web" exec dsh-web-search-tavily apply    # 手动应用
pnpm --dir "$DSH_HOME/profiles/web" exec dsh-web-search-tavily restore  # 卸载前还原

Windows:$DSH_HOME 默认在 %USERPROFILE%\.dsh,把 $DSH_HOME/profiles/web 换成实际绝对路径。

升级 / 卸载

  • dsh 升级后:先 dsh-web-search-tavily status 确认补丁状态;rc.8 已改为动态注册,status 应为 skipped-version 且提示 patch not needed,属正常。
  • 卸载:先 restoredsh plugin --profile web remove @zzy001/dsh-web-search-tavily。卸载后 web 行恢复默认 searchProvider: deepseek-official

安全与合规

  • 密钥经 role('secret') 处理:只写输入、永不回传;存储于本地 settings.yaml
  • Tavily 收到搜索词与启用的搜索参数;include_answer 会把第三方页面内容带入模型上下文,按需关闭。
  • 多账号叠加免费额度可能违反 Tavily 服务条款,请自行评估风险。

开发

npm install
npm run check    # tsc --noEmit
npm test         # vitest
npm run build    # tsdown → lib/
npm pack --dry-run

结构:

src/
├── index.ts      # 插件入口(name/inject/apply + 启动时补丁)
├── settings.ts   # web-search-tavily 设置 namespace + schema + resolveProviderOptions
├── shared.ts     # 共享校验(ENV 变量名 / 密钥字面量判定,消除双维护)
├── provider.ts   # TavilySearchProvider:轮询 + 429 冷却 + 映射
├── rotation.ts   # 轮询/冷却状态机(纯逻辑,可测)
├── patch.ts      # apiproxy allowlist 守卫式补丁(rc.6 专用,rc.7+ 自失效)
└── types.ts      # Tavily API 类型
client/client.js  # 设置卡片(ModuleLoader bundle,含 hash 失效回退样式)
bin/              # dsh-web-search-tavily CLI(status/apply/restore)

License

MIT。