SuperAI Agent v0.2.30
SuperAI Agent v0.2.30
被代理拦截后的自动重试,这次是真的在重试了。
更正:v0.2.26 与 v0.2.27 的重试从未生效
这两个版本都声称「空回复会自动重试」。实际上一次都没有重试过。
企业网络机器上的调试日志给出了确证:withRetry 每处理一个错误都会记录一行 API error (attempt N/M)。在一次连接被拒的失败中,日志里有整整 11 行;而在「空回复」失败中,一行都没有——说明 withRetry 根本没有看到那个错误。日志中只有一条 attempt=1,随后本轮对话直接结束。
原因是结构性的,我本应在发布前就核对:
withRetry 的操作回调 -> 在 claude.ts:1848 结束
生成器在此被驱动 -> 1853
非流式兜底请求 -> 2554 <- 已在重试循环之外
v0.2.26 抛出的可重试错误 -> 2629 <- 直接进入终止分支
withRetry 的操作回调只覆盖「创建流式请求」这一步;非流式兜底发生在之后的 queryModel 中,早已脱离该重试循环。因此那个 throw 直接落到了终止处理里。当时为了让 shouldRetry 返回 true 而把错误类型设计成 APIConnectionError,是在推理一个根本不会被执行到的函数。
结论:那两个版本只改变了报错文案,没有改变任何行为。
本次修复
-
重试改到实际发起请求的位置:新增
runEmptyFallbackWithRetry,在结果为空且判定允许重试时,重新执行非流式兜底请求(带短暂退避),耗尽后再给出与此前相同的终止报错。这件事也无法交给
executeNonStreamingRequest自带的withRetry处理:代理返回的拦截页是一个完全正常的 200 响应,而非传输层错误,那层重试没有任何可触发的条件。 -
attempt=现在统计的是兜底请求的次数:此前用的是attemptNumber,它统计的是内层请求的尝试次数,即使兜底已经跑了三次,它依然显示 1——现场日志里看到的正是这个数字,其误导性与上述问题同源。 -
删除
EmptyFallbackRetryableError:已无任何地方抛出它。一个名为「可重试错误」却从不会被抛出的类,正是导致这个问题拖了两个版本才被发现的那类东西。
验证情况
共 33 项测试通过,新增 3 项通过统计调用次数来验证重试确实发生——这正是前两次尝试所缺少的断言,也是它们连续两次带着问题发布的原因。
将循环故意改回「只执行一次就返回」(即 v0.2.26/27 的实际行为)后,3 项新测试中有 2 项失败——即这些测试确实能够捕获当初发布出去的那个缺陷。
按测试名比对失败集合,出现一项 SearchService > should respect maxResults limit;已确认为既有的不稳定用例:单独运行连续两次均通过,且在未包含本次改动的代码树上整套服务端测试一起跑时同样会失败,与本次改动无关。