完善通用开发 Agent Runtime V1.1
新增仓库上下文指纹复核与 durable action 漂移保护 拆分 App CLI 与独立 Runner 的投递执行边界并补齐恢复诊断 加入桌面和移动端浏览器验证及跨源网络阻断 实现隔离子 Agent 私有记忆与终止状态传播 补齐 Provider 协议确认副作用重放与 join 真实端到端验证 同步共享契约实施计划决策记录与开发流程文档
This commit is contained in:
@@ -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 KiB,prompt 渲染最多 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 point;Unix 通过 `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。认领后取消尚未执行的固定 continuation;continuation 已开始时拒绝认领。父 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 个 join;completed 投影、最终 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 只落账并唤醒同一发布二进制的独立 Runner,append-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。
|
||||
|
||||
Reference in New Issue
Block a user