完善 Agent Runtime 成功交接与终态恢复

新增 Provider 成功响应 handoff,绑定真实 requestId 并支持原子恢复
补齐 compaction 与 finalization v4 的 stream committed 提交事务
让 Runner 在 handoff 存在时保持 busy,并覆盖冲突与崩溃窗口
同步 V1.41 技术方案、实施计划和项目共享记忆
This commit is contained in:
AIGameCreator App
2026-07-20 02:31:11 +08:00
parent 50e33dd469
commit c321aef489
12 changed files with 2493 additions and 92 deletions
@@ -4910,3 +4910,13 @@
- 恢复:进入 Provider 前先同步 response 阶段计划投影与 context bundle。Runner 重启后即使公共 state 先投影 planning,执行 pass 也先按当前 run sidecar 识别 `requestKind=final-reply / final-reply-context-compaction`,恢复原 `nextLoopIndex` 并跳过新的 tool-plan;后者先恢复同一压缩请求,再继续原 final-reply。重建请求或 Provider/Goal/steer/revision 身份漂移时删除旧 sidecar,只记录漂移字段名并在同一 run 重新规划,不提交旧回复。
- 流式与终态:失败 attempt 的半句只进入 failed/discarded response-stream,恢复 attempt 沿原基础 stream 身份推进;唯一 canonical assistant 仍只由 finalization journal 提交。确定性测试覆盖 sidecar-first 投影窗口、到期前零请求、失败/恢复 HTTP body 逐字节一致、无重复 tool-plan、唯一 assistant/completed/committed stream 和终局零 retry sidecar。
- 证据边界:当前 `provider_retry_` 21/21、`provider_transient_retry_` 5/5、`response_stream_` 16/16,Tauri/Rust 串行全量 `969 passed / 4 ignored`。尚未完成真实外部 Provider 的 final-reply 退避期 Runner 强杀,因此不能复用 V1.39 首次 tool-plan 的真实 PASS;手动压缩和 tool-plan `repair-N` 继续保持进程内重试。Provider 成功返回到压缩 sidecar 或 finalization journal `prepared` 之间仍有崩溃窗口,重启可能重新请求 Provider;finalization journal 清理到 stream committed 之间也不是可恢复事务。本切片只保证失败重试与最终 assistant 幂等,不能声称成功请求 exactly-once 或 stream 终态事务已经完成。
## 2026-07-20 AI 游戏创作 Agent Runtime V1.41 Provider 成功交接与回复流终态恢复
- 持久所有权:`game-creator-provider-handoff.v1` 是 Provider 成功返回与消费端 durable commit 之间的私有交接记录,每个 Agent/run 最多一条。只允许无 tool call 的 `context-compaction / final-reply-context-compaction / final-reply`,绑定完整 retry identity、真实 request slot/attempt、真实 Provider lifecycle requestId、规范化文本响应及其指纹;不保存 prompt、请求消息、API Key、Provider URL、tool call/arguments 或错误正文。
- 提交顺序:物理 Provider 成功后先去 thinking、按既有规则脱敏并原子写入 handoff,再回读逐字段完全一致,之后才允许为 handoff 中保存的真实 requestId 写 `completed` lifecycle。handoff 成为 durable owner 后,恢复先补齐同一 requestId 的 `started -> completed`,再零网络回放响应;不得生成新 requestId、把真实成功记到 base requestId,或在 handoff 未回读成功时宣称 lifecycle completed。
- 所有权转移:上下文压缩必须先把规范 compaction sidecar 原子写入并回读一致,才可删除匹配 handoff;final-reply 先把回复转入 finalization journal `prepared`,随后由 journal 持有 assistant、Runtime/Goal 终态和 response stream 提交责任。终局清理不得早于下一 durable owner 建立;取消、steer、Goal 作废、失败或其它终态也必须按完整身份清理所属 handoff。
- 冲突与漂移:同一 run 的 handoff 与 retry identity/attempt/slot 完全一致时,以 handoff 为成功事实并清理 retry;任一字段冲突必须在网络调用前进入 `needs-reconciliation`,保留两份 sidecar 和真实 requestId 供核对。相同 durable run 的 Goal/steer/request/config 等身份漂移,先按 handoff 的旧真实 requestId 补齐 lifecycle,再只记录漂移字段名、删除旧 handoff/retry 并回到同 run planning;响应正文不得进入公共审计。跨 run 身份冲突直接失败关闭。
- 回复流事务:finalization journal 升级为 v4,并固定保存 `responseRequestSlot / responseSteerCursor / responseRevision / response`。assistant 与 Runtime/Goal 已幂等完成后,journal 仍必须保留到匹配 response stream 写成 `committed` 且立即回读身份、状态和正文完全一致;之后才可删除 journal 和剩余 handoff。提交使用 journal 的固定 Agent/task/Session/run/request slot/steer cursor/revision,禁止调用面向 UI 的可见性过滤或用当前全局 project revision 静默跳过既定 run 的 stream。
- 回复流恢复:stream 缺失或仍为 `streaming` 时,可用 journal 固定身份和正文重建 `ready` 后提交;已 `committed` 且正文一致时按幂等成功继续清理。既有 stream 身份冲突、ready/committed 正文冲突、写入失败或回读失败都必须保留 journal 并保持可恢复 finalization,不能删除证据、覆盖冲突正文或把 finalization 当成已经清理。
- Runner 与边界:primary、`.previous` 或损坏的 handoff 都使所属 root 保持 busy,并阻止 `runner.shutdown_if_idle`。handoff 原子提交并回读前强杀 Runner,仍可能留下 Provider 已成功但本地只有未闭合 `started` 的未知窗口;Runtime 只能失败关闭,V1.41 不因此承诺端到端 exactly-once。`tool-plan` 和 function arguments 明确不在本协议内,真实外部 Provider 的 final-reply 退避期 Runner 强杀仍需独立 E2E 后才能记 PASS。
@@ -115,6 +115,26 @@ cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml provi
第一条测试必须停在 final-reply retry sidecar 已提交而 task/state 尚未投影的窗口,恢复扫描补齐 waiting 后在到期前保持零请求;第二条必须让 final-reply 前置自动压缩先失败并进入 `requestKind=final-reply-context-compaction` 等待态,到期后恢复同一压缩请求,再继续原 final-reply。两条链路都不得重新调用 tool-plan;失败和恢复请求只比较 HTTP body 字节、SHA-256 和长度,测试失败不得打印正文。真实 Provider 验收必须另起独立 suite,在 Supervisor 已认领全部专业回执、repair 和宿主验证后注入 final-reply 故障并于退避期强杀 Runner;该 suite 尚未 PASS 前,不能复用 V1.39 首次 tool-plan 的真实证据。Provider 成功返回到 finalization journal `prepared` 之间的崩溃窗口仍须独立补齐和验收,当前门禁不能据此宣称 Provider 调用 exactly-once。
### AI 游戏创作 Runtime V1.41 成功交接与回复流恢复复验
修改 Provider 成功响应、持久重试、finalization、response stream 或 Runner idle 判定后,至少运行:
```bash
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml provider_handoff_ -- --nocapture --test-threads=1
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml response_stream_ -- --nocapture --test-threads=1
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml durable_provider_handoff_prevents_shutdown_even_when_corrupt -- --nocapture --test-threads=1
```
复验和排障按 durable ownership 的顺序取证:
1. 先按 handoff 中保存的真实 `providerRequestId / requestSlot / attempt` 核对 Provider lifecycle。成功响应必须先原子写入 handoff 并回读完全一致,再为同一真实 requestId 补 `completed`;恢复不得生成替代 requestId。
2. 在 handoff 已提交、lifecycle 仍只有 `started` 的 checkpoint 停止执行,关闭 mock Provider 后再恢复。final-reply 必须零网络回放并只产生唯一 assistant/completed/committed stream;前置压缩只允许在回放压缩结果后发出后续必要的 final-reply,不能重复 tool-plan 或 compaction。
3. 同一 run 同时存在 handoff 与 retry 时,完全匹配才允许回放并清理 retry;identity、attempt 或 slot 冲突必须零网络进入 `needs-reconciliation`,保留两份 sidecar 和真实 requestId 证据,不要为了让 Runner 退出而手工择一删除。
4. finalization 已到 `runtime-completed` 后,故意删除 stream、保留 `streaming` 半句、注入 committed 写失败、在 committed 后 journal 清理前停止,并在期间推进全局 project revision。恢复必须始终使用 journal 固定的 run/request slot/steer cursor/response revision 与正文重建或幂等提交,写入后回读成功才可删除 journal。
5. 固定身份或正文冲突、stream 写入或回读失败时,断言 journal 保留且恢复扫描继续处理同一 finalization;Runner 对 primary、`.previous` 或损坏 handoff 都应保持 busy,`runner.shutdown_if_idle` 不得返回 idle。终局再核对 retry/handoff/finalization sidecar 全部为零,并扫描公共 task/event/Agent DB/CLI,确保没有响应正文、thinking、凭据、Provider URL 或绝对路径。
V1.41 只覆盖无 tool call 的 `context-compaction / final-reply-context-compaction / final-reply`。Runner 在 Provider 成功后、handoff 原子提交并回读前被硬杀时,仍只能把未闭合 `started` 视为结果未知并失败关闭;该窗口不是 exactly-once。`tool-plan` 及其 function arguments 不进入 handoff,真实外部 Provider 的 final-reply 退避期 Runner 强杀仍需独立 E2E,不能用上述确定性测试或 V1.39 PASS 代替。
suite 只能读正式 AppData,在其同级目录写入 sentinel 管理的 `0600` 私有副本和 overlay;启动 CLI/Runner 时须把 loopback 合并进大小写两套 no-proxy 环境,防止系统 HTTP 代理绕过本地故障门禁;source-dir guard 必须证明本 suite 前缀未进入源目录,源配置和 endpoint 身份保持不变,报告不得保存 Provider URL、headers、正文、凭据或绝对配置路径。sidecar 先于 task/state 投影是合法提交窗口,验收器应等待完整等待态后再强杀;若后续协作或终局失败,partial report 仍应保留已取得的 retry checkpoint,但失败轮不得与后续成功轮拼接。
### AI 游戏创作自主 Swarm 终端复验
@@ -3367,3 +3367,14 @@
- 真实验收陷阱:sidecar 按设计早于 task/state 等待投影落盘,验收器看到 sidecar 后必须继续等完整 `running / waiting-for-provider-retry`,不能把合法提交窗口误判为 torn projection。共享 Runner 强杀会同时中断其它 Agent 的 in-flight Provider 请求;要隔离验证单个持久 retry,应在子请求产生前对父 Agent 首次规划注入故障,恢复后再完成同一 run 的并行协作。首批同批双委派若只依赖自然语言提示会受模型波动影响,真实 suite 应使用正式 collaboration policy/preflight 固定两个指定 static Agent,并保留无正文的 batch 数量诊断。长链路还可能发生额外真实瞬态失败,不能用“全局 failed/retry 必须等于 1”把已正确恢复的网络抖动误判为注入失败;应按 request identity 锁定唯一受控链,额外 failure/retry 独立计数并继续执行全部 lifecycle、后继终态和零残留门禁。
- final-reply 恢复陷阱:不能把当前 Runtime `status / phase / currentAction` 投影或整份临时 tool-plan 放进要求跨进程稳定的请求指纹。前者在 `waiting -> planning -> response` 恢复过程中必然变化,后者的 `planUpdate/actions` 不会由 context bundle 原样保存;两者都会让合法 `-transient-N` 被误判为 drift。final-reply 必须在请求前同步 response 状态与 context bundle,并只使用可由 bundle 精确恢复的有界收束摘要;恢复 pass 先识别 `final-reply` 或 `final-reply-context-compaction` sidecar、恢复原 loop 并跳过新 planning。Agent DB lifecycle 的 requestKind 白名单也必须同步扩展,否则压缩请求会在网络调用前失败并被 planning fallback 掩盖。测试必须制造两种 sidecar-first 窗口、调用恢复扫描、按网络接收时间证明 `acceptedAtMs >= retryAtMs`,并比较失败/恢复 HTTP body 的 SHA-256 和字节一致性;失败输出不得打印正文片段。Provider 成功返回到压缩 sidecar 或 finalization journal `prepared` 之间仍不是 durable 提交点,进程退出可能重发 Provider;finalization journal 清理后才标记 stream committed 的窗口也可能留下 assistant 已落盘但 stream 仍为 ready。在新增成功响应 journal 与可恢复 stream commit 前不得宣称成功请求 exactly-once 或 stream 终态事务。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/provider_retry.rs`、`agent.rs`、`runner.rs`、`tests.rs`、`docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`。
## Provider 成功不等于已交接,stream ready 也不等于 finalization 已完成
- 现象:Provider 已返回完整 final-reply,Runner 在 finalization `prepared` 前退出后却再次请求;或 assistant/completed 已唯一落盘,response stream 长期停在 `ready / streaming`。更危险的修复是看到 handoff 与 retry 同时存在便择一删除,或因为另一个 Agent 已推进全局 project revision,就把当前固定 run 的 stream 当成不可见缓存并静默跳过提交。
- 原因:Provider 网络 future、成功 handoff、compaction/finalization journal 和 response stream 是连续但不同的 durable owner。只有内存中的成功响应、`started` lifecycle、流式半句或 `ready` 展示缓存都不能证明下一 owner 已接管;面向 UI 的 stream 可见性还会读取当前全局 revision,不适合作为 finalization 的提交判据。
- 正确顺序:成功响应先规范化并写入 `game-creator-provider-handoff.v1`,原子落盘并回读一致后,才用 handoff 保存的真实 requestId 补 `completed` lifecycle。恢复先修复该真实 requestId,再零网络回放。压缩结果先持久化并回读 compaction sidecar 后再清 handoff;final-reply 至少先进入 finalization `prepared`,journal 持续负责唯一 assistant、Runtime/Goal completed 和 stream committed,直到 committed 写入后的身份、状态、正文回读全部成功才清理。
- 冲突处理:handoff/retry 只有完整 identity、attempt 和 slot 一致才可把 retry 当作已被成功结果覆盖;冲突时必须零网络进入 reconciliation,并保留两份 sidecar、`.previous` 和真实 requestId 证据。stream 身份或正文与 journal 冲突时也保留 journal;禁止覆盖冲突 stream、删除 journal、补造 requestId 或靠重复 Provider 调用“刷新”现场。Runner 对存在、备份或损坏 handoff 的 root 都必须报告 busy,不能为 idle shutdown 自动删证据。
- stream 恢复:finalization 使用 journal v4 固定的 Agent/task/Session/run/request slot/steer cursor/response revision 和正文直接读取提交面。缺失或 `streaming` 可由 journal 重建为规范 `ready` 再提交;已 committed 且正文一致可幂等清理。即使全局 project revision 已被其它 Agent 推进,也不能跳过这个既定 run 的 stream;写入、回读、固定身份或正文任一不一致,都保持 journal 和可恢复 finalization。
- 排障与验证:先核对 handoff 的 `providerRequestId / requestSlot / attempt` 与 Agent DB lifecycle,再看 retry/handoff/finalization/response-stream sidecar,最后才看 Runtime/UI 投影。用关闭 mock Provider 后恢复证明 handoff 回放零网络;分别覆盖 compaction 与 final-reply 消费窗口、handoff/retry 冲突、stream 缺失/streaming、commit 写失败、committed 后清理前退出、全局 revision 漂移和 Runner busy。日志与断言只公开指纹、字符数、状态和差异字段,不能打印 handoff 正文、请求体、凭据、URL 或绝对路径。
- 保留边界:Runner 若在 Provider 成功后、handoff 原子提交并回读前被硬杀,本地仍只有结果未知的 `started`,不能安全补发或宣称 exactly-once。handoff 只覆盖无 tool call 的 `context-compaction / final-reply-context-compaction / final-reply`;`tool-plan` 及其 function arguments 不在内,真实外部 Provider 的 final-reply Runner 强杀门禁也需单独完成。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/provider_handoff.rs`、`provider_retry.rs`、`agent.rs`、`project.rs`、`runner.rs`、`tests.rs`、`docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`。