ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Apache Maka 崩溃恢复事实源架构:RuntimeEvent 唯一账本与 RecoveryResolver 判定权威解析

Apache Maka 崩溃恢复事实源架构:RuntimeEvent 唯一账本与 RecoveryResolver 判定权威解析 Apache Maka 崩溃恢复事实源架构RuntimeEvent 唯一账本与 RecoveryResolver 判定权威解析【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka导读本指南剖析 Apache Maka 在 Runtime Resume Phase 2.5–3 阶段落地的恢复语义决策当 Agent 运行时在工具派发边界处崩溃系统如何判定工具到底执行了没有。文章围绕一份已接受的 ADR架构决策记录展开完整覆盖 RuntimeEvent 唯一事实源、T1 dispatch 边界事件、协议 marker 门控、RecoveryResolver 决策表、可重建投影与 continuation replay 清单并结合仓库源码与测试给出可验证的实现证据。读完你不仅能理解 Maka 的崩溃恢复判定模型还能直接定位到对应的类型定义、存储实现与测试用例用于在自己的恢复系统设计中复用其 fail-closed 思路。一、问题背景两套并行事实如何引发状态机漂移Maka 的 Phase 2 已经把 provider 可见的function_call、Tool Journal 和tool_operations放进同一个 SQLite 事务但这仍遗留一个根本性问题系统中存在两套可能独立演进的恢复事实——RuntimeEvent表达 provider 历史的 append-only 事件流Tool Journal / tool_operations表达是否跨过了工具派发边界的查询投影。如果恢复代码分别读取二者并自行推断冲突处理、legacy 兼容和后续状态扩展都会退化为平行状态机同一份崩溃现场Planner、CLI、UI 各自组合事实可能得出不同结论。本 ADR 的核心动机就是确定事实归属、判定权威与投影边界并明确声明其承诺边界——它不承诺从 Runtime 内部事实推导外部世界的绝对状态外部副作用在崩溃窗口内仍可能未知。二、核心决策 1RuntimeEvent 是唯一 canonical recovery fact sourceADR 的第一条决策确立了事实的唯一性规则工具执行边界、工具结果、恢复判断和 reconcile 结果都必须表现为 append-only RuntimeEventTool Journal 与tool_operations只保留为 SQLite 查询投影不是第二份账本Runtime 不得只写 Journal 而不写对应 RuntimeEventJournal 行必须引用产生它的 RuntimeEvent新协议数据删除投影后必须能从 RuntimeEvent 重建投影冲突时以 RuntimeEvent 为准冲突本身作为corruption处理projection 可以与 RuntimeEvent 在同一个 SQLite 事务中同步更新但这不改变事实归属。Legacy 数据不伪装成新协议。缺少新协议 marker 或 dispatch fact 的历史按 legacy 规则保守解释——不能利用事件缺失证明工具未执行。从源码看这条规则已被落实为类型系统约束。在 packages/core/src/runtime-event.ts 中RuntimeEvent 的actions字段同时承载toolDispatch、toolRecovery、runtimeProtocol、stateDelta等恢复语义载体见 runtime-event.ts#L558-L588校验器对每一类都做了严格判定见 runtime-event.ts#L1315-L1340。三、核心决策 2T1 是独立、非模型可见的 dispatch RuntimeEventADR 明确区分两个概念function_call只表达 provider 发起调用不能同时承担 T1工具派发边界语义——它可以在权限等待期间先提交。真正的 T1 事件是独立提交的 dispatch RuntimeEvent时机在所有参数校验、availability、loop、权限与 runtime guards 通过之后、工具 implementation 之前actions.toolDispatch { protocol: t1_after_preflight_v1, operationId, providerToolCallId, toolName, canonicalArgsHash, recoveryMode }该事件的准确含义是Runtime 已进入不可安全假定 implementation 未执行的边界而不是副作用已经发生。T1 事务原子提交 function call若尚未存在、dispatch RuntimeEvent 和查询投影T1 提交失败必须阻止 implementation。源码层面这一事实模型定义在 packages/core/src/runtime-event.ts#L431-L450常量TOOL_BOUNDARY_PROTOCOL_V1 t1_after_preflight_v1RuntimeEventToolDispatch接口包含protocol、operationId、providerToolCallId、toolName、canonicalArgsHash、recoveryMode并可携带managedMutationT1 冻结的托管工作区变更身份见 runtime-event.ts#L449。canonicalArgsHash的生成逻辑可参见 packages/core/src/tool-args-identity.ts。四、核心决策 3Protocol marker 是运行时事实不是版本属性toolBoundary: t1_after_preflight_v1只在canonical durable commit sink 实际接线时写入不能根据软件版本无条件写入。具体约束JSONL/best-effort 或无 tool commit sink 的 run不得携带此 marker该 capability 由 host 显式注入再按当前 run 选择的 backend 门控SQLite store 的存在本身不是充分条件——当前只有确实接入RuntimeCommitSink的 AiSdk tool path 可以声明该协议其他 backend 即使共享同一个 SQLite RuntimeEventStore 也不得继承 markermarker 只允许位于 run 的首个 canonical RuntimeEvent普通 runinitial user RuntimeEvent 的actions.runtimeProtocolcontinuation runcontinuation-start RuntimeEvent 的actions.runtimeProtocolResolver 不接受中途补写 markermarker 缺失即 legacy/unknown protocol。这一逻辑在 packages/runtime/src/agent-run.ts 中有直接实现。commitInvocationOpening负责在 invocation 首个事件上挂载协议 marker见 agent-run.ts#L1505-L1530其注释明确写道It is the invocations first event, so it also carries the protocol marker RecoveryResolver reads off event one. 同时在事件消费路径上isAtomicToolBoundaryProjection会拦截已由RuntimeCommitSink持久化的协议标记事件避免重复追加破坏边界见 agent-run.ts#L900-L903。五、核心决策 4RecoveryResolver 是唯一判定权威Planner、CLI、UI 和未来 reconciler不得各自组合事实它们只消费RecoveryResolver输出的稳定 decision 与 reason code。核心决策表如下RuntimeEvent facts判定call matching response无 dispatchcompleted表示 T1 前合成结果legacy 下 response 本身也是完成证据call dispatch matching responsecompletedcall dispatch无 responseindeterminateResolver 置requiresReconciliationreason 记dispatch_without_responsecall无 dispatch、无 response首事件声明新协议definitely_not_dispatchedcall无 dispatch、无 responselegacy/unknown protocolindeterminatedispatch 存在但对应 call 不存在corruptionresponse 存在但对应 call 不存在corruptiondispatch/response 的 operation、tool call、tool name 或执行身份冲突corruption同一 operation 出现多个不一致 dispatch 或 responsecorruptioncall含 dispatch 后无 response且 operation 已带 recovery decision fact以 recovery bundle 结算disposition 为completed则completedreasonrecovery_bundle_completed否则parked并沿用 fact 的 reasonCodefact 本身损坏按 corruption 处理Resolver 必须fail-closed未知组合不能退化成自动重试。Phase 3 恢复写入者经原子 recovery bundle 事务提交actions.toolRecoverydecision factmaka.tool.recovery_decisionprotocoltool_recovery_v1后续 reconcile 结果同样追加事件不回写历史事实。源码与测试证据Resolver 主函数resolveRuntimeRecovery及其决策模型位于 packages/runtime/src/tests/recovery-resolver.test.ts 的 import 声明recovery-resolver.test.ts#L28-L31。测试新协议 call 无 dispatch →definitely_not_dispatchedreasonnew_protocol_before_dispatch见 recovery-resolver.test.ts#L34-L51测试dispatch 无 response →indeterminatereasondispatch_without_response且requiresReconciliation: true见 recovery-resolver.test.ts#L53-L73recovery fact 的类型定义集中在 packages/core/src/tool-recovery-fact.tsdecision fact 分为ToolRecoveryCompletedDecisionFactdispositioncompletedreasonCodereconcile_matches_expected_state与ToolRecoveryParkedDecisionFactdispositionparkedreasonCode 取reconcile_matches_prior_state/reconcile_diverged/reconcile_unreadable见 tool-recovery-fact.ts#L43-L62reconcile 观察事实使用maka.tool.reconcile_resultkindprotocoltool_reconcile_v1observation 含matches_expected_state/matches_prior_state/diverged/unreadable见 tool-recovery-fact.ts#L20-L36recovery bundle 的原子结算约束定义在 packages/core/src/tool-recovery-bundle.ts校验 reconcile 与 decision 双 fact 的配对关系见 tool-recovery-bundle.ts#L159-L170。六、核心决策 5Journal 是可重建投影不是第二份账本Phase 2.5 保留现有表以降低查询成本但状态集合缩窄为写入路径可达的集合prepared | reconcile_observed | outcome_committed | recovery_completed | recovery_parked该集合与ToolJournalState联合一致其中reconcile_observed由 reconcile 追加事件写入。未来新状态若需要查询表示先定义对应 RuntimeEvent再扩展 projector。新协议的重建验收标准清空tool_journal_events与tool_operations后从 RuntimeEvent 投影得到相同的 operation identity、dispatch/result event refs、recovery mode 与 current state。存储实现可见 packages/storage/src/sqlite-runtime-store.tsToolJournalState类型即包含reconcile_observed见 sqlite-runtime-store.ts#L215-L217投影写入同时维护tool_journal_events与tool_operations两张表见 sqlite-runtime-store.ts#L2739-L2758并提供了按 dispatch_event_id 清空投影以便从 RuntimeEvent 重建的路径见 sqlite-runtime-store.ts#L3062-L3084。七、核心决策 6Continuation 保持组装式 replay不把全部祖先事件复制进 continuation run避免 O(n²) 存储和重复 canonical facts。continuation-start 的actions.stateDelta.replaySources保存 canonical manifest[{ invocationId, runId, turnId, highWater, prefixDigest }]prefixDigest对原始不可变前缀做摘要按 durable 顺序使用 event id 与完整 payload 的规范化序列化不摘要provider replay 投影因为投影逻辑会随版本演进planning 与 execution revalidation 复用同一个祖先遍历器每个 source 都校验 identity、high-water 与 prefix digestcycle 与 depth overflow 使用稳定 park/revalidation codebatch read 属于性能优化不是 Phase 3 前置条件。类型层面RuntimeEventContinuationStartV2在 runtime-event.ts#L507-L524 定义了protocol: continuation_start_v2、boundaryDigest、immediateSource含highWater与prefixDigest、replayManifestDigest、providerProjectionVersion1 | 2与providerReplayDigest实现上镜像了 store 持有的 claim 状态且恢复逻辑不会单独信任该字段。八、核心决策 7Phase 0–3 的身份契约一个 Invocation 对应一个 AgentRun。Continuation 创建新的invocationId、runId 和 turnIdinvocationId隔离 provider/tool execution 与 operationIdrunId标识 durable operational ledger当前阶段不宣称一个 invocation 包含多个 run。九、被否决的方案与理由方案否决理由Journal 作为唯一事实源要求 legacy RuntimeEvent 被硬塞进 Journal 语义使 provider replay 与恢复状态分别拥有事实权威RuntimeEvent 与 Journal 都是事实源事务一致不能消除两套状态机的解释漂移corruption 时无法回答谁有最终权威continuation 物化全部祖先事件造成链长增长时的 O(n²) 存储、事件身份重复和去重复杂度十、实施顺序Phase 2.5 → Phase 3Phase 2.5增加 dispatch RuntimeEvent 和运行时 protocol markerJournal 改为其同步投影。Phase 2.5实现稳定 revalidation error code清理无生产调用的旧接口与虚设状态。Phase 3实现纯 RecoveryResolver 与完整决策表。Phase 3经 recovery bundle 提交 terminal decision factdispositionparked/completed先支持 park/reconcile不直接自动重跑有副作用工具。Phase 3加入 replay manifest、全 source digest revalidation 与投影重建工具。十一、验收不变量可直接转为测试断言ADR 末尾给出的不变量清单既是实现验收标准也是本文所述机制的完整行为契约T1 失败时 tool implementation 调用次数为零dispatch 事件存在而 response 缺失时不得自动重试新协议中 call 缺少 dispatch 可以判定definitely_not_dispatchedlegacy 中相同缺口仍为indeterminatepermission deny 等 T1 前合成 response 被判定completedorphan dispatch、orphan response 和 ref mismatch 被判定corruptionprotocol marker 只在 durable boundary 实际激活时出现在首事件删除新协议 Journal/operation projection 后可以从 RuntimeEvent 等价重建continuation 执行前校验每个 replay source 的原始前缀 digest。这些不变量在仓库测试中均有对应覆盖除了前文引用的 recovery-resolver.test.ts 之外还可对照 packages/core/src/tests/tool-recovery-authority.test.ts决策 fact 的构造与结算、packages/storage/src/tests/sqlite-runtime-crash.test.ts 与 packages/storage/src/tests/sqlite-recovery-concurrency.test.ts崩溃与并发下的存储行为以及 packages/runtime/src/tests/continuation-replay.test.tsreplay manifest 校验。十二、设计要点回顾对本 ADR 的工程价值做一个收敛性总结便于直接引用单一账本一切恢复相关事实只存在于 append-only RuntimeEvent查询投影Journal / tool_operations可被清空重建边界显式化T1 dispatch 是独立、非模型可见的事件语义是不可安全假定未执行与副作用已发生严格区分能力门控协议 marker 由 host 注入 backend 门控SQLite store 存在不等于协议可用防止软件版本升级自动声明不存在的 durable 边界判定收敛RecoveryResolver 是唯一权威输出稳定 decision reason code任何消费方不得自行推断fail-closed 与不自动重跑未知组合不重试带副作用工具崩溃后先 park/reconcile由后续 recovery bundle 结算终态组装式 continuationreplay manifest prefix digest 校验避免 O(n²) 物化同时保证每个 replay source 的原始前缀不可篡改。完整 ADR 原文位于 docs/architecture/runtime-recovery-resolver-adr.zh-CN.md其配套的英文设计文档 docs/architecture/runtime-resume-architecture.md 与阶段崩溃契约docs/architecture/runtime-resume-phase0-crash-contract.md、docs/architecture/runtime-resume-phase1-safe-boundary-contract.md提供了更完整的上下文读者可按需深入。【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表