Record unanswered tool results before closing a failed step
在关闭失败步骤前补齐工具结果
A committed assistant message can request tools whose scheduler fails before all results are recorded. Closing the step and turn with those calls unanswered makes later model requests invalid for providers that require paired tool calls and results. An error turn is already closed, so crash-tail repair cannot recover it on resume.
English
Problem
A committed assistant message can request tools whose scheduler fails before all results are recorded. Closing the step and turn with those calls unanswered makes later model requests invalid for providers that require paired tool calls and results. An error turn is already closed, so crash-tail repair cannot recover it on resume.
Decision
The AgentLoop driver records recovery results for unanswered calls before it closes a failed step, then propagates the original failure. Live step recovery and interruptedTurnClosers share incremental pending-call tracking and result construction; the live driver still owns its step and turn events. A step-local observer retains pending identities from committed events without copying session history. The scheduler stops replenishment and drains started dispatches before rejecting, so result recovery cannot race a live dispatch.
Recovery preserves committed results and follows the assistant's call order. A recorded tool/call without a result receives TOOL_OUTCOME_UNKNOWN; its text warns against blindly retrying an operation with possible side effects. An assistant request with no call record receives TOOL_NOT_STARTED. A call record precedes preparation and does not establish that the tool body ran, so unknown outcomes remain conservative.
This decision supersedes only the missing-result policy in parallel tool-call execution. Its classification, concurrency limit, ordering, and quiescence rules remain applicable.
Alternatives considered
Leave calls unanswered to avoid inventing tool outcomes. An unanswered call invalidates later provider requests. An explicit unknown-outcome error records the limit of the available evidence without claiming success, cancellation, or absence of side effects.
Repair only when resuming or forking. The ordinary failure path already records step/end and turn/end; open-tail repair intentionally preserves closed history. Recovery belongs before those records, while the driver owns the failed step.
Repair inside the tool scheduler alone. Failure can occur after the assistant message is recorded but before scheduling starts. The step driver covers that interval and reuses the existing session repair semantics rather than adding a second implementation of call/result matching.
Retry automatically. A dispatch can have side effects even when its result is missing. The error result supplies retry guidance, while the turn retains the original failure and waits for later work.
Consequences
Later requests, resume, and fork retain a usable call/result history after a live step failure. Recovery appends results; it does not remove assistant messages, replace completed results, execute tools, or convert the failed turn into success. The log uses existing event types and recovery codes, with no format change.
Already-closed inconsistent historical turns remain unchanged. The live recovery path requires the session to accept the missing result records; it cannot promise recovery from a failed log append.
中文
问题
已提交的 assistant 消息可能请求多个工具,而调度器在全部结果记录完成之前失败。如果关闭步骤和轮次时仍有调用尚无结果,后续模型请求就不满足要求工具调用与结果配对的提供方。错误轮次已经关闭,因此恢复会话时的崩溃尾部修复无法恢复它。
决策
AgentLoop 驱动器在关闭失败步骤之前,为尚无结果的调用记录恢复结果,随后传播原始失败。实时步骤恢复和 interruptedTurnClosers 共享增量的待处理调用跟踪与结果构造;实时驱动器仍拥有自己的步骤和轮次事件。步骤本地观察器从已提交事件中保留待处理调用标识,不复制会话历史。调度器在拒绝之前停止补充池并排空已启动的派发,因此结果恢复不会与运行中的派发竞争。
恢复保留已提交的结果,并遵循 assistant 的调用顺序。已有 tool/call 记录但尚无结果的调用获得 TOOL_OUTCOME_UNKNOWN;其文本警告不要盲目重试可能存在副作用的操作。没有调用记录的 assistant 请求获得 TOOL_NOT_STARTED。调用记录先于准备阶段,不能证明工具主体已经运行,因此未知结果保持保守。
本决策仅取代并行工具调用执行中的缺失结果策略。其中的分类、并发上限、顺序和完全停稳规则继续适用。
备选方案
让调用保持无结果,避免虚构工具执行结果。 尚无结果的调用会使后续提供方请求无效。显式的未知结果错误记录可用证据的局限,而不声称成功、取消或没有副作用。
仅在恢复或 fork 时修复。 普通失败路径已经记录 step/end 和 turn/end;开放尾部修复有意保留已关闭历史。恢复应在这些记录之前执行,此时驱动器仍拥有失败步骤。
仅在工具调度器内部修复。 失败可能发生在 assistant 消息记录之后、调度开始之前。步骤驱动器覆盖这段区间,并复用已有的会话修复语义,避免另行实现调用/结果匹配。
自动重试。 即使结果缺失,派发也可能产生副作用。错误结果提供重试指引,而轮次保留原始失败并等待后续工作。
影响
实时步骤失败后,后续请求、恢复和 fork 会保留可用的调用/结果历史。恢复追加结果;它不移除 assistant 消息、不替换已完成结果、不执行工具,也不将失败轮次改为成功。日志使用已有事件类型和恢复代码,无需格式变更。
此前已关闭的不一致历史轮次保持不变。实时恢复路径要求会话能够接纳缺失结果记录;它不能保证从日志追加失败中恢复。