明确 /editor/agent 智能体作为工程改动编排器,通过结构化 patch、校验、snapshot、构建和预览反馈闭环落地。 补充左侧聊天、中间预览、右侧 IDE 的页面布局约束,右侧展开文件内容后隐藏聊天栏。 同步验收清单,明确 MVP 不做 diff 视图并覆盖 agent turn 和布局验收。
13 KiB
浏览器内 AI Web 工程沙箱预览方案
更新时间:2026-06-13
背景
/editor/agent 需要承载一个类似 IDE 的 AI Web 工程编辑器:用户在浏览器里看到文件树、代码编辑、AI 指令输入、构建日志和实时预览,AI 生成的是一个完整 Web 工程。这个工程的构建、依赖安装和运行必须与 Genarrative 主站、当前仓库源码目录、平台密钥和正式业务数据隔离。
第一版不追求“浏览器里完整云 IDE + 任意 npm + HMR + 后端服务”。目标是先跑通一个安全、可恢复、可验收的静态 SPA 预览闭环。
结论
MVP 采用四层结构:
平台编辑器壳 /editor/agent
-> api-server 控制面
-> 独立 web-project-runner worker
-> 独立 preview origin / preview gateway
第一版只支持固定 React / Vite / TypeScript 静态模板、虚拟文件系统、结构化 AI patch、平台固定构建命令、独立 runner 静态构建和独立域 iframe 预览。
MVP 明确不做:
- 终端 shell。
- 任意后端服务。
- 任意端口代理。
- HMR / 长驻 dev server。
- 任意 npm 依赖安装。
- AI 自定义 build shell script。
- diff 视图。
- 与主站同源的预览 iframe。
- 将 AI 生成工程写入当前 Genarrative 仓库源码目录。
分层职责
平台编辑器壳
入口路由固定为 /editor/agent。这一层只负责前端体验:
- 左侧聊天、中间预览、右侧 IDE 的水平三分布局。
- AI 指令输入、构建日志、当前项目版本和预览 iframe。
- 右侧 IDE 默认只显示文件树;展开后显示当前文件内容,并隐藏左侧聊天栏。
- 保存用户编辑和 AI patch。
- 订阅构建 job SSE 状态。
- 在构建成功后切换 iframe 的
previewUrl。 - 构建失败时保留上一版可用预览。
平台编辑器壳不得直接执行用户工程代码,不持有 runner 临时工作区路径,不把平台 access token、用户 cookie、SpacetimeDB 连接信息或 OSS 写权限暴露给预览页。
如果后续接入现有创作链路,入口仍应走 play_flow 主干和 shared-contracts DTO,不在前端壳或 app.rs 中新建平行业务流程。
智能体编排器
/editor/agent 的智能体不是普通聊天页,也不是直接生成整包代码的黑盒。它是“工程改动编排器”,负责把用户意图转成可审计、可校验、可回滚的 Web 工程 patch。
智能体职责:
- 理解用户自然语言目标,并结合当前 snapshot、文件树、选中文件和最近构建结果形成任务上下文。
- 输出结构化 patch plan,而不是直接写真实目录或执行 shell。
- 将 patch plan 提交给 api-server 校验,校验通过后生成新 snapshot。
- 创建 preview build job,并订阅 job SSE。
- 读取构建日志、错误摘要和 preview 状态,失败时继续生成修复 patch,成功时推动预览切换。
- 保留每轮 agent turn 的用户输入、上下文摘要、patch 摘要、校验结果、jobId 和最终状态,便于刷新恢复和审计。
智能体最小闭环:
用户在左侧聊天输入需求
-> 前端提交 agent turn
-> api-server 读取当前 snapshot 和允许暴露的上下文
-> LLM 返回结构化 patch plan
-> api-server 校验 patch plan
-> 校验通过后生成新 snapshot
-> 创建 preview build job
-> runner 构建
-> SSE 回传 queued / running / log / succeeded / failed
-> 成功时中间预览 iframe reload
-> 失败时智能体基于错误摘要进入下一轮修复
智能体输出只允许以下 patch 操作:
create_fileupdate_filedelete_filerename_filepackage_manifest_request
package_manifest_request 只是依赖请求,不是事实源。MVP 中 api-server 必须拒绝或忽略任意新增依赖、生命周期脚本、私有 registry、git: / file: / http: 依赖和 AI 自定义构建命令。
智能体不得:
- 直接写入当前 Genarrative 仓库源码目录。
- 直接访问 runner 临时工作区。
- 直接执行 shell、npm script 或任意构建命令。
- 直接拿平台 access token、用户 cookie、SpacetimeDB 连接、OSS 写权限或 LLM provider 密钥。
- 绕过 api-server 的路径、依赖、大小、敏感文件和 snapshot 校验。
页面布局
/editor/agent MVP 使用水平三分布局,不做 diff 视图:
┌───────────────┬──────────────────────────────┬────────────────┐
│ 左侧聊天 │ 中间预览 │ 右侧 IDE │
│ Agent 对话 │ sandbox iframe + 状态日志 │ 默认文件树 │
└───────────────┴──────────────────────────────┴────────────────┘
布局规则:
- 左侧聊天承载用户输入、智能体回复、构建状态摘要和失败修复建议。
- 中间预览始终是主工作区,展示当前 active preview iframe;构建失败时保留上一版 succeeded preview,并在聊天或日志区域展示失败摘要。
- 右侧 IDE 默认只显示文件树,突出当前工程结构,不默认展示代码内容。
- 用户展开右侧 IDE 后,右侧显示文件树和当前文件内容,左侧聊天栏隐藏,中间预览与右侧 IDE 形成双栏工作模式。
- 用户收起右侧文件内容后,恢复左侧聊天 + 中间预览 + 右侧文件树三栏。
- 文件内容查看用于理解和轻量编辑当前文件,不提供 diff 视图;版本变化通过 agent turn 摘要、snapshot 时间线和构建状态表达。
- 移动端优先保持预览和聊天可用,右侧 IDE 通过抽屉或分段入口进入;展开文件内容时同样隐藏聊天。
api-server 控制面
控制面只管理权限、快照、任务和状态,不执行 AI 工程代码:
- 鉴权和项目归属校验。
- 校验 AI patch 和用户编辑。
- 保存虚拟文件系统 snapshot。
- 创建 preview build job。
- 给 runner 发放最小任务能力。
- 输出构建日志和状态 SSE。
- 签发短期 preview URL。
- 将业务状态通过受控 procedure 或 BFF 更新到正式数据层。
api-server 不把 SpacetimeDB、OSS 写权限、LLM provider、支付、用户 cookie 或平台内部 token 传给 runner。runner 需要读取资产时,只拿只读短期签名 URL 或受控 fixture。
web-project-runner worker
新增独立进程角色,例如 web-project-runner。它可以复用外部生成 worker 的“任务表 + lease + controller + worker”模式,但不应把 Web 工程执行塞进 external_generation_job,避免语义污染。更合适的落点是新增 web_project_runtime_job 或抽象出通用 job 模块。
runner 只做执行面:
- 拉取指定 snapshot。
- 展开到独立临时工作区或容器。
- 使用平台白名单模板依赖。
- 执行平台固定构建命令。
- 采集构建日志、资源用量和结果。
- 上传静态 artifact。
runner 不能反向写平台业务表。业务状态回写必须经过 api-server / SpacetimeDB 的受控入口。
preview gateway 与独立预览域
预览页使用独立 origin,例如:
https://preview-<token>.sandbox.genarrative.world
或者统一域名加不可枚举 token path:
https://sandbox.genarrative.world/p/<previewToken>/
预览域不得与主站同源,不带平台 cookie,不共享主站 localStorage / sessionStorage。主站只通过 sandbox iframe 嵌入预览。
MVP 只服务静态构建产物。HMR、WebSocket 代理和长驻 dev server 后置到单独阶段评审。
MVP 流程
用户在 /editor/agent 输入需求或编辑文件
-> AI 返回结构化 patch
-> api-server 校验 patch
-> 生成 workspace snapshot
-> 前端 debounce 后创建 preview build job
-> runner claim job 并构建静态 dist
-> artifact 上传 artifact store
-> preview gateway 只读服务 artifact
-> 前端 SSE 收到 succeeded 后 iframe reload
失败链路:
构建失败 / 超时 / runner 崩溃
-> job failed / expired
-> 前端展示错误日志摘要
-> active preview 保持上一版 succeeded artifact
接口草案
接口归属分成项目控制面和运行时控制面。
POST /api/creation/web-project/projects
GET /api/creation/web-project/projects/{projectId}/snapshot
PATCH /api/creation/web-project/projects/{projectId}/files
POST /api/creation/web-project/projects/{projectId}/agent-turns
POST /api/runtime/web-project/projects/{projectId}/preview-builds
GET /api/runtime/web-project/preview-builds/{jobId}
GET /api/runtime/web-project/preview-builds/{jobId}/events
/events 复用现有 src/services/sseStream.ts 的 SSE 传输层口径。事件类型建议包括:
queuedrunninglogsucceededfailedcancelledexpiredstale
前端刷新恢复时,先读取项目 active snapshot 和 active preview,再按未终态 job 继续订阅 SSE。
agent-turns 的请求建议包含:
projectIdbaseSnapshotIdmessageselectedFilePathvisibleFilePathsrecentBuildJobId
agent-turns 的响应建议包含:
turnIdstatusassistantMessagepatchSummaryvalidationErrors[]snapshotIdbuildJobId
当 patch 校验失败时,不生成 snapshot,不创建 build job,只返回可展示的校验错误和智能体修正建议。
虚拟文件系统
平台内的“文件系统”是虚拟工作区,不是真实目录长期挂载。
snapshot manifest 建议包含:
projectIdsnapshotIdparentSnapshotIdownerUserIdtemplateKeyfiles[]createdAtcreatedBypatchSummary
文件项建议包含:
pathcontentDigestsizeBytesmediaTypeencodingexecutable=false
路径必须 fail-closed:
- 只允许相对路径。
- 拒绝绝对路径。
- 拒绝
..。 - 拒绝符号链接。
- 拒绝超深目录。
- 拒绝超大文件。
- 拒绝隐藏敏感文件名,例如
.env、.npmrc、.ssh、.git。 - MVP 只支持文本源码和少量静态资源。
文件内容小文本可以按 digest 存对象;大一点的 snapshot 可打包成 tar / zip artifact 放受控 artifact store。图片、音频等大资产继续走现有资产链路,不让 AI 工程随意内嵌大 Data URL。
依赖和构建
MVP 只支持平台预置模板依赖:
- React
- Vite
- TypeScript
- 平台已审核的 UI / 工具依赖子集
package.json 在 MVP 中不是事实源。AI 可以提出 manifest patch,但 api-server 会重写或忽略危险字段。构建命令由平台固定,例如:
npm ci --ignore-scripts
npm exec vite build
第一版应禁止:
preinstall/install/postinstallgit:/file:/http:依赖。- 私有 registry。
- native build。
- 二进制下载型包。
- AI 自定义 shell script。
后续若要开放依赖,必须进入“受控依赖白名单”和“隔离依赖解析服务”阶段,不混入 MVP。
预览状态机
draft snapshot
-> build queued
-> build running
-> build succeeded
-> build failed
-> build cancelled
-> build expired
-> build stale
状态规则:
- 新 snapshot 触发新 build 时,旧 running build 应取消或标记 stale。
- 只有当前 active snapshot 的
succeededjob 可以成为 active preview。 - failed / cancelled / expired / stale 不能覆盖 active preview。
- 回滚是切回历史 snapshot 并复用对应 immutable artifact,或重新构建该 snapshot。
- 不允许复用 runner 临时目录作为回滚来源。
后续阶段
Phase 0:文档和威胁模型
补齐技术方案、威胁模型和验收清单,明确 MVP 不可做能力、安全门禁、状态机和 QA 口径。
Phase 1:静态模板预览纵切
完成 /editor/agent 编辑器壳、固定模板、虚拟文件系统、AI patch 保存、runner 静态构建、artifact 服务和 iframe reload。
Phase 2:持久任务和恢复
引入 web_project_runtime_job,按 lease / controller / worker 模式实现任务队列、取消、stale、刷新恢复和日志 SSE。
Phase 3:受控依赖安装
支持白名单依赖、lockfile 固化、依赖层缓存、安装失败可读错误、依赖封禁和审计。
Phase 4:实时体验增强
在安全评审后再做长驻 dev server、HMR、WebSocket 代理、端口租约和空闲回收。
Phase 5:作品化发布
将通过安全门禁的 Web project 接入平台作品类型。发布必须重新构建 immutable artifact,不直接提升临时预览 artifact。
与现有系统的关系
- 前端 SSE 读取复用
src/services/sseStream.ts。 - 后端 job 模式参考外部生成 worker 的 lease / controller 经验,但使用新的 Web 工程 runtime 语义。
/editor/agent是第一版用户入口,不新增重复 IDE 页面。- 业务真相仍通过 server-rs + SpacetimeDB 受控写入,前端和 runner 都不能绕过控制面。