Bundle
dsh-retry-boost
让 DeepSeek Harness 自动重试商汤 429/QUOTA 等瞬时网关故障直到任务完成——启动时给所有 llm-pi-ai provider 热注入加固版 retryPolicy,运行中新增的 provider 也会自动补上,再也不用手动发「继续」。
- Source
- hhb1028
- stars
- 3 stars
- License
- MIT
- Updated
- Updated 4 days ago
Readme
# dsh-retry-boost
遇到网关瞬时故障(429 限流/断流/超时)时自动退避重试、直到任务完成——一个 DSH
插件,启动时把防断流 `retryPolicy` 热注入到所有 `llm-pi-ai` provider;
之后在运行中新增/修改的 provider 也会自动补上(监听 `llm/adapters-updated`)。
再也不用手动发「继续」了。
[English README](./README.en.md)
---
## 问题背景
网关返回 **`429 insufficient_quota`**(商汤 SenseNova 和很多 LLM 网关都这么措辞)时,
DSH 的错误分类器会先命中 `isQuotaExceededError` 把它归为 **`QUOTA`** 码,
而不是通用的 429 → `RATE_LIMIT`。
DSH 内置重试(`dsh-llm-retry`)只重试 `retryableCodes` 列表里的错误码。而**默认**策略是:
```text
retryableCodes: [EMPTY_RESPONSE, RATE_LIMIT, SERVER, TIMEOUT, TRANSPORT] // ← 没有 QUOTA
maxRetries: 5
backoff: 500ms → 10s
```
`QUOTA` 不在列表里 → 瞬时 `429 insufficient_quota` 直接 **fail-fast**:
一次都不重试、turn 立刻死掉,手动「继续」也会再撞同一堵墙。上游同源问题:
[deepseek-ai/deepseek-harness discussion #892](https://github.com/deepseek-ai/deepseek-harness/discussions/892)
(目前 0 回复,官方尚未修复)。
## 解决方案
插件启动时把一份加宽的 `retryPolicy` 写入 `llm-pi-ai` 设置命名空间,
llm-pi-ai 的 settings `onChange` 会**热生效,无需重启**。注入的策略:
```text
retryableCodes: [EMPTY_RESPONSE, RATE_LIMIT, QUOTA, SERVER, TIMEOUT, TRANSPORT, PI_AI_ERROR, UNKNOWN]
maxRetries: 50
backoff: 1s → 60s,抖动 0.2(指数退避)
```
效果:瞬时 429 / 断流 / 超时会被指数退避**重试直到任务完成**——就是把商汤生产
环境里用的那个 settings.yaml 补丁产品化,让任何人都能一键装上。
## 覆盖范围与已知限制
本插件注入的是 `llm-pi-ai` 设置命名空间里的 provider——**直连主路由全覆盖**。
以下路径**不在射程内**(本插件没有任何配置面能影响它们):
- **图片输入变体路由**(如 `vision-toolkit-<provider>`):由视觉类插件
(如 dsh-vision-toolkit)通过 `registerAdapter` 注册的独立 adapter,
其 `retryPolicy` 在注册时一次性捕获、不读 settings。DSH 对这类路由
会落到内置默认值——`retryableCodes` 里**没有 QUOTA**,商汤 429 会在
这条路线上照样秒断。
- 插件会自动**检测并在日志里警告**这类路由(`warnUnprotectedVariants`,
默认开启,路由注册/更新时复检)。看到
`variant route "..." retries WITHOUT QUOTA` 就是它。
- 出路:给变体 adapter 的上游提补丁(让 `providerRetryPolicy` 委托
upstream 主路由)、换原生支持图片输入的模型、或临时关闭粘贴自动切变体。
- **其他第三方 LLM adapter 插件注册的自有路由**:同样不经过 llm-pi-ai
命名空间,本插件无法注入。
## 为什么做成插件而不是只改 settings.yaml?
- **一条命令安装**——对*所有* provider 生效,不只是你手改的那一个。
- **跟着新 provider 走**——以后新增 provider,下次启动自动套用。
- **可配置**——`fill` / `boost` / `force` 三种策略,重试预算可调。
- **透明**——注入的策略会出现在 `settings.yaml` 里,看得见、改得动;
插件幂等,绝不和你手改的配置打架。
## 与 dsh-chat-continue 的区别
| | dsh-retry-boost(本项目) | [dsh-chat-continue](https://github.com/Chu-m/dsh-chat-continue) |
| --- | --- | --- |
| 定位 | **第一道防线**——让 DSH 内置重试真正生效 | **第二道防线**——内置重试耗尽后兜底重试 |
| 机制 | 给所有 `llm-pi-ai` provider 注入 `retryPolicy`(走官方重试链路) | 拦截 `agent/request-error` 自己重发失败的请求 |
| 退避 | 指数退避 1s → 60s + 抖动 | 固定间隔 |
| 手动确认 | —— | 可选弹窗通知 |
| 安装 | `dsh-retry-boost`(npm) | `@wuxjs/dsh-chat-continue` |
两者**互补**:单独用本项目即可;也可以叠上 chat-continue 作为最后的兜底网。
## 环境要求
- DSH `>= 0.1.1-rc.1`(支持 `dsh.bundle.patch` 宿主插件)
- Node.js `>= 20`
## 安装
方式一:从 npm 安装(推荐):
```bash
dsh plugin --profile <你的profile名> add dsh-retry-boost
```
方式二:直接从 GitHub 安装(跟踪 main 分支):
```bash
dsh plugin --profile <你的profile名> add "github:hhb1028/dsh-retry-boost#main"
```
然后重启 DSH。日志里会出现类似:
```
dsh-retry-boost: injected retry policy for "sensenova" (mode=normal retries=50 backoff=1000ms->60000ms codes=8)
```
注入后的策略会出现在 profile 的 `settings.yaml` 中
`llm-pi-ai.providers.*.retryPolicy` 下——可以随意手动修改。
## 配置项
在合并进 profile 的 `cordis.patch.yml` roster 行(或 DSH 的插件配置界面)里调整:
| 键 | 默认值 | 含义 |
| --- | --- | --- |
| `strategy` | `fill` | `fill` = 只处理**没有**显式 `retryPolicy` 的 provider;`boost` = 对显式配置的也合并缺失错误码并抬高上限;`force` = 全部替换为插件策略 |
| `mode` | `normal` | `normal` = 有界重试;`always` = 无限重试(⚠️ 慎用,永远重试下去) |
| `maxRetries` | `50` | `normal` 模式下的重试次数上限 |
| `initialDelayMs` | `1000` | 首次退避延迟 |
| `maxDelayMs` | `60000` | 退避上限 |
| `jitterRatio` | `0.2` | 抖动比例(0–1) |
| `retryableCodes` | 上面 8 个码 | 需要重试的失败码 |
| `warnUnprotectedVariants` | `true` | 检测到不受保护的变体路由(见「覆盖范围与已知限制」)时打日志警告 |
## 卸载
```bash
dsh plugin --profile <你的profile名> remove <名字>
```
卸载后注入到 `settings.yaml` 里的 `retryPolicy` 段**不会自动删除**——手动清掉
(或卸载前先用 `force` 策略并恢复你自己的值),即可回到 DSH 默认行为。
## 工作原理
1. 启动时读取 `llm-pi-ai` 设置命名空间。
2. 按 `strategy` 为每个 provider 规划目标 `retryPolicy`(`lib/policy.js` 纯函数,
全量单元测试)。
3. 通过 DSH 的 settings provider 合并写入:经 llm-pi-ai 校验(与 `dsh-llm`
的 `RetryPolicySchema` 完全一致)→ 持久化到 `settings.yaml` →
`installSettingsSection` 的 `onChange` 热生效。
4. 写入幂等:已达标时再次运行产生空 patch,绝不反复改写。
5. 变体路由巡检:监听 `llm/adapters-updated`,对 `vision-toolkit-*` 等变体
路由的已捕获 `retryPolicy` 复检;缺 QUOTA 时打警告(每条路由一次,
修复后重新武装),只警告不改动——诚实告知射程边界。
## 开发
```bash
npm test # 单元 + 真实 schema 集成 + apply 流程测试(node --test)
npm run check # 语法检查
```
无构建步骤——纯 ESM。schema 集成测试会把生成的策略跑过框架**真实**的
`RetryPolicySchema` / `resolveRetryPolicy`,保证注入的 patch 永远不会被设置校验拒绝。
## Roadmap
- [x] 发布到 npm(`dsh-retry-boost`,v1.2.0 已上线)
- [x] llm-pi-ai 配置变化时自动重跑策略(v1.2.0:监听 `llm/adapters-updated`,
防抖 300ms,幂等防自触发——运行中新增的 provider 无需重启即受保护)
- [ ] 可选的设置页面(Settings → Retry Boost)
## 更新记录
### 1.2.0
- 运行中新增的 provider 自动受保护:监听 `llm/adapters-updated`(与变体路由
警告共用事件),防抖 300ms 后重跑注入计划。计划幂等——本插件自己写入引发
的扫描不会造成二次写入,更不会死循环;启动行为与 v1.1.0 完全一致。
- 适用于:先启动 DSH、之后往 settings.yaml 加新 provider(比如第二把 key 的
备用通道)、或在设置界面新增供应商的场景,全程无需重启。
## 许可证
MITInstall
dsh plugin --profile web add github:hhb1028/dsh-retry-boost
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-retry-boost from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.