
DeepSeek-Reasonix 工具中断后的持久恢复执行证据、恢复卡与安全重试机制全解析【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix导读工具调用是 Agent 与外部世界交互的边界而进程崩溃、网络中断或工具超时会让是否真的产生了外部效果变成悬案。DeepSeek-Reasonix 通过将执行证据交由 Go runtime 管理实现了一套不依赖新数据库的工具中断持久恢复机制所有执行证据沿 session、turn ledger 与文件 checkpoint 持久化Electron 本地 tab 与 Remote tab 共用同一套 Controller API用户可在重启后通过恢复卡安全地检查、确认或受限重试未决的工具调用。读完本文你将掌握其执行边界模型调用回执、幂等键、写入屏障、界面与传输链路快照、修订号、前台写权限、重试与幂等约束EffectVerifier、RecoveryScope、协议兼容策略以及完整的验证与交付流程。设计总览为何执行证据由 Go runtime 管理文档开宗明义执行证据由 Go runtime 管理。这意味着恢复能力的核心不在前端界面也不在 Electron 进程而在负责会话与回合turn账本的主机侧。Electron 本地 tab 与 Remote tab 共用同一套 Controller API沿用 session、turn ledger 和文件 checkpoint不新增恢复数据库。从源码看这一架构体现在两个层面会话层internal/agent/tool_recovery_records.go中的Session.toolRecoveryRecord/setToolRecoveryRecord直接读写会话消息里的ToolCall.Recovery字段恢复记录作为消息的局部元数据随 session checkpoint 一起落盘控制层internal/control/tool_recovery.go的Controller.ToolRecoverySnapshot()与ResolveToolRecovery()负责生成快照和执行恢复操作两者都复用与模型回合相同的会话写权限与准入互斥逻辑。因此整个恢复体系是既有持久化设施的语义层扩展而非旁路的新存储系统。执行边界回执先落盘再执行工具回执的生命周期文档规定参数检查、工具目标解析和权限判定完成后才建立调用回执。回执包含session、turn、call、attempt 标识规范化参数摘要ArgumentDigest对规范化参数做 SHA-256幂等键IdempotencyKey写入状态ToolRunStarted/ToolRunRunning/ToolRunUnknown/ToolRunNotStarted/ToolRunFailed/ToolRunCompleted/ToolRunUserConfirmed等。执行顺序严格固定先通过现有 session checkpoint 持久化回执再同步落盘tool_started最后才调用工具。第一个写工具同时把身份和 transcript 摘要绑定到文件 checkpoint形成谁在何时、以何参数、对哪个资源发起了什么写入的完整审计链。对应的实现位于 internal/agent/tool_recovery_records.go 的beginToolRecovery在设置恢复记录后调用emitToolStarted任何一步失败都会把状态回退为ToolRunNotStarted保证未持久化即视为未开始。调用过不等于效果已确认文档明确区分了两个概念调用过与外部效果已确认。重启后已开始但未确认结果的调用仍为未知unknown新格式中只有 dispatch、没有 start 的调用可以认定未开始not started旧记录缺少证据时保守处理不猜测成功或失败。unresolvedToolRecord见 internal/agent/tool_recovery_records.go将以下状态视为未解决ToolRunStarted、ToolRunRunning、ToolRunUnknown以及显式失败但效果未知且非只读的ToolRunFailed effect_unknown。值得注意的是显式工具错误只能证明失败不能证明外部部分效果不存在——这是本设计最关键的保守性原则之一。写入屏障未知写操作阻止后续写操作未解决的写操作构成写入屏障即使模型换了 call ID 发起新的写工具调用也会被beginToolRecovery中的检查拒绝返回recovery_required: inspect and resolve the previous uncertain tool effect before another write而只读诊断可以继续。从源码看屏障在 internal/agent/tool_recovery_records.go 实现遍历所有未解决记录只要存在非只读的未决效果且不是同一重试链就阻止本次写调用。同一 session 的压缩compaction或历史改写rewind也不会抹除未解决回执——retainUnresolvedToolRecords同文件 L175-L194会把未解决的非只读记录以LocalOnly消息形式保留在新历史中。用户确认语义用户确认记录为user_confirmed系统不会伪造工具成功输出也不会自动再次执行已确认的相同工具和参数。beginToolRecovery中专门检查confirmedRecoveryEffect如果该精确效果幂等键匹配已被用户确认发生新的写调用会被拒绝理由是用户已确认此效果发生过不再重复写入internal/agent/tool_recovery_records.go。界面与传输恢复卡与快照协议桌面统一入口与 Remote 转发桌面统一入口是GetToolRecoveryForTab和ResolveToolRecoveryForTab实现在 desktop/tool_recovery.go本地 tab通过tabAndCtrlByID拿到 Controller若实现toolRecoveryController接口ToolRecoverySnapshot()与ResolveToolRecovery(...)直接调用Remote tab通过remoteToolRecovery转发到 Serve 的GET/POST /tool-recoverydesktop/tool_recovery.go沿用认证、会话路径与前台写权限保护响应中的SessionPath与会话路径不一致时会报 remote recovery session changed。服务端路由注册在 internal/serve/tool_recovery.goGET /tool-recovery返回快照POST /tool-recovery经foregroundMutation包装以施加前台写权限保护且请求体限制 16 KiB 并DisallowUnknownFields。快照字段与操作约束ToolRecoverySnapshot携带以下字段internal/control/tool_recovery.go字段含义sessionPath快照所属会话路径runtimeEpoch运行时纪元重启后变化revision内容修订号对快照 JSON 做 SHA-256 得到calls未解决的工具调用列表retryEnabled是否开放重试受REASONIX_TOOL_RECOVERY_RETRY控制statistics未知、已确认、重试、拒绝、阻断等计数silent是否静默恢复关键设计普通快照隐藏原始参数Calls[i].Arguments nil前端拿到的是不可变身份与检查事实而不是可执行载荷。任何恢复操作必须提交快照及attemptId、inspectionId若请求中的sessionPath、runtimeEpoch、revision与当前快照不一致会返回 recovery snapshot changed; refresh before resolving。此外运行中、结束处理中、会话切换中、已关闭的 Controller 状态running/finishing/rotating/closed都会拒绝操作返回ErrTurnRunning见 internal/control/tool_recovery.go。恢复卡操作类型恢复卡支持四类操作Action字段见 internal/control/tool_recovery.go检查inspect执行效果检查只有显式检查才返回本地参数回执检查结果区分四种状态——效果存在present、文件后置条件满足postcondition_satisfied、效果不存在且旧尝试已被阻止提交absent_fenced、无法确认unknown。确认已生效confirm将记录置为user_confirmed必须在已检查的同一 attempt上操作inspectionId必须匹配。不重试reject保留未知事实与写入屏障。注意文档强调拒绝重试不能证明外部效果不存在。受限重试retry见下一节。检查逻辑实现在 internal/agent/tool_recovery_actions.go 的InspectToolRecovery若工具实现了tool.EffectVerifier先校验RecoveryScope()与原记录的资源身份一致再调用InspectEffect判定 present / absentfenced否则检查checkRecordedWrite是否满足文件后置条件。文件后置条件只证明当前状态不证明原调用结果——这正是postcondition_satisfied与present被区分的根本原因。切换 tab/session 后旧异步响应不得覆盖新界面——ResolveToolRecovery中的SessionPath/RuntimeEpoch/Revision三重校验正是为此服务。重试与幂等默认关闭条件严苛重试开关重试默认关闭。只有在拥有该 session 的 Go 主机设置环境变量REASONIX_TOOL_RECOVERY_RETRY1时才开放重试操作远程 tab 的重试能力由远端主机决定。从 internal/control/tool_recovery.go 可见RetryEnabled直接读取该环境变量ResolveToolRecovery对retry动作会先检查view.RetryEnabled否则返回 tool recovery retry is disabled。重试的管线约束重试使用新 call ID 和 attempt ID保留原幂等键和原始参数并经过正常的参数、权限、hook、租约和工具执行管线——它不是一个特权捷径。实现见 internal/agent/tool_recovery_actions.go 的RetryToolRecovery校验 attempt 未解决、inspectionId匹配校验旧执行者已退出stragglers.live 0否则 the previous executor is still running对写工具强制校验tool.EffectVerifier重试前必须重新证明效果不存在且旧尝试已无法再提交InspectEffect返回absent且Fenced true。仅观察到不存在不够校验重试期间目标未改变CanonicalTool、ArgumentDigest、ResourceScope三者一致否则 retry target changed during policy resolution以retry_hex新 call ID 创建新工具调用原记录标记SupersededBy旧请求不能再提交同一重试。幂等键与验证器接口幂等键的构成见 internal/agent/tool_recovery_records.go对身份 规范化参数摘要 资源作用域不含 attempt做 SHA-256。同一动作的所有显式重试共享同一幂等键。工具可通过tool.RecoveryIdempotencyKey(ctx)读取该键internal/tool/recovery.go在实际接收端实现去重。验证器接口定义在 internal/tool/recovery.gotype EffectVerifier interface { RecoveryScope() string // 稳定的接收端/账户/资源身份不随重试变化 InspectEffect(context.Context, string, json.RawMessage) (EffectInspection, error) }EffectInspection的State取值present | absent | unknownFenced表示旧尝试已无法再提交——Absent 只有在 Fenced 时才对重试安全。验证器的RecoveryScope必须与原记录的接收端、账户和资源身份一致在检查与重试两处都会校验。对于没有实现验证器的工具资源作用域保守地覆盖整个 sessionsession: SessionID绝不猜测路径或采用模型提供的 scope 来削弱屏障。能力边界不做无法兑现的承诺文件工具复用已有WriteVerifier做只读检查——internal/tool/write_recovery.go 定义WriteVerifier.VerifyWrite(ctx, FileWriteIntent)配合RecordWriteIntent钩子记录文件的 before/after 意图可判定satisfied | unchanged | conflict | unknown。而通用 shell 和任意 MCP 服务无法自动证明外部效果不存在因此默认保持未知。本实现不对没有权威回执或去重能力的第三方服务承诺 exactly-once——这是诚实的能力边界声明也是受限重试而非自动重试的根本原因。协议与兼容可选元数据向前向后兼容transcript gate 与执行恢复相互独立transcript gate转录门控与执行恢复是两条独立机制前者在 provider-request interceptor 之后、请求发送之前验证 adapter 配对规范化后的视图后者管理执行证据。已被 host 确认未执行的坏参数调用可以在请求修复视图中使用空对象并保留错误说明但本地原参数不改写。正常请求字节不变恢复回执不进入系统提示、工具 schema 或模型消息——它纯粹是宿主侧的本地元数据。兼容性保证新字段ToolCall.Recovery等为可选本地元数据旧 JSON 可读、旧事件编号不变旧远程客户端仍受新服务端执行屏障的保护屏障在服务端强制旧版本可执行程序没有新恢复保证因此应先解决未确认效果再降级 Go runtime本功能不自动改写存储格式也不执行降级迁移避免静默破坏历史数据。统计信息语义快照还提供从保留的 session 证据计算的未知、已确认、重试、拒绝和阻断计数ToolRecoveryStatistics但这些数据是当前恢复状态的视图不当作历史全量遥测——它们只反映保留中的未决记录及其处置情况。验证与交付测试覆盖与浏览器验收自动化测试覆盖文档列出的测试覆盖点在仓库中均有对应实现权限/参数拒绝、开始前持久化失败、状态分类见 internal/agent/tool_recovery_actions_test.go 与 internal/control/tool_recovery_test.go快照隔离、旧 attempt 拒绝见 internal/control/tool_recovery_crash_test.go幂等接收端、重复重试、存储失败后的确认回滚见 internal/agent/live_tool_recovery_confirm_test.go 与 internal/agent/unknown_recovery_test.go真实子进程场景真实子进程在副作用 fsync 后、结果返回前退出重启与并发确认验证结果持久化并确保副作用只发生一次——覆盖崩溃窗口内的效果确认这一核心竞态。浏览器验收命令cd desktop/frontend node bench/tool-recovery.mjs该验收脚本desktop/frontend/bench/tool-recovery.mjs 及其 fixture desktop/frontend/bench/tool-recovery-fixture.tsx覆盖检查、确认、继续任务、禁止不安全重试、切换 session 后拒绝迟到响应。前端恢复卡组件实现位于 desktop/frontend/src/components/ToolRecoveryPanel.tsx类型契约见 desktop/frontend/src/lib/toolRecovery.ts。部署注意点部署时必须配套更新 Go runtime 与 Electron 生成契约desktopContract.generated系列由契约生成流程产出先保持重试关闭核实具体工具的接收端语义后再开启。关闭重试不会删除证据或人工恢复能力。远端发布和生产灰度是独立交付步骤不等同于本地实现与测试完成——恢复功能的可靠性门槛以本地全链路验证通过为前提。总结DeepSeek-Reasonix 的工具中断恢复机制围绕一条核心原则展开对不确定的外部效果保持保守绝不猜测、绝不重复、绝不伪造。它通过回执先落盘再执行建立执行边界通过写入屏障阻止不确定状态下的级联写入通过EffectVerifierRecoveryScope 幂等键实现受限重试的安全前提并通过快照修订号与 epoch 校验保证恢复操作的会话一致性。对于无法提供权威回执的通用 shell 与任意 MCP 服务系统诚实地将效果保持为未知交由用户在恢复卡上基于检查事实做出确认或拒绝的决定。这套机制既可用作运行时崩溃后的自愈底座也可作为 Agent 工具链路审计与人工交接的标准实践参考。【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考