mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-30 16:23:35 +08:00
PR #79 (suppress consecutive identical retry errors) merged after the v0.5.20 release commit but before the tag was pushed. The released build will contain its code, so the notes need to mention it. Title broadened to cover both retry-link denoise changes (#78 + #79). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4.7 KiB
4.7 KiB
v0.5.20
重试链路两处去噪:子代理限流器从单门改双门,正常多步工作不再被误杀;HTTP 重试期间相同错误不再每次都堆到对话气泡。
修复
-
子代理限流器双门(#78)。原
verification类子代理 cap=5,5 个连续 PASS 的 PR 验证后第 6 个就被硬阻断——即使每次都成功。源码注释承诺「only fires on pathological loops, not on normal multi-step work」,实际行为违背了这条契约。本版把单门改成双门:- 总 cap 放宽:
verification5 → 12。日常多 PR 工作有充足预算。 - 连续 FAIL streak 门:新增
noteOutcome(agentType, verdict)。3 次连续 FAIL(无 PASS 中断)立即 cap,与总数无关。任何 PASS / UNKNOWN 清零 streak。这才是真正抓 verifier-loop 的语义。 - 保守 verdict 解析:
parseVerdict(text)解析子代理输出的VERDICT: PASS|FAIL|CHANGES_NEEDED|APPROVE|UNCONFIRMED行,附带SECURITY:PLAN_REVIEW:ROOT CAUSE:同义词。UNKNOWN 当 soft-PASS ── 一次性研究类子代理(如 Explore)没有 verdict 结构的输出不会被误杀。 - 错误文案区分
cappedReason: 'total' | 'streak' | 'none',用户能看到具体哪个门触发。 - 环境变量出口保留:
CLAUDE_CODE_AGENT_LIMIT_<TYPE>=N调高 total cap、CLAUDE_CODE_AGENT_LIMITER_OFF=1整体禁用。
- 总 cap 放宽:
-
HTTP 重试期间相同错误不再刷屏对话(#79)。原
withRetry默认maxRetries=10,每次失败只要错误是APIError就把SystemAPIErrorMessageyield 到对话流。一次 flaky 上游恢复需要 2-3 次重试时,对话气泡里就会堆出 2-3 条一模一样的错误(用户原话「100% 显示出来」)。本版加同错误去重门控:- 首次出现的错误 key:立即 yield(携带新信息)。
- 连续相同错误:沉默到累计 ≥ 3 次(默认)才再 yield。
- 任何 429 rate-limit:始终 yield —— wait-time 信息是它存在的意义。
- 错误 key:用
Error.name + APIError.status + Error.message拼接,401 与 503 即使 message 相同也不会折叠。 - State 是 generator 闭包局部变量,跨 withRetry 调用不泄露;persistent 模式 heartbeat 复用一次性算定的结果,避免长 persistent 等待重复增计数。
- 环境变量
CLAUDE_CODE_RETRY_REPORT_AFTER=N可调阈值(默认 3)。 - 效果:一段 3 次相同错误的重试现在显示 2 个气泡而非 3 个;更长 streak 压缩更明显,但用户始终能看到通话还在重试。
测试
src/tools/AgentTool/invocationLimiter.test.ts:28 cases / 153 expects 全过。- 14 个原测试按新 cap=12 适配
- 5 个 streak 行为新测试:3 FAIL trip / PASS clears / UNKNOWN soft-PASS / per-agent-type 隔离 / 12 PASS 触 total cap not streak
- 9 个 parseVerdict 测试:empty / 标准 VERDICT 行 / FAIL 同义词 / APPROVE / 专家技能同义词 / 无 verdict / markdown 容忍 / 长 input tail
src/services/api/withRetry.test.ts:4 cases,3 个新测试覆盖 same-error 抑制、新 key 立即 yield、env override 提高阈值。- 两个 PR 各自的 verification 子代理均独立 PASS,含状态隔离、heartbeat 放大、UNKNOWN soft-PASS 攻击面、throw/abort 场景 streak 残留等对抗性 probe。
设计审查
- UNKNOWN 当 soft-PASS 的攻击面(#78):恶意子代理可省略 VERDICT 行避开 streak,但 total cap=12 仍兜底;且子代理 prompt 由调用方完全控制,不是普通输入面。
- throw / abort 场景的 streak 状态(#78):
noteInvocation已增计数但noteOutcome不跑——streak 保持原值不偏移,下次调用基于既有 streak 起步,PASS 仍能清零。 - 接入点对称性(#78):
AgentTool.tsx中noteOutcome与noteInvocation用完全相同的 guard(!toolUseContext.agentId && isBuiltInAgent(selectedAgent) && !isLimiterDisabled()),避免 streak/total 计数不同步。 - 非 APIError 不进对话流(#79):
Stream ended without receiving any events这类普通 Error 仍走外层CannotRetryError路径,本 PR 不扩大SystemAPIErrorMessage的类型契约(它要求error: APIError)。改契约会扩散到所有消费者,超出本 PR 范围。
范围
src/tools/AgentTool/invocationLimiter.ts:核心改造,加 streak 状态、noteOutcome、parseVerdict、双门判定。src/tools/AgentTool/AgentTool.tsx:completed 分支加noteOutcome调用。src/tools/AgentTool/invocationLimiter.test.ts:14→28 测试。src/services/api/withRetry.ts:加DEFAULT_RETRY_REPORT_THRESHOLD/errorIdentityKey/shouldReportRetry,2 处 yield 改 guard。src/services/api/withRetry.test.ts:1→4 测试。