修正 AI 游戏创作真实网关生成链路

调整 AI 游戏创作 App 的 LLM 默认超时和输出上限

将组内角色 brief 改为本地编排生成,保留 6 组多角色 trace,减少真实 provider 调用

允许画板资源占位引用通过自检,继续拒绝固定模板和未完成实现

更新本地 provider smoke 和 Agent trace 断言
This commit is contained in:
AIGameCreator App
2026-06-25 20:55:21 +08:00
parent 72a6d635da
commit 1b4bca1ab3
4 changed files with 162 additions and 195 deletions
@@ -23,33 +23,6 @@ const smokeAssetBytes = Buffer.concat([
const smokeAudioAssetPath = 'assets/uploads/smoke-bounce.mp3';
const smokeAudioAssetBytes = 'SMOKE_LOCAL_AUDIO:bounce';
const groupRoles = [
['策划组', 'Director', 'design', 'director'],
['策划组', 'Gameplay', 'design', 'gameplay'],
['数值组', 'Director', 'balance', 'director'],
['数值组', 'Difficulty', 'balance', 'difficulty'],
['美术组', 'Director', 'art', 'director'],
['美术组', 'Asset', 'art', 'asset'],
['美术组', 'Polish', 'art', 'polish'],
['音乐组', 'Director', 'audio', 'director'],
['音乐组', 'SFX', 'audio', 'sfx'],
['程序组', 'Director', 'code', 'director'],
['程序组', 'Code', 'code', 'code'],
['程序组', 'Preview', 'code', 'preview'],
['程序组', 'Playtest', 'code', 'playtest'],
['运营组', 'Director', 'publishing', 'director'],
['运营组', 'Publish', 'publishing', 'publish'],
];
function roleBrief(pass, [label, role, group, id]) {
return [
`本角色判断:pass ${pass} ${label} ${role} 负责 ${group}.${id}`,
`交付物:${group}/${id}`,
'下游约束:必须围绕反弹弹幕厨房,不能输出固定模板。',
'验收风险:缺输入、缺主循环或缺胜负状态都要返工。',
].join('\n');
}
function handoffs() {
return [
[
@@ -203,11 +176,7 @@ function draft({ withInput }) {
const responses = [
'## 核心循环\n\n反弹弹幕点亮三口锅。\n\n## Evaluator 验收\n\n必须有输入监听、主循环、胜负状态和重开路径。',
...groupRoles.map((role) => roleBrief(1, role)),
JSON.stringify(draft({ withInput: false })),
...groupRoles
.filter(([, , group]) => group === 'code' || group === 'publishing')
.map((role) => roleBrief(2, role)),
JSON.stringify(draft({ withInput: true })),
];
@@ -498,7 +467,7 @@ try {
(step) =>
step.pass === 2 &&
step.agent === '程序组 / Director' &&
step.toolCalls?.[0]?.toolId === 'llm.chat.group.code.director',
step.toolCalls?.[0]?.toolId === 'agent.role.brief.code.director',
),
'trace missing code repair role',
);
@@ -507,7 +476,7 @@ try {
(step) =>
step.pass === 2 &&
step.agent === '运营组 / Publish' &&
step.toolCalls?.[0]?.toolId === 'llm.chat.group.publishing.publish',
step.toolCalls?.[0]?.toolId === 'agent.role.brief.publishing.publish',
),
'trace missing downstream publishing repair role',
);
File diff suppressed because it is too large Load Diff
@@ -52,7 +52,7 @@ describe('AI 游戏创作 Agent loop 摘要', () => {
summary: '需要回流画板角色素材',
toolCalls: [
{
toolId: 'llm.chat.group.art.asset',
toolId: 'agent.role.brief.art.asset',
status: 'completed',
inputPaths: ['.agent/manifest.json'],
outputPaths: ['.agent/passes/pass-2/groups/art/asset.md'],
@@ -115,7 +115,7 @@ game-project/
- 通过 Evaluator 和 `game.static_smoke` 后,Agent loop 会把本次 runId、状态、轮次、下一步、active / carry-over 任务和最终本地产物摘要追加到 `memory/session.md``memory/project.md`;下一次 Planner、组内角色和 Generator 会通过记忆输入自然读取上一轮稳定原型状态,而不只依赖开发窗口 trace。
- `.agent/agent.db` 当前作为最小本地索引文件使用 JSONL:初始化写入 `project.init`,每次 `game.generate_draft` 追加目标、标题和本地产物路径,上传 / 登记 / 画板导入资产时追加 `asset.register``asset.update`v1 不引入 SQLite 依赖。
- `.agent/run.latest.json` 的 schema 固定为共享契约 `GAME_CREATION_AGENT_RUN_SCHEMA_VERSION = game-creator-agent-run.v1`;TS 与 Rust 都从共享契约读取 run trace 类型,避免开发窗口和 Tauri 写入结构漂移。
- `game.generate_draft` 写入最终产物后会复用白名单受限命令 `game.static_smoke` 做一次生成后自检,至少检查 `game/index.html` 包含 canvas、canvas 渲染上下文、绘制调用、主循环、非空输入监听、明确目标、失败或胜利状态和重开路径,且不使用远程资源、`eval``new Function``localStorage``fetch``WebSocket``ServiceWorker`,也不得包含占位 / placeholder / 固定星核传送门模板词,并把该工具调用写入 `.agent/run.latest.json``.agent/logs/command.log`;自检失败则本次命令失败,不继续启动预览。
- `game.generate_draft` 写入最终产物后会复用白名单受限命令 `game.static_smoke` 做一次生成后自检,至少检查 `game/index.html` 包含 canvas、canvas 渲染上下文、绘制调用、主循环、非空输入监听、明确目标、失败或胜利状态和重开路径,且不使用远程资源、`eval``new Function``localStorage``fetch``WebSocket``ServiceWorker`,也不得包含固定星核传送门模板词、纯按钮计分模板或 `TODO` / `待实现` / `这里省略` 等未完成实现;画板资源占位引用允许出现在 asset id 或说明中,并把该工具调用写入 `.agent/run.latest.json``.agent/logs/command.log`;自检失败则本次命令失败,不继续启动预览。
- `ArtifactWriter` step 使用 `file.write.local_artifacts` 工具调用记录最终写入的 `memory/``game/``assets/``exports/``.agent/manifest.json` 路径;写入完成后 `nextStep` 指向 `game.static_smoke`
- `preview.start` / `preview.stop` 会追加 `.agent/logs/preview.log`,并在 `.agent/run.latest.json` 已存在时追加 `Preview` step 和 `preview.*` toolCall,记录本地 HTTP 预览 URL 与停止事件;单全局本地预览被新项目替换时,会 best-effort 把旧项目 manifest、preview log 和 trace 记录为 stopped,避免旧项目残留 running;本地 HTTP server 的 `/` 映射到 `game/index.html`,只允许读取 canonical 后仍位于项目真实 `game/` 或真实 `assets/` 下的文件,拒绝 `memory/``.agent/``exports/``..`、一级 `game` / `assets` 符号链接目录和内部符号链接越界,并为常见图片、音频、视频和 Web 资源返回对应 MIME;静态 `HEAD` 返回真实 `Content-Length` 但不返回 body,确保浏览器和媒体资源探测可用;上传和画板回流资产可被生成游戏引用但不会暴露记忆或 trace;没有 run trace 的手动预览启动不阻断。
- 聊天输入会生成待确认的 `game.generate_draft` 内置命令;用户确认后才把 LLM 返回的结构化草案写入短期记忆 `memory/session.md`、长期记忆 `memory/project.md`、设计草案 `game/game_design.md`、数值配置 `game/balance.json`、美术清单 `assets/manifest.art.json`、音乐音效清单 `assets/manifest.audio.json`、发布包装草案 `exports/README.md` 和可运行 `game/index.html`。生成完成后,普通聊天消息会自动展示最近一次 Agent loop 的轮次、工具调用、active / carry-over 任务、返工焦点、画板同步建议命令和本地产物摘要;完整证据仍由 `/trace` 读取同一份 `.agent/run.latest.json`