Files
Genarrative/apps/ai-game-creator-shell/tests/agentTraceSummary.test.ts
T
AIGameCreator App 998e33ca3d 完善AI游戏创作App本地工作区与Agent协作
补齐工作区启动器、非空目录确认和主窗口切换入口

改为运行时配置文件并支持全局与单Agent LLM Provider

接入平台 External API 生成和同步美术资产

补齐本地对话记录、Agent私有记忆和项目黑板

完善Agent状态、历史Run、快照、文件和资产快捷入口

同步AI游戏创作App实施计划和共享决策记录
2026-07-03 01:32:51 +08:00

285 lines
10 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
createGameCreationAppSeedTasks,
GAME_CREATION_AGENT_RUN_SCHEMA_VERSION,
type GameCreationAgentRunTrace,
} from '../../../packages/shared/src/contracts/gameCreationApp';
import { summarizeAgentRunTrace } from '../src/App';
describe('AI 游戏创作 Agent loop 摘要', () => {
it('shows repair loop state in the chat trace summary', () => {
const tasks = createGameCreationAppSeedTasks();
tasks[0]!.status = 'completed';
tasks[1]!.status = 'completed';
const trace: GameCreationAgentRunTrace = {
schemaVersion: GAME_CREATION_AGENT_RUN_SCHEMA_VERSION,
runId: 'run-test',
commandId: 'game.generate_draft',
status: 'needs-revision',
lifecycleStatus: 'pending',
passes: 2,
maxPasses: 3,
toolCallCount: 12,
maxToolCalls: 128,
stopReason: 'max-passes-exhausted',
goal: '做一个弹幕厨房游戏',
coordination: 'Planner -> Orchestrator -> Generator -> Evaluator',
steps: [
...Array.from({ length: 7 }, (_, index) => ({
pass: 1,
agent: `LLM-${index + 1}`,
phase: 'llm',
taskId: null,
group: null,
role: null,
status: 'completed',
inputPaths: [],
outputPaths: [],
summary: `LLM 调用 ${index + 1}`,
toolCalls: [
{
toolId: `llm.call.${index + 1}`,
status: 'ok',
inputPaths: [],
outputPaths: [],
summary: `LLM 工具 ${index + 1}`,
},
],
})),
{
pass: 2,
agent: 'Orchestrator',
phase: 'plan',
taskId: 'code-director',
group: 'code',
role: 'Code',
status: 'completed',
inputPaths: ['.agent/findings.md'],
outputPaths: ['.agent/passes/pass-2/task-graph.json'],
summary: '重跑程序链路及下游发布包装',
toolCalls: [],
},
...Array.from({ length: 4 }, (_, index) => ({
pass: 2,
agent: `Bridge-${index + 1}`,
phase: 'handoff',
taskId: null,
group: null,
role: null,
status: 'completed',
inputPaths: [],
outputPaths: [],
summary: `中间步骤 ${index + 1}`,
toolCalls: [],
})),
{
pass: 2,
agent: '美术组 / Asset',
phase: 'role-brief',
taskId: 'art-asset-plan',
group: 'art',
role: 'Asset',
status: 'completed',
inputPaths: ['.agent/manifest.json'],
outputPaths: ['.agent/passes/pass-2/groups/art/asset.md'],
summary: '需要回流画板角色素材',
toolCalls: [
{
toolId: 'agent.role.brief.art.asset',
status: 'completed',
inputPaths: ['.agent/manifest.json'],
outputPaths: ['.agent/passes/pass-2/groups/art/asset.md'],
summary: '规划角色资产',
},
{
toolId: 'agent.tool.suggest.canvas.project_sync',
status: 'suggested',
inputPaths: ['.agent/manifest.json'],
outputPaths: [],
summary:
'项目还没有画板回流资产;建议用户确认 /sync-canvas-project <画板项目ID>。',
},
...Array.from({ length: 5 }, (_, index) => ({
toolId: `agent.tool.suggest.extra.${index + 1}`,
status: 'suggested',
inputPaths: ['.agent/manifest.json'],
outputPaths: [],
summary: `额外建议命令 ${index + 1}`,
})),
],
},
],
artifacts: [
{
path: '.agent/older-artifact.json',
sizeBytes: 64,
checksum: 'fnv1a64:older',
},
{
path: '.agent/passes/pass-2/task-graph.json',
sizeBytes: 128,
checksum: 'fnv1a64:test',
},
...Array.from({ length: 4 }, (_, index) => ({
path: `.agent/passes/pass-2/artifact-${index + 1}.json`,
sizeBytes: 128 + index,
checksum: `fnv1a64:artifact-${index + 1}`,
})),
],
taskGraph: {
goal: '做一个弹幕厨房游戏',
readyTaskIds: ['code-director'],
activeTaskIds: ['code-director', 'quality-review', 'publish-package'],
carriedTaskIds: ['design-director'],
repairFocus: ['gameHtml 缺少 canvas'],
repairRoutes: [
{
issue: 'gameHtml 缺少 canvas',
taskIds: [
'code-director',
'quality-review',
'preview-readiness',
'publish-package',
],
reason: 'code-repair+dependency-impact',
},
{
issue: '缺少输入绑定',
taskIds: ['code-director'],
reason: 'input-binding',
},
{
issue: '缺少胜负条件',
taskIds: ['quality-review'],
reason: 'win-condition',
},
{
issue: '缺少发布说明',
taskIds: ['publish-package'],
reason: 'publish-readme',
},
],
tasks,
},
passPlans: [
{
pass: 1,
mode: 'initial',
summary: '第 1 轮全量调度',
activeTaskIds: ['design-director', 'code-director'],
carriedTaskIds: [],
dependencyWaves: [['design-director'], ['code-director']],
repairFocus: [],
repairRoutes: [],
},
{
pass: 2,
mode: 'repair',
summary: '第 2 轮重跑程序链路及下游发布包装',
activeTaskIds: ['code-director', 'quality-review', 'publish-package'],
carriedTaskIds: ['design-director'],
dependencyWaves: [
['code-director'],
['quality-review'],
['publish-package'],
],
repairFocus: ['gameHtml 缺少 canvas'],
repairRoutes: [
{
issue: 'gameHtml 缺少 canvas',
taskIds: [
'code-director',
'quality-review',
'preview-readiness',
'publish-package',
],
reason: 'code-repair+dependency-impact',
},
{
issue: '缺少输入绑定',
taskIds: ['code-director'],
reason: 'input-binding',
},
{
issue: '缺少胜负条件',
taskIds: ['quality-review'],
reason: 'win-condition',
},
{
issue: '缺少发布说明',
taskIds: ['publish-package'],
reason: 'publish-readme',
},
],
},
{
pass: 3,
mode: 'repair',
summary: '第 3 轮复核',
activeTaskIds: ['quality-review'],
carriedTaskIds: ['design-director'],
dependencyWaves: [['quality-review']],
repairFocus: [],
repairRoutes: [],
},
{
pass: 4,
mode: 'repair',
summary: '第 4 轮收尾',
activeTaskIds: ['publish-package'],
carriedTaskIds: [],
dependencyWaves: [['publish-package']],
repairFocus: [],
repairRoutes: [],
},
],
nextStep: 'repair-next-pass',
error: null,
updatedAt: 1,
};
const summary = summarizeAgentRunTrace(trace);
expect(summary).toContain(
'needs-revision / pending · 2/3 轮 · max-passes-exhausted',
);
expect(summary).toContain('工具调用:12/128');
expect(summary).toContain('任务:已完成 2');
expect(summary).toContain(
'active 任务:程序组 / Director 拆解程序实现(code-director), 程序组 / Review 执行质量评审(quality-review), 运营组 / Publish 整理发布包装(publish-package)',
);
expect(summary).toContain(
'carry-over 任务:策划组 / Director 拆解创作方向(design-director)',
);
expect(summary).toContain('返工焦点:gameHtml 缺少 canvas');
expect(summary).toContain(
'返工路线:code-repair+dependency-impact: 程序组 / Director 拆解程序实现(code-director), 程序组 / Review 执行质量评审(quality-review), 程序组 / Preview 执行静态自检(preview-readiness), 运营组 / Publish 整理发布包装(publish-package)',
);
expect(summary).toContain('还有 1 条路线');
expect(summary).not.toContain('publish-readme:');
expect(summary).toContain('建议命令:');
expect(summary).toContain('agent.tool.suggest.canvas.project_sync');
expect(summary).toContain('/sync-canvas-project <画板项目ID>');
expect(summary).toContain('agent.tool.suggest.extra.4');
expect(summary).not.toContain('agent.tool.suggest.extra.5');
expect(summary).toContain('还有 1 个建议命令');
expect(summary).toContain('编排轮次:');
expect(summary).toContain(
'pass 2 · repair · active 程序组 / Director 拆解程序实现(code-director), 程序组 / Review 执行质量评审(quality-review), 运营组 / Publish 整理发布包装(publish-package) · carry 策划组 / Director 拆解创作方向(design-director) · waves 程序组 / Director 拆解程序实现(code-director) / 程序组 / Review 执行质量评审(quality-review) / 运营组 / Publish 整理发布包装(publish-package) · repair gameHtml 缺少 canvas · routes code-repair+dependency-impact: 程序组 / Director 拆解程序实现(code-director), 程序组 / Review 执行质量评审(quality-review), 程序组 / Preview 执行静态自检(preview-readiness), 运营组 / Publish 整理发布包装(publish-package)',
);
expect(summary).not.toContain('pass 1 · initial');
expect(summary).toContain('还有 1 个较早轮次');
expect(summary).toContain('.agent/passes/pass-2/task-graph.json');
expect(summary).not.toContain('.agent/older-artifact.json');
expect(summary).toContain('还有 1 个较早产物');
expect(summary).not.toContain('Orchestrator #2 · completed · plan');
expect(summary).toContain('Bridge-1 #2 · completed · handoff');
expect(summary).toContain('还有 8 个较早步骤');
expect(summary).toContain('LLM-2 #1 · completed · llm · llm.call.2');
expect(summary).not.toContain('LLM-1 #1 · completed · llm · llm.call.1');
expect(summary).toContain('还有 1 个较早 LLM 步骤');
});
});