# DSH 上游错误统一重试 5 次
## 目标
改本地 DSH 源码:模型上游请求失败时统一重试,最多 5 次(合计最多 6 次请求)。任一次成功即停;全失败再报错。无上游错误白名单。用户取消立即停。只重试失败的模型请求,不重跑已成功的工具调用。保留会话与进度。provider 自定义配置不得绕过上限。
覆盖:HTTP 4xx/5xx(含 401/403/429)、鉴权/配额、超时、HTTP2/SSE 中断、网络断开、上游提前关流、`sticky_control_unavailable`、`continuation routing failed`、SDK 抛错、未知错误码、无有效响应。本地文件/工具/配置错误不进此重试。用户停止不重试。
## 路径
相对路径,工作目录 = DSH Desktop 安装根。
主要:`./resources/app.asar`、`host-module-fallback.mjs`、`harness-node-entry.mjs`
核心包(asar 内或源码 src):`dsh-llm-pi-ai`、`dsh-llm-retry`、`dsh-agent-loop`
asar 按环境选:源码改、重建、或 ESM load 钩子。有完整 Git 仓则改 src,别当编译产物是源码。
## 开工前
读 AGENTS.md;确认 Desktop/Harness 版本;查现有重试插件、适配器错误捕获、Agent 循环异常处理;查是否已打过补丁;DSH 在跑则勿强杀任务。优先补洞,不另造重试管理器。
## 改什么
**A · `dsh-llm-pi-ai`**(`streamWithSnapshot` / `classifyPiAiError` / `mapStopReason` / `toStreamChunks`)
上游错误与 SDK 抛错都进统一处理;流提前结束、无终止帧、首字超时、截断、服务端 aborted → 失败可重试;用户取消 → 不重试;请求未开始的本地错保持原样。统一成 finish 错误帧:`kind=error`,`failure.message` 原文,`failure.code` 原码或 `UPSTREAM_ERROR`。勿吞异常伪造成功。
**B · `dsh-agent-loop`**(`preparedCall.stream`、流读取、`agent/request-error`、`AssistantStreamAttempt`)
流创建/读取阶段捕获上游异常 → 记失败尝试 → 交给 `agent/request-error`;返回 `retry` 则只重跑当前模型请求;次数耗尽抛最终错;取消立即结束。禁止整回合重跑(不重复 Shell/写文件等有副作用工具)。各层勿重复计数,整链最多 5 次重试。
**C · `dsh-llm-retry`**(`recover` / `retryPolicy` / `retryableCodes` / `maxRetries` 等)
去掉上游错误码白名单;进 `agent/request-error` 的上游失败均可重;`maxRetries=5`(首次不计);覆盖 provider 禁用/无限重试;无 policy 也继续;Retry-After 超上限不直接停;取消不继续;成功结束链;错误类别变化不重置次数。禁止给数组加 `*` 通配。
## 参数
`maxRetries=5`,`initialDelayMs=500`,`maxDelayMs=10000`,`jitterRatio=0.1`,指数退避 + ~10% 抖动。默认启用,无新配置页。
## 安装版做法
优先 `host-module-fallback.mjs` 的 ESM hooks,精确替换上述三包;不破坏原解析与其它修复;改前备份;锚点不匹配则重查源码;语法校验;重启后生效。无必要不重打包整个 Electron。
## 测试(离线模拟,无真 Key、无真请求)
覆盖:400/401/403/429/502/503、sticky/continuation、HTTP2/SSE 断、超时、SDK 抛错、未知码、上游关流、provider 禁/无限重试、Retry-After 过大、用户停止、工具失败不进上游重试。
验收:连续失败 = 6 次请求后停;第 1/3/6 次成功则总请求对应为 1/3/6;取消不续重;工具错不重试模型。日志勿输出历史对话正文。
## 备份 / 回滚
仅备份本次涉及文件 → `./resources/local-fixes/upstream-retry-five/`(原文件 + 测试脚本 + 短 README)。有 Git 则用 Git。勿动会话/配置/凭证。
## 收尾汇报
版本;三模块与相对路径;覆盖错误类型;是否首次+5 重试;测试结果;回滚位置;是否需重启;未验证的真实场景。禁止凭证、绝对路径、服务器地址、会话正文。
DSH 在跑:改完提醒完全退出再重启,勿声称热进程已生效。
---
按精简守则:最少必要改动,复用官方 `agent/request-error` / llm-retry / sessionProjections,不另造调度器,无关重构不做。现在直接查改源码,别只交方案。