998e33ca3d
补齐工作区启动器、非空目录确认和主窗口切换入口 改为运行时配置文件并支持全局与单Agent LLM Provider 接入平台 External API 生成和同步美术资产 补齐本地对话记录、Agent私有记忆和项目黑板 完善Agent状态、历史Run、快照、文件和资产快捷入口 同步AI游戏创作App实施计划和共享决策记录
285 lines
10 KiB
TypeScript
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 步骤');
|
|
});
|
|
});
|