文件与行号
internal/provider/openai.go:485-487(mid-stream retry 的 retrySleep 失败分支)对照 :401-404(connect 阶段对称路径)与 anthropic.go :436-439
问题描述
流式请求收到可重试错误且尚未 emit 内容时进入 mid-stream retry;retrySleep 等待期间 ctx 取消 → 发送 StreamEventError 后直接 return,但没有设置 streamError = true。外层 L590 if !streamError 随后计算 usage 并发送 StreamEventDone → 消费者先收到 Error 再收到 Done,终止事件契约(恰好一个 Error 或 Done)被违反。
三处对称代码中两处正确设置了标志(openai connect 阶段、anthropic mid-stream),唯独此处漏写,不对称性证明是疏忽。gemini.go 无此问题(其 return 直接退出 goroutine)。
触发场景
connect 成功 + 首个 Recv 返回可重试错误(429/5xx)且未 emit + backoff 期间(最长 30s,Retry-After)用户 Ctrl+C/会话超时 → Error 后紧跟带 usage 的 Done。
预期行为 vs 实际行为
- 预期:终止事件恰好一个(Error)
- 实际:Error 之后又发 Done(usage=0)
主消费路径(agent.go L4559 在首个 Error 即 return)当前被意外保护,实际故障面为零;但 fallback 透传层及未来任何读完 channel 的消费者会把带 Usage 的 Done 解读为成功完成。
修复建议
L486 后补一行 streamError = true,与 L403、anthropic L438 对齐。
严重程度
Low(协议契约违规,经独立 subagent 复核确认;现网消费路径短路保护,属潜在契约陷阱)
文件与行号
internal/provider/openai.go:485-487(mid-stream retry 的 retrySleep 失败分支)对照:401-404(connect 阶段对称路径)与 anthropic.go:436-439问题描述
流式请求收到可重试错误且尚未 emit 内容时进入 mid-stream retry;
retrySleep等待期间 ctx 取消 → 发送StreamEventError后直接return,但没有设置streamError = true。外层 L590if !streamError随后计算 usage 并发送StreamEventDone→ 消费者先收到 Error 再收到 Done,终止事件契约(恰好一个 Error 或 Done)被违反。三处对称代码中两处正确设置了标志(openai connect 阶段、anthropic mid-stream),唯独此处漏写,不对称性证明是疏忽。gemini.go 无此问题(其 return 直接退出 goroutine)。
触发场景
connect 成功 + 首个 Recv 返回可重试错误(429/5xx)且未 emit + backoff 期间(最长 30s,Retry-After)用户 Ctrl+C/会话超时 → Error 后紧跟带 usage 的 Done。
预期行为 vs 实际行为
主消费路径(agent.go L4559 在首个 Error 即 return)当前被意外保护,实际故障面为零;但 fallback 透传层及未来任何读完 channel 的消费者会把带 Usage 的 Done 解读为成功完成。
修复建议
L486 后补一行
streamError = true,与 L403、anthropic L438 对齐。严重程度
Low(协议契约违规,经独立 subagent 复核确认;现网消费路径短路保护,属潜在契约陷阱)