Repository navigation
Releases
v0.6.0
dsh-web-search-pool 0.6.0
Added
- 接管 ctx.web.fetch(web_fetch 工具):服务级接管从 web.search 扩展到 web.fetch(2026-11-01 依桌面版 0.2.1-rc.5 app.asar 核对)。启用后 AI 仍调用同一个 web_fetch 工具,抓取走 Tavily Extract(POST /extract),不再消耗 DeepSeek 平台的 Fetch API 额度;结果映射为 seam 同形结构。
- fetch 调度与门禁:SearchPoolProvider.fetch 复用搜索的 key 池调度、限流、熔断与 Tavily 额度门禁(额度门禁抽为 _quotaGate,search/fetch 共用);抓取只走 Tavily key(Exa 的 /contents 未接),池里没有 Tavily key 时抓取返回不可用。
- fetch 独立开关与回退:fetchEnabled(默认 true,关闭后 web.fetch 原样走宿主 fetch provider)与 fetchFallbackToOfficial(默认 false);服务级 patch 不可行时按官方 fetch provider id(deepseek-fetch-api → http)降级替换,禁用态委托同搜索模式。
- Tavily Extract 高级参数:providers.tavily.fetchDepth(默认 basic——advanced 按 2 credits/URL、basic 按 1 credit/5 URL,成本差约 10 倍;JS/反爬站点抓不到正文再改 advanced)与 fetchFormat(默认 markdown)。
- SearchPoolProvider 构造期 fetchImpl 注入点:与适配器层既有 fetchImpl 设计对齐,测试不再依赖全局 fetch 猴补丁。
- 回归用例 18 个(tests/search-pool-fetch.test.js),全量 154 用例通过。
完整变更见 CHANGELOG.md。安装与配置见 README 与 docs/。
v0.5.1 — 修复 5xx/超时下 failover 不推进(issue #1)
修复:单次搜索内不重复重试同一个失败的 key(#1)
第一个被选中的 key 若返回 HTTP 5xx / 401 / 网络错或单次超时(不是 429),同一次搜索的下一轮又会选中它;maxAttempts = keyPool.totalKeys 很快用尽,同供应商的健康 key 和下一个供应商都不会被尝试。最常见的「1 个 Tavily key + Exa 兜底」配置在 5xx/超时时不切换,上游挂起时每次搜索耗满宿主预算(默认 30s)后失败。
根因
_search每轮重新scheduler.acquire(),不排除本次搜索已试过的 entry;acquire()无排除参数,smooth WRR 按max(1, rpm)加权,高权重 key 连续胜出(单 key 供应商时它就是唯一候选);- 非 429 失败只累加
failCount,要连续allowedFails(默认 3)次才冷却,所以下一轮仍是候选; - 原超时换 key 用例两个 key rpm 都是 60,WRR 恰好交替,测试假绿。
修复
Scheduler.acquire(exclude?)新增调用级排除参数:候选在冷却过滤之外再排除已试 entry,不写冷却、不改失败计数、不影响权重累加;SearchPoolProvider._search维护tried集合,选中 entry 后先登记再走凭据/闸门 —— 一次搜索内每个 entry 至多尝试一次,失败立即换 key / 换供应商;- 冷却、失败计数、权重轮转、错误中性化与
ctx.web.search接管契约均未改动。
验证
| 项 | 结果 |
|---|---|
node scripts/run-tests.mjs |
136 用例全绿(原 131,新增 5) |
| 反证:临时移除修复 | 132/136,4 个新用例必红 |
| 内联复现 A/B/C | 全部成功:A [bad,good]、B [tavily,exa]、C [hang,exa] |
node --check / scripts/check-docs.mjs |
通过,0 errors |
已知边界
- 「所有 key 同时挂起」时仍会逐个等到
requestTimeoutMs(默认 20s);宿主web_search的截止时间不向 provider 暴露,因此不引入总预算猜测。 - 未跑真实宿主 e2e(
scripts/e2e-boot.mjs需要 app.asar 提取目录)。
升级
dsh-web-search-pool: https://gh-proxy.com/https://github.com/DreamRift/dsh-web-search-pool/archive/refs/tags/v0.5.1.tar.gz
或使用本 Release 附带的 dsh-web-search-pool-0.5.1.tgz(sha256 9BD00666C530AE2EE3F592538CC65059ED901E82277EEC90DFC0BB3E3129D268)。
完整变更:v0.5.0...v0.5.1
v0.5.0: 运行时接管官方搜索
修复
- 「启用搜索 Key 池」未真正生效:0.4.0 只在
apply时把web行的searchProvider改成search-pool。官方WebRuntime.search是调用时才按该字段选 provider,而用户 profile 的cordis.patch.yml在 bundle 层之后应用、官方 Web search 设置页也写同一行;覆盖后请求仍走deepseek-search-api/deepseek-official,消耗 DeepSeek 官方 API key。
变更
- 接管点改为
ctx.web.search服务方法:apply时在 web 服务实例上安装可逆 wrapper,启用态直接走 key 池;不依赖 provider id、provider 注册顺序、web.searchProvider或行 id,因此不会被 profile patch / 官方设置页覆盖。关闭时委托回原web.search,卸载时按 descriptor 恢复。 cordis.patch.yml不再改写官方web行,只插入web-search-pool行。- 模型无感:wrapper 返回与官方 seam 同形的
{ content?, sources, truncated },去掉池内部query/provider字段,并按maxResults截断;池不可用/失败时默认不回退官方,抛中性的WEB_PROVIDER_UNAVAILABLE(不含 Tavily / Exa / key / 官方端点字样),详细原因只写ctx.logger与error.cause。 - 降级路径:若宿主把
web.search冻结/设为不可配置,退回替换deepseek-search-api/deepseek-officialprovider 对象的search/available;若searchProviders也不可检查,再退回配置同步。 - 清理注册到
ctx.effect:cordis 4.0.4 的 Loader 不把apply的返回值当 disposer,原写法在卸载时不会恢复官方方法。
新增
fallbackToOfficial(默认false):池不可用/全部 key 失败时是否回退官方搜索;可在 profile patch 中打开。scripts/privacy-scan.mjs用户名改为运行时获取(PRIVACY_USERNAME可覆盖),不再把账户名写进源码。
验证
- 单元/契约测试 131 例全绿(
node scripts/run-tests.mjs):服务级接管、未知 provider id、maxResults截断、中性错误、关闭委托、fallbackToOfficial回退、web.search不可 patch 的降级、dispose 恢复。 - 桌面版 0.2.1-rc.2(
resources/app.asar提取)真实启动全绿:web行保持deepseek-official、ctx.web.search有 own wrapper、无 key 时真实宿主调用抛中性错误、settings.update不改写 web 行。 - 复现失效场景(profile 显式写
searchProvider: deepseek-search-api)下--live-search真机搜索仍走 Tavily:约 3.9s 返回 5 条来源 + answer 摘要。
安装方式:DSH 桌面版 → 设置 → 插件 → 安装 → 选择本 Release 附带的 dsh-web-search-pool-0.5.0.tgz,按提示重启。升级后 web 行仍显示官方 provider 属正常现象——接管发生在 ctx.web.search 方法上;日志可见 search-pool: takeover installed at web.search。安装后验证与配置说明见仓库 docs/安装与升级.md。
v0.4.0: 适配 DSH 0.2.0
新增
- 支持 DSH 0.2.0 线:peer 范围从
^0.1.7-rc.1扩为^0.1.7-rc.1 || ^0.2.0-rc.1(0.1.7 与 0.2.0 双线并存),桌面版 0.2.0-rc.1 的启动兼容门放行本 bundle 层。 scripts/privacy-scan.mjs:扫描 git 全部历史的个人用户名、绝对路径、真实长度 API key、邮箱、Bearer token;接入发布流程必跑步骤。scripts/e2e-boot.mjs新增--user-patch(真实用户 patch 层组合验证)与--live-search(真机搜索冒烟)两个能力。
变更
- 0.2.0 适配核对(无行为改动):0.2.0 把 loader 拆为独立包
@deepseek-ai/cordis-plugin-loader(cordis 4.0.4 的 peer),逐项核对宿主 app.asar 源码确认本插件依赖的契约无破坏性变化——ctx.web.registerSearchProvider与 provider 面、loader/volatile-update、Config schema 的 volatile 投影、plugins.row.configkeyed slot、ctx.configForms、ctx.remote.credentials与credentials/reference-updated事件、dsh.client.inject三包到达顺序、dsh-base 根组web行的 restate 语义。因此 0.2.0 线只放宽 peer 范围,src/无功能改动。
验证
- 桌面版 0.2.0-rc.1(
resources/app.asar提取)源码核对 +scripts/e2e-boot.mjs真实启动全绿:skippedBundles 为空、web行 patch 生效(searchProvider=search-pool 且 fetchProvider 保留)、web-search-pool行 ACTIVE、settings.describe 投影全部字段、settings.update 端到端(不重挂 + volatile 就地提交 + web 行双向同步 + patch 落盘)、client-modules 图谱下发浏览器 bundle。 - 本地测试 122 个用例全绿;发布前隐私扫描(全历史 + 待提交改动)通过。
安装方式:DSH 桌面版 → 设置 → 插件 → 安装 → 选择本 Release 附带的 dsh-web-search-pool-0.4.0.tgz,按提示重启。安装后重启验证与配置说明见仓库 docs/安装与升级.md。
v0.3.0 — 适配 DSH 0.1.7
v0.3.0 — 适配 DSH 0.1.7(官方桌面版 0.1.7-rc.2 实测)
🔧 修复
- 「安装后无插件页面 + 重启 dsh 报错」:0.2.1 的 client half 在
exports.inject
里等服务settingsScope——0.1.7 已随设置体系重写移除该服务,浏览器 loader entry
永久 pending,web boot fail-loud(桌面版崩溃日志实证
dsh-web-search-pool: pending (waiting for service: settingsScope))。
⚠️ Breaking
- 仅支持 DSH 0.1.7+(peer 收紧为
^0.1.7-rc.1,DSH 启动兼容门 satisfies 判定)。
✨ 变化
Host half
- 设置面改为 loader 行 Config schema 自动投影(namespace = 行 id);全部可编辑字段
.volatile()——运行期是 Ref,编辑经settings.mutate写 profile patch 后就地提交
(loader/volatile-update,不重挂插件)。 - 运行时 usage/tick/diagnostic 移出 schema(0.1.7 的 settings 写入即落盘进用户 patch),
Tavily 额度快照改ctx.logger观测;额度门禁 / 长冷却 / 自动恢复逻辑不变。 web行 id 运行时探测(web/include:web)。
Client half(按官方 companion 包同构重写)
settings.plugin.itemslot →plugins.row.config(key =dsh-web-search-pool#web-search-pool)。ctx.settingsScope→ctx.configForms(get(ns)+whileServed门控)。- 写入走
form.mutate(ops, revision);凭据走remote.credentialsdescribe/set。
✅ 验证
- 122 个 node:test 用例全绿(含真实 cordis + Loader + schemastery 驱动 host half 的集成测试)。
scripts/e2e-boot.mjs:用桌面版 app.asar 内真实运行时 + 隔离 profile 端到端启动整棵
宿主树——bundle 加载 / patch 生效 / 插件 ACTIVE / settings 投影 / 写入落盘就地提交 /
client-modules 图谱下发,全绿。
📦 安装
npm pack
# 桌面版:设置 → 插件 → 安装 → 选择 tgz;在 dsh-web-search-pool 的 web-search-pool 行点「配置」详见 docs/安装与升级.md 与 CHANGELOG.md。