技术方案:Game Agent Runtime 交互边界重构 #168
Reference in New Issue
Block a user
Delete Branch "codex/game-agent-runtime-interaction-design"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
关联 #167
变更内容
本 PR 重构 Game Agent Runtime 交互边界技术方案,并将原先集中在单篇长文档中的内容拆分为四份职责明确的文档:
方案的目标是将 GUI、CLI 和自动化测试统一为同一协议的 Consumer:
本 PR 不包含
文档权威关系
IC-*规则以此为准;迁移矩阵和证据附录不得覆盖或改写 Interaction Contract。
验证
已完成:
npm run check:encodinggit diff --checkIC-*定义与引用检查本 PR 只包含技术方案文档,不包含生产实现,也不代表 P0–P6 的实施验收已经完成。
先说结论:方向认同,身份/ledger/投影三层的收敛做得很扎实。下面只针对 V1 公开写协议的表达能力提两点,其余部分不评。
两点的共同性质是:它们不是实现细节,而是 §8「协议冻结输出」一旦生效后无法靠 Consumer fallback 或新增字段绕过的缺口(§1.3.2 已经明确禁止「忽略未知字段」式兼容)。所以放在冻结前提。
1.
submit_intent没有承载「入口意图」的通道§1.3.2 冻结的请求体是
{ meta, sessionId, message, runProfile },配合 §1.3 的「source由受信任 transport 固定映射,Consumer 不得自报任意 source」。问题在于 transport 是「Tauri GUI / CLI / 测试夹具」这一层,不是「用户点了哪个按钮」这一层。同一个 GUI 里的多个入口映射到同一个 source,于是:
两个请求逐字节相同。连
requestFingerprint都相同——§1.3.1 第 2 步规定指纹覆盖「完整业务 payload」但「transport 字段不进指纹」。后端没有任何确定性依据区分这两次调用。两个看起来可行的替代都不成立:
runProfile:它是执行档(standard/autonomous-game-build),表示「怎么执行」;入口意图表示「要做什么」。两者正交,合并会让同一字段承担两种语义,且 §1.3.2 限定runProfile只允许已注册的公开 profile 名称和版本。message推断:信息源本来是一次确定的按钮点击,从自由文本反推等于把确定信息降级成启发式。凡是需要「同一时刻最多一条某类 run」这种并发唯一性判定的场景,后端必须确定性地知道本次是不是该类启动,猜不出来。建议
给
SubmitIntentCommand增加一个业务字段(形态由本方案决定,intentKind只是举例):关键是「Consumer 可请求、后端可否决」,这样不破坏本方案原有的信任模型:
source。后端查表只是从transport → source变成(transport, intentKind) → source,映射权和否决权都还在后端。顺带一个正效果:
intentKind作为业务字段进入requestFingerprint,同requestId换 intent 会正确命中IDEMPOTENCY_KEY_REUSED,而不是静默走错分支。这不是个例
任何新增的用户入口都会撞同一堵墙——「从模板新建」「续做上一次的方案」「导入既有设计直接开建」。五命令冻结后若没有 intent 通道,以后每加一个入口,要么申请第六个命令,要么从自由文本里夹带。前者违反 §8 的冻结,后者违反 §1.1 的「Consumer 不得反向推导 Runtime 状态」的同一精神。
2.
ApproveCommand的二值 decision 表达不了「带意见退回重做」§1.3.2 冻结
ApproveCommand { meta, interaction, decision },ApprovalDecision = Approve | Reject,且 §1.3.2 明确「未列出的字段不属于 V1……未知字段、重复字段和错误字段类型统一返回INVALID_REQUEST,不得通过忽略未知字段实现兼容」。这意味着审批类交互在 V1 里只有二值。但「用户看到产物 → 提出具体修改意见 → 退回重做 → 再次审批」是审批场景的常见第三态,它和
Reject(终止)在业务语义上完全不同:前者继续同一条工作链,后者收束它。二值方案下只能:Reject兼作退回 —— 语义丢失,后端无法区分「不要了」和「改一下」;Reject再重新submit_intent—— 变成两次独立操作,中间状态无法保证原子,且丢掉了「这次修改针对的是哪一版产物」的绑定;answer—— 但 §1.4 明确「answer仅接受 UserInput,approve仅接受 ToolApproval/PolicyApproval;命令与 kind 不匹配返回INVALID_REQUEST」。建议
二选一即可,不需要两个都做:
ApprovalDecision扩成稳定三值枚举(approve | reject | requestChanges或等价命名),并允许requestChanges携带一个有界、可脱敏的意见正文字段;AgentRuntimePublicInteractionPresentation::PolicyApproval的allowed_decisions中允许声明第三值,由 presentation 侧驱动。无论哪种,正文字段都应纳入 §1.4 的 response fingerprint(「不能只散列自由文本」那条约束正好适用),并沿用 §1.4 已有的公开内容安全过滤。
以上两点都不是迁移工作量,而是协议表达能力:按 §1.3.2「不得通过忽略未知字段实现兼容」和 §8「任何实现若无法满足上述合同,必须先修改本技术方案并重新评审」,一旦冻结,补这两个缺口的门槛就从「改一版草案」变成「重新评审」。所以放在现在提。
方案重构与重新请求评审
已吸收此前评审提出的两项 V1 协议表达能力问题:
submit_intent现在显式携带intentKind,由 Consumer 陈述入口意图、Shell 在策略和权限边界内复核;approve现在支持requestChanges,并绑定有界 feedback、不可变目标和唯一 rework operation。同时,为避免单篇长文档同时承担说明、规范、迁移和证据四种职责,候选方案已整理为四份互相引用的文档:
IC-*规则;EG-*验收门禁。本轮还补齐了此前 P2 审查发现的协议闭环:
collaborationId、retry lineage 和 fallback replacement;当前 PR 仍然只包含设计文档,不包含生产实现。
P0 可以在方案评审后开始建立现状基线和 fixture;P1–P6 仍需按各阶段的
EG-*门禁实施和验收。请重新评审时重点确认:
Pull request closed