修正 AI 游戏创作真实网关生成链路
调整 AI 游戏创作 App 的 LLM 默认超时和输出上限 将组内角色 brief 改为本地编排生成,保留 6 组多角色 trace,减少真实 provider 调用 允许画板资源占位引用通过自检,继续拒绝固定模板和未完成实现 更新本地 provider smoke 和 Agent trace 断言
This commit is contained in:
@@ -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`。
|
||||
|
||||
Reference in New Issue
Block a user