完善通用开发 Agent Runtime V1.1

新增仓库上下文指纹复核与 durable action 漂移保护
拆分 App CLI 与独立 Runner 的投递执行边界并补齐恢复诊断
加入桌面和移动端浏览器验证及跨源网络阻断
实现隔离子 Agent 私有记忆与终止状态传播
补齐 Provider 协议确认副作用重放与 join 真实端到端验证
同步共享契约实施计划决策记录与开发流程文档
This commit is contained in:
AIGameCreator App
2026-07-12 20:58:42 +08:00
parent 028e6b872d
commit 5e627a4677
27 changed files with 17694 additions and 531 deletions
@@ -0,0 +1,250 @@
# AI 游戏创作 Agent Runtime V1.1 技术方案
更新时间:`2026-07-12`
## 目标
在不引入第二套任务系统、不开放任意 shell、不复制现有 Runtime 的前提下,优先补齐五项通用开发能力:
1. 仓库启动上下文与代码理解。
2. 脱离 WebView / Tauri UI 生命周期的独立持久 Runner。
3. 面向当前本地项目预览的真实浏览器验证。
4. 动态创建、隔离运行、并行执行并统一回收结果的子 Agent。
5. 使用真实 Provider 覆盖计划、工具、修改、确认、验证、持久化和重启恢复的自动验收。
本方案是现有 [`【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`](./【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) 的 Runtime V1.1 扩展,不建立平行 App、平行队列或平行持久化真相。
## 不在本轮
- 任意 shell、PTY、远程命令执行和通用进程管理。
- 完整 Git 分支、提交、合并和 worktree 工具。
- 云端 Runner、跨机器任务迁移或无人值守开机自启。
- RAG、CodeGraph、tree-sitter 或语言服务器作为发布依赖。
- 允许 Agent 访问任意网址、执行任意 JavaScript 或复用用户浏览器 Profile。
- 用动态子 Agent 绕过项目权限、项目写锁、revision 或验证门禁。
## 总体结构
```text
WebView / CLI
|
| Tauri command + RunnerClient
v
AppData runner endpoint (protocol + port + private token)
|
| 127.0.0.1 length-prefixed JSON
v
同一发布二进制 --agent-runner
|
+-- .agent/runtime 任务、恢复、确认、终态账本
+-- repository startup context
+-- preview.validate / Chrome CDP
+-- isolated child-agent lanes and join receipts
```
`.agent/runtime/**` 继续是任务执行事实源。Tauri command 负责用户授权、精确确认和 UI 桥接;Runner 是 LLM、工具循环、队列 drain、恢复和浏览器验证的唯一执行者。事件只作为刷新提示,UI 断线重连后必须重新读取完整 Runtime snapshot。
## 1. 仓库启动上下文
### 契约
新增 `RepositoryStartupContext`,每个 run 在首次 planning 前确定性装配,恢复时按相同规则重建。正文不混入普通 observation,也不被 6 轮压缩窗口删除;context bundle 只保存 schema、来源清单和 fingerprint。
启动上下文最多包含:
- 有界顶层目录摘要、文件/目录数量和是否截断。
- `package.json``Cargo.toml``pyproject.toml``go.mod` 等 manifest 摘要。
- 可验证脚本名和原始命令摘要;执行仍必须走 `project.verify`
- 根目录及嵌套目录中的 `AGENTS.md` 路径和有界正文,按根到具体目录叠加。
-`CONTEXT.md`、README 的有界背景摘要和项目记忆来源列表。
- 固定安全 Git 摘要:是否为仓库、当前分支、tracked dirty 数;不开放任意 Git 参数。
- 常见入口文件候选和按扩展名聚合的语言分布。
任意源码正文、对话、资产、私有记忆和黑板正文仍必须通过已有工具按需读取。仓库文本一律标记为不可信项目输入,只能约束项目做法,不能提升工具权限、覆盖 Runtime 系统规则或自动批准动作。
### 预算与安全
- 最多扫描 10,000 个目录项、2,000 个候选文件、深度 12。
- 跳过符号链接、`.git`、整个 `.agent` 控制面、依赖、构建、缓存和敏感配置目录;任务图、会话、记忆、checkpoint 和 Runtime 证据只能通过专用工具读取,不能参与仓库指纹。
- 单规范文件最多 24 KiB,全部规范正文最多 64 KiBprompt 渲染最多 20 KiB。
- 不读取 `.env*`、运行时配置、认证文件、Cookie、Token 或数据库 dump。
- 每个 durable 工具动作在真正执行前都要重建并复核 repository fingerprint;发现适用规范或启动上下文漂移后,旧动作必须落为 `blocked` observation,跳过本轮剩余动作并在同一 run 下一轮 planning 重新确认。创建 checkpoint、写 Runtime 日志等 `.agent` 控制面变化不得制造伪漂移。
- 项目索引、checkpoint、diff 和 restore 使用同一敏感路径排除规则,额外排除私钥、数据库及 dump 文件;checkpoint manifest 中每个文件路径必须是可移植的规范相对路径,拒绝绝对路径、`..`、反斜杠、盘符 / UNC / ADS 别名、控制字符、Windows 非法字符、尾随点或空格、保留设备名和符号链接边界。manifest 路径按 Windows 大小写不敏感键去重,禁止 `State.txt``state.txt` 同时出现。通用文件工具不能读写 `.agent/checkpoints/**`restore 不覆盖或删除 `.env*`、运行配置、认证文件、私钥、数据库、dump、`.agent`、VCS、依赖和构建目录。
`project.index` 升级为显式刷新和查看完整启动摘要的工具;自动启动上下文使用同一构建核心,不建立第二份索引。
## 2. 独立持久 Runner
### 进程模式
同一 Tauri 发布二进制新增:
```text
--agent-runner --config-dir <AppData 目录>
```
Runner 从显式 AppData 目录读取 `game-creator.config.json`API Key 不进入 IPC payload、项目目录、状态文件、日志或验收报告。Unix 使用新 session,Windows 使用新进程组和无窗口标志,使 Runner 不依附 WebView 生命周期。
### 本地协议
- Runner 只监听随机 `127.0.0.1` 端口。
- AppData endpoint 文件权限收紧为当前用户,保存 `protocolVersion / pid / bootId / port / token / heartbeatAt`
- 请求使用 `u32` 长度前缀加 UTF-8 JSON,单帧最多 1 MiB。
- 每个请求必须携带私有 token、`requestId` 和协议版本。
- 首版方法:`runner.ping``runner.status``runtime.wake_pending``runtime.resume``runtime.continue_action``runner.shutdown_if_idle`
- 只读失败可重试;写请求先按 requestId/runId 重读事实源,禁止网络重试制造重复任务。
### 执行所有权
- App 写入精确用户输入、任务或确认账本后只通知 Runner;不再在 App 进程中 claim 后台任务。
- Runner 复用现有恢复顺序:finalization -> pending action -> recoverable task -> delegate/join receipt reconciliation。
- 同 Agent 继续持有 per-Agent OS 锁,不同 Agent/子 Agent lane 可并行。
- Runner 崩溃后,现有 `executing -> needs-reconciliation`、finalization 幂等和 cancel tombstone 语义保持不变。
- 整机重启后不自动执行;App/CLI 下次启动并经过 `agent.resume` 策略后恢复。
### 跨进程前置修复
- `.agent/agent.db`、conversation、events、tasks、activity、output 和 Session catalog 的读改写临界区升级为进程内 Mutex + OS 文件锁。
- App 配置写入改为同目录临时文件 + 原子替换,Runner 只读取完整版本。
- Runner endpoint、项目 execution-owner 和协议主版本共同阻止 split-brain。
- 所有会写 Runtime 的 CLI 命令必须显式传入项目外 AppData,不能回退到 CLI 进程内执行;`--runner-status` 只读已有 endpoint,不得为了查询状态启动 Runner。
- AppData 在 Unix 上必须由当前用户持有且权限为 `0700`endpoint/lock 为 `0600`。Windows 下 AppData 目录、Runner endpoint、AppData Runner lock 和 execution-owner 诊断文件使用禁止继承的 protected DACL,只允许当前用户 SID;目录 ACE 带对象 / 容器继承,文件 ACE 不带继承。写入口可以收紧后复核,只读状态入口只能校验,不能创建、收紧或修复。
- Runner lock、Agent lane lock 和项目 execution-owner 均拒绝符号链接、硬链接或 Windows reparse pointUnix 通过 `openat` 逐级无跟随打开,Windows 持有逐级目录句柄,取得稳定句柄和 OS 锁后才允许写诊断信息。
- 项目 execution-owner 是项目级跨进程系统锁,不按 AppData 分叉;不同 AppData 启动的 Runner 不能同时接管同一项目。`.agent/runtime/execution-owner.lock` 只承载句柄级排他所有权,`execution-owner.json` 是可恢复诊断投影:诊断缺失、截断或损坏不能阻止合法锁持有者恢复,也不能作为接管依据;新诊断经临时文件写入、同步、原子替换和回读全等校验,仅在旧完整记录可信时写入 `recoveredFromBootId`
## 3. 浏览器验证
### 工具
新增 `preview.validate`,不新增通用 `browser.open`
输入只允许:
```json
{
"viewports": ["desktop", "mobile"],
"expectedText": ["可选可见文本"],
"settleMs": 800,
"failOnConsoleError": true
}
```
工具不接受 URL、脚本、请求头、Cookie 或浏览器 Profile。Runtime 只验证当前项目 `PreviewRegistry` 中的精确 loopback URL;独立 Runner 未持有持久预览时,可启动同一项目的临时预览并在验证后关闭。
### 证据
通过系统 Chrome/Chromium/Edge 的 CDP 采集:
- `document.readyState`、title、可见文本摘要和 DOM 字符数。
- console error/warn、未捕获异常和失败网络请求。
- canvas 尺寸、可见面积和非空像素抽样;每个视口至少存在一个可见 canvas,且抽样必须同时包含非透明像素和至少两种 RGBA 状态,全透明或均匀纯色画布不能通过。
- `desktop 1280x720``mobile 390x844` PNG 截图。
`viewports` 必须且只能同时包含 `desktop``mobile`;单视口、重复视口、空 body、无 canvas 或空白 canvas 都是失败,不允许用成功摘要掩盖缺失证据。
证据写入 `.agent/runtime/browser-validations/<agentId>/<runId>/<revision>/`。observation 和 LLM 只接收脱敏计数、诊断摘要和项目内相对路径,不接收截图二进制或完整 DOM。
### 安全
- 只从操作系统固定安装位置发现 Chrome / Chromium / Edge,不搜索 `PATH`。仅允许精确 `http://127.0.0.1:<port>` 预览 origin;导航前开启覆盖全部资源的 CDP Fetch request-stage 拦截,网络只放行同 origin HTTP 和同 host / port WebSocket。其他端口、HTTP(S)、WSS、跨 origin redirect target 和 WebSocket 必须在连接或握手前阻断并记为致命策略失败;浏览器默认走不可达代理,只为精确 HTTP / WS origin 配置 bypass。
- 使用全新临时 Profile;不添加 `--no-sandbox`
- 验证前后重读 project revision 和预览身份,任一漂移都使结果失效。
- `preview.validate` 是独立试玩证据,不替代修改后的 `project.verify``game.static_smoke` 完成门禁。
## 4. 动态隔离子 Agent
### 工具契约
保留 `agent.delegate` 的静态规范 Agent 语义,新增 `agent.spawn_isolated`
```json
{
"children": [
{
"templateAgentId": "code-prototype",
"task": "完成一个边界清晰的子任务",
"acceptanceCriteria": ["可验证条件"],
"expectedArtifacts": ["game/feature-a/**"],
"writeScopes": ["game/feature-a/**"]
}
],
"joinMode": "all"
}
```
模型不能指定执行实例 ID。Runtime 从父 actionId 稳定派生:
- `delegationGroupId = sha256(parentActionId)`
- `delegationId = sha256(groupId + childIndex)`
- `instanceId = child-<delegationId 前缀>`
- 每个实例使用独立 session、run、queue、state、event、lock 和私有临时记忆。
### 隔离与限制
- 角色 prompt、LLM 配置和 Agent 策略继承 `templateAgentId`;执行和持久化 lane 使用 `instanceId`
- 单次最多 3 个并行实例,最大深度 1。
- sibling `writeScopes` 不得重叠;所有真实写入仍通过项目级写锁、revision 和 verification gate。
- 子实例默认拒绝 `agent.spawn_isolated``project.restore``agent.schedule_ready`
- 子实例的 `memory.read/write(scope=agent)` 只访问 `.agent/runtime/isolated-agents/memory/<instanceId>.json` 私有临时 lane;不能指定 sibling 或静态模板 Agent,也不能写 `project / session / blackboard` 共享记忆。普通静态 Agent 的私有记忆语义保持不变。
- 父任务进入 `failed / budget-exhausted / cancelled` 时,向所有非终态子实例写取消 tombstone;重复收束和恢复必须幂等,已开始或完成的 join continuation 不得被重新认领。
- 动态实例不写 manifest,不出现在普通用户 Agent 列表;开发 Runtime 状态页可读取其状态。
### Join 与结构化结果
每个 child 终态生成结构化结果:
```text
delegationId, instanceId, templateAgentId, runId, status,
summary, artifacts[path, sha256], evidence[], verifiedRevision, error
```
同一 group 全部终态后,Runtime 使用 `.agent/runtime/isolated-agents/join-deliveries/<groupId>.json` 持久记录交付状态,并且只允许固定 `joinRunId` 入队一次。父 run 仍持有自身 lane 时,只能通过当前已持久化 `agent.run_status` 工具动作的 `actionId` 认领 ready all-join;交付记录保存 `claimedByActionId`,同一 action 崩溃重试可幂等重读,同一 run 的其他 action 不再看到该 join。认领后取消尚未执行的固定 continuationcontinuation 已开始时拒绝认领。父 run 未认领时,唯一 continuation 才在 lane 释放后执行,`dispatched -> claimed-by-parent / suppressed` 单向不可逆。恢复、并发 child 终态和重复状态查询都不能重新开放交付、生成 `-dup-*` join run 或重复调用父 LLM。
## 5. 真实 Provider 验收
新增 opt-in 命令:
```bash
npm run ai-game-creator-shell:agent-runtime:real-e2e -- --config-dir <AppData> --suite full
```
验收在系统临时目录创建带 disposable sentinel 的项目,配置和凭据始终留在仓库外。通过条件只采信持久化事实,不采信模型自述。
完整套件至少证明:
1. 首轮拿到 repository startup context,且没有泄露敏感文件。
2. 真实 Provider 返回合法工具计划,协议记录为 `native_function` 或受支持的 `text_json` 回退。
3. 执行 checkpoint、读取、精确 patch/write,并在确认策略下停到 `waiting-for-confirmation`
4. 精确确认后由独立 Runner 继续,App/发起 CLI 退出不影响任务。
5. 修改后通过 `project.verify`,再通过 `preview.validate` 生成桌面和移动证据。
6. 两个相同模板实例和一个不同模板实例真实并行,最后只产生一个 join continuation。
7. Runner 强制终止后按原 run/session 恢复,不重复工具、消息、receipt 或最终 assistant。
8. task/event/agent.db、revision、verification、finalization、conversation 和浏览器报告一致。
9. 对项目、stdout、报告和 Runtime 元数据执行已加载密钥扫描,`secretLeakCount=0`
`full` 套件缺少 LLM、受支持浏览器或 External Editor API 配置时必须报告 `BLOCKED`,不能以 skip 计为通过。默认 CI 继续运行本地假 Provider smoke;真实套件不进入无凭据 CI。
### 2026-07-12 真实验收结果
使用发布 AppData 中已配置的真实 `gpt-5.5` 运行 `llm-runtime` 套件,结果为 `PASS`:Runner 强制终止后恢复同一 run/session;共形成 85 条 task、143 条 event、127 条 Agent DB 审计、11 条合法工具协议记录和 9 次结构化成功工具执行;4 个确认动作的 waiting / required / approved / ok 生命周期各自唯一,5 个副作用动作的新 actionId 重放为 0。项目 revision 为 1,项目验证与 1 组桌面/移动浏览器验证通过;3 个隔离实例来自 2 个模板且只形成 1 个 joincompleted 投影、最终 assistant 及其 conversation audit 均仅 1 条,重复 action/message/receipt 均为 0;已加载密钥和项目诱饵泄露均为 0;保留项目核对完成后按 disposable sentinel 清理。
同一 AppData 的 `full` 套件返回 `BLOCKED(editorApi)`,原因是未配置 External Editor API。该结果属于正确的外部前置条件阻断,不记为通过,也不复用其他环境凭据。
### 安全与负向验收
- repository fingerprint 测试覆盖自动 `file.write / file.patch / file.delete / project.restore` 在 planning 后规范漂移时全部阻断,并覆盖 `.agent` checkpoint / 日志 / Runtime 控制面变化不产生伪漂移。
- 隔离测试覆盖两个同模板 instance 的私有记忆互不可见、共享记忆写入拒绝、父任务三类终态取消 children、重复 reconcile 不重开 join,以及已开始 continuation 不可被父 run 迟到认领。
- 浏览器纯逻辑测试覆盖单视口、重复视口、无 canvas、透明 canvas 和均匀纯色 canvas 失败;显式真实 Chrome 测试同时证明桌面/移动截图有效,跨 origin HTTP redirect 与 WebSocket 目标在发送前零连接。
- Runner 测试覆盖只读状态无副作用、锁链接 / 硬链接拒绝、跨 AppData 唯一 owner,以及缺失、截断或损坏 owner 诊断在 OS 锁后原子恢复。
## 验收命令
- `npm run ai-game-creator-shell:typecheck`
- `npm run test -- apps/ai-game-creator-shell/tests`
- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml`
- `cargo test -p platform-agent --manifest-path server-rs/Cargo.toml game_creation`
- `cargo test -p shared-contracts --manifest-path server-rs/Cargo.toml game_creation_app`
- `npm run ai-game-creator-shell:agent-run:smoke`
- `npm run ai-game-creator-shell:agent-runtime:real-e2e -- --config-dir <AppData> --suite full`
- `npm run check:encoding`
- `git diff --check`
@@ -16,6 +16,12 @@
## Runtime 边界
2026-07-12 起,通用开发能力的 Runtime V1.1 增量以 [`【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`](./【技术方案】AI游戏创作Agent%20Runtime%20V1.1-2026-07-12.md) 为编码级事实源。它补充仓库启动上下文、同一发布二进制独立 Runner、受限本地预览浏览器验证、动态隔离子 Agent 和真实 Provider 全链路验收;本文件中“进程内 tokio task”“首轮不预加载项目内容”和“不创建动态执行实例”的旧口径由 V1.1 明确替代,未涉及能力继续沿用本文件。
2026-07-12 真实验收:发布 AppData 中的真实 Provider 已通过强化后的 `llm-runtime` 套件,覆盖 Runner 强杀恢复、仓库上下文、checkpoint/精确修改/四段确认生命周期、项目验证、桌面与移动非空画布证据、3 个隔离实例并行和唯一 all-join;工具协议、副作用判重、终态投影、assistant audit、消息、回执和密钥泄露均以结构化落盘事实验收。`full` 套件因当前 AppData 未配置 External Editor API 正确返回 `BLOCKED(editorApi)`,不得记为通过。
以下能力清单保留 Runtime V1 的演进记录;其中“App 进程内 tokio task”“跨进程同项目写入不作为支持目标”和“恢复到当前 App 进程”的旧描述均已由 V1.1 替代。当前边界是 App / CLI 只落账并唤醒同一发布二进制的独立 Runnerappend-only JSONL 使用进程内锁加 OS 文件锁,恢复继续由 Runner 接管同一 run / session。
Agent Runtime 负责:
- 2026-07-12 安全边界补充:`project.verify` 的 script 最多 160 个字符,固定使用系统 script shell,并在解析和执行前拒绝项目级 `.npmrc` 改写 npm 语义。Runtime context bundle 绑定 `projectId / agentId / taskId / sessionId / runId / source / task`,结尾换行计入 64 KiB 上限;恢复时同时校验 `nextLoopIndex`、context window、当前窗口已完成轮数、观察指纹、计划、observation 数量,以及 `contextStalled` 只能位于非零上下文窗口边界。bundle 通过项目内无符号链接路径原子写入,并从同一文件句柄最多读取 64 KiB;项目路径和常见 `sk- / GitHub / npm / AWS / JWT` 凭据统一脱敏。工具 observation 进入 context checkpoint 后才删除 `observed-*` 动作账本,避免重启时旧 ledger 抢占有效 bundle。