feat(runtime): 引入验收事实与决策快照,收敛 verification continue 循环#540
feat(runtime): 引入验收事实与决策快照,收敛 verification continue 循环#540Cai-Tang-www wants to merge 53 commits into1024XEngineer:mainfrom
Conversation
…s and TUI payloads
… snapshot summary
…uplicate read loops from resetting progress
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Cai-Tang-www <106404101+Cai-Tang-www@users.noreply.github.com>
test(gateway): 补充 runtime snapshot/todo 分支覆盖
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Cai-Tang-www <106404101+Cai-Tang-www@users.noreply.github.com>
test(cli): improve gateway runtime bridge coverage
…runtime events Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Cai-Tang-www <106404101+Cai-Tang-www@users.noreply.github.com>
test: expand coverage for runtime decider/facts and tui todo events
…xt actions Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: Cai-Tang-www <106404101+Cai-Tang-www@users.noreply.github.com>
fix(runtime): stabilize decider task kind and next actions
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
| hasVerification := len(allFacts.Verification.Passed) > 0 | ||
| hasSubAgent := len(allFacts.SubAgents.Started) > 0 || len(allFacts.SubAgents.Completed) > 0 || len(allFacts.SubAgents.Failed) > 0 | ||
| hasTodo := todos.Summary.Total > 0 || len(allFacts.Todos.CreatedIDs) > 0 || len(allFacts.Todos.CompletedIDs) > 0 || len(allFacts.Todos.FailedIDs) > 0 | ||
| hasRead := len(allFacts.Files.Exists) > 0 || len(allFacts.Commands.Executed) > 0 |
There was a problem hiding this comment.
这里将 len(allFacts.Files.ContentMatch) > 0 计入 hasWrite,会把 read/verify 事实当成写入证据。纯只读或仅校验场景会被误判为 workspace_write,后续可能错误要求 file_written 并进入 continue。建议 hasWrite 仅绑定真实写入事实(如 Files.Written 或明确 write 工具事实)。
| case protocol.ListSessionTodosParams: | ||
| return strings.TrimSpace(typed.SessionID) | ||
| case *protocol.ListSessionTodosParams: | ||
| if typed == nil { |
There was a problem hiding this comment.
这个函数新增了 ListSessionTodosParams 分支,但未补 protocol.GetRuntimeSnapshotParams(及其指针)分支。runtime.snapshot.get 的 payload 级 session_id 提取因此不完整,和同类新接口不一致。建议在此处补齐对应分支,避免依赖 payload 提取的路由/指标出现偏差。
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
问题
本 PR 引入一条结构化的 Runtime 验收事实与决策快照链路,用于收敛 final acceptance / verification continue 循环。
最初触发问题是
todo_write回归:Todo 状态更新被误归类为workspace_write,导致即使用户任务已经完成,FinalDecider 仍持续要求verification_passed(workspace_write),进而触发多轮 continue / intercept。在修复过程中,同一类根因也暴露在相邻链路中:
unverified_write的 continue action 可能带有不可执行占位参数,例如<expected-token>;unverified_write;因此,本 PR 不再把问题视为单一
todo_writebug,而是作为一条 Runtime 验收闭环问题来处理。Problem
Current Behavior
修改前,Runtime final acceptance 在以下场景中容易进入重复 continue / intercept:
todo_write状态事实和 workspace 文件写入事实没有明确分离;reason=unverified_write时可能生成不可执行的 next action,例如expect_contains=["<expected-token>"];continue之后,模型可能继续输出无工具调用的“已完成”文本;Expected Behavior
Runtime 应该只基于客观结构化事实做最终验收:
missing_facts和required_next_actions;noop_write,不应重新打开unverified_write;incomplete,而不是无限循环。Why this PR touches multiple modules
这份 PR 会涉及多个模块,是因为问题本身发生在一条端到端链路上:
如果只修其中一层,会出现“局部正确、整体仍然循环”的情况:
只修 tool,Runtime 不消费 facts,仍然不能收敛;
只修 Runtime,TUI 仍然把被拦截的文本展示成成功;
只修 TUI,Runtime 仍然无法判断哪些事实可信;
只修提示词,模型仍然可能无法一次性产出 verification facts。
因此,本 PR 将验收闭环相关的最小必要链路放在一起处理。虽然范围较大,但目标仍然聚焦在:让 Runtime final acceptance 能够基于结构化事实收敛或停止。
##Changes
增加结构化 Runtime facts,用于表达:
Todo facts;
file write/read/glob facts;
verification facts;
subagent lifecycle facts;
tool error facts。
增加 FinalDecider 相关逻辑,用于判断:
task kind;
Todo 是否收敛;
workspace write 是否完成验证;
subagent 是否完成;
被拦截 final 后是否产生新事实。
continue / incomplete / failed / accepted 决策中增加结构化信息:
status;
stop_reason;
missing_facts;
required_next_actions;
user/internal summary。
避免无工具调用的 assistant final 反复重置 progress,导致循环保活。
filesystem_write_file
支持 verify_after_write;
写入后可直接 read-back 验证;
内容一致时产出 verification_passed;
相同内容重复写入识别为 noop_write,不重新打开 unverified_write。
filesystem_read_file
支持 expect_contains;
用于产出内容匹配类 verification facts。
filesystem_glob
支持 expect_min_matches;
用于产出文件存在类 verification facts。
Todo 状态更新产出结构化 facts:
todo_created;
todo_updated;
todo_completed;
todo_failed。
增加 Todo snapshot metadata,供 Runtime/TUI 消费。
优化 pending todo 的完成路径,允许工具层安全展开:
pending -> in_progress -> completed
Todo 冲突、revision conflict、状态失败时产出 conflict/error fact,而不是伪装成正常 updated。
增加 Runtime Decision 展示。
当 assistant final 被 Runtime 判定为 continue / incomplete 时:
不再把该文本展示成正常完成回复;
改为展示 [Runtime Decision] 结构块。
TUI 可消费 Todo snapshot / Runtime facts / Decision 事件,展示当前验收状态和缺失事实。
支持展示 Runtime 为什么拒绝 final,而不是只看到模型说“已完成”。
增加 Todo / Runtime Snapshot 查询路径,支持:
TUI 初始化;
Gateway 模式;
未来桌面端断线重连后恢复状态。
保持 Runtime event payload 中的结构化字段,避免外层只看到泛化的 progress 事件。
增加 task_type 相关契约:
review;
edit;
verify。
明确 prompt / content 是任务指令,不是文件路径。
收紧 inline subagent 的 allowed tools / allowed paths 处理。
增加 subagent facts,供 Runtime/TUI 观测。
当前 Runtime flow 中,before_completion_decision 保持观察型语义,不作为最终终态裁决层。
修复 hook timeout 后 executor slot 释放问题。
Non-Goals
本 PR 不处理:
不重写完整 acceptance 架构;
不把 hook 作为最终控制面;
不放宽 tool permission / capability 模型;
不实现自动 Todo executor 调度;
不保证所有未来 task kind 都有完整验收 profile;
不重写整个 TUI;
不将所有外部客户端强制迁移到新 Snapshot 协议。
本 PR 的目标是收敛当前 Runtime 验收循环,并建立可继续演进的 facts / decision / snapshot 基础。
Acceptance Criteria
Given 一个 Todo-only 任务,当 todo_write 创建或完成 Todo 状态时,FinalDecider 不再要求 verification_passed(workspace_write)。
Given 一个 workspace file write 使用 verify_after_write=true,当写入后 read-back 内容一致时,tool 产出 VerificationPerformed=true 和 VerificationPassed=true。
Given 对同一路径重复写入相同内容,当内容未变化时,Runtime 将其识别为 noop_write,不重新打开 unverified_write。
Given reason=unverified_write 且期望内容已知,当 Runtime 返回 continue 时,required_next_actions 包含可执行的 filesystem_read_file(path, expect_contains, verification_scope) 参数。
Given reason=unverified_write 但期望内容未知,当 Runtime 返回 continue 时,required_next_actions 退化为 filesystem_glob(expect_min_matches=1),不得生成 等占位符。
Given acceptance continue 后,下一轮 assistant 没有 tool call 且没有新 facts,Runtime 会计入 no-progress,并最终进入 incomplete。
Given Runtime 将 assistant final 判定为 continue 或 incomplete,TUI 显示 [Runtime Decision],而不是将被拒绝的 assistant 文本展示成正常最终回复。
Given Todo 或 Runtime snapshot 事件发出,TUI 能从事件 payload 更新 Todo/Decision 状态。
当新 verification 参数未传入时,既有 filesystem read/write/glob 行为保持兼容。
Test Plan
已运行:
go test ./internal/runtime -count=1
go test ./internal/tui/core/app ./internal/tui/services
本 PR 覆盖/新增的测试方向:
Runtime final acceptance;
no-progress after intercepted final;
Runtime facts collector;
FinalDecider task-kind decision;
filesystem verification facts;
Todo state facts and metadata;
TUI Runtime Decision rendering;
Gateway runtime event payload decoding;
SubAgent task type contracts;
Hook timeout slot release。
全仓回归:
go test ./...
说明:全仓测试中曾遇到 Windows TempDir RemoveAll 偶发清理失败。相关 Runtime 包二次运行通过,当前看起来与本 PR 的 acceptance 逻辑无关。
Risks / Compatibility
Risks
Final acceptance 变严格后,部分旧提示词可能更早进入 continue 或 incomplete。
Runtime event payload 扩展后,外部消费者需要忽略未知字段。
PR 范围较大,review 成本较高。
Compatibility
新 verification 参数为可选参数;
未使用新参数时,原 filesystem 工具行为应保持兼容;
Runtime 新事件应尽量 additive,不删除旧事件;
TUI/Gateway 对未知字段应容忍。
Rollback Strategy
如果需要回滚,可以按层回滚:
TUI 展示变更可以单独回滚,不影响 Runtime facts;
Gateway snapshot API 可以单独回滚;
filesystem verification 参数可以通过不传参保持旧行为;
FinalDecider 接入可回退到旧 acceptance 路径;
SubAgent task_type 和 Hooks 修复相对独立,可单独回滚。
Reviewer Notes
本 PR 较大,建议按以下顺序 review:
internal/tools/filesystem/:验证事实与 no-op write;
internal/tools/todo/:Todo facts / snapshot / transition;
internal/runtime/facts/* 和 internal/runtime/decider/*;
internal/runtime/final_acceptance.go / runtime 主链路接入;
TUI / Gateway 的 snapshot 与 decision 展示;
SubAgent task type;
Hooks timeout / observe-only 兼容修复。
重点 review 目标不是 UI 细节,而是:
Runtime 是否只基于客观 facts 接受 final,并且在缺少 facts 时能给出可执行 next action,最终能 accepted / failed / incomplete,而不是无限 continue。
为什么没有拆成多个 PR?
这次问题本质是一条端到端验收链路: