Files
Genarrative/packages/shared/src/contracts/gameCreationApp.ts
T
AIGameCreator App afd699a060 补齐游戏创作智能体本地Run控制
新增 agent run 状态、停止、重试和恢复命令
把 run 生命周期写入 trace、activity、output 和 context bundle
补齐聊天入口、测试覆盖和实施计划文档
2026-06-26 21:55:31 +08:00

489 lines
14 KiB
TypeScript

export const GAME_CREATION_APP_MANIFEST_SCHEMA_VERSION =
'game-creation-app.manifest.v1';
export const GAME_CREATION_AGENT_RUN_SCHEMA_VERSION =
'game-creator-agent-run.v1';
export const GAME_CREATION_AGENT_RUN_MAX_PASSES = 3;
export const GAME_CREATION_AGENT_TOOL_CALL_MAX = 128;
export type GameCreationAppPermission = 'auto' | 'confirm' | 'deny';
export interface GameCreationAppCommandDescriptor {
id: string;
permission: GameCreationAppPermission;
}
export const GAME_CREATION_APP_COMMANDS = [
{ id: 'help.show', permission: 'auto' },
{ id: 'project.create', permission: 'confirm' },
{ id: 'project.status', permission: 'auto' },
{ id: 'task.list', permission: 'auto' },
{ id: 'agent.trace_read', permission: 'auto' },
{ id: 'agent.run_status', permission: 'auto' },
{ id: 'agent.kill', permission: 'confirm' },
{ id: 'agent.retry', permission: 'confirm' },
{ id: 'agent.resume', permission: 'confirm' },
{ id: 'agent.capabilities', permission: 'auto' },
{ id: 'agent.audit', permission: 'auto' },
{ id: 'llm.config_check', permission: 'auto' },
{ id: 'game.generate_draft', permission: 'confirm' },
{ id: 'game.run_local', permission: 'confirm' },
{ id: 'file.list', permission: 'auto' },
{ id: 'file.read', permission: 'auto' },
{ id: 'file.write', permission: 'confirm' },
{ id: 'file.delete', permission: 'confirm' },
{ id: 'asset.list', permission: 'auto' },
{ id: 'asset.upload', permission: 'confirm' },
{ id: 'asset.register', permission: 'auto' },
{ id: 'preview.start', permission: 'confirm' },
{ id: 'preview.open', permission: 'confirm' },
{ id: 'preview.stop', permission: 'auto' },
{ id: 'preview.status', permission: 'auto' },
{ id: 'command.run_limited', permission: 'confirm' },
{ id: 'canvas.project_open', permission: 'confirm' },
{ id: 'canvas.project_sync', permission: 'confirm' },
{ id: 'canvas.asset_import', permission: 'confirm' },
{ id: 'canvas.export_import', permission: 'confirm' },
{ id: 'memory.read', permission: 'auto' },
{ id: 'memory.write', permission: 'confirm' },
{ id: 'memory.delete', permission: 'confirm' },
] as const satisfies readonly GameCreationAppCommandDescriptor[];
export interface GameCreationAgentCapabilityDescriptor {
id: string;
area: 'user' | 'agent-runtime' | 'local-runtime' | 'dev-runtime';
title: string;
}
export const GAME_CREATION_AGENT_CAPABILITIES = [
{ id: 'chat', area: 'user', title: '聊天入口' },
{ id: 'file-upload', area: 'user', title: '上传文件' },
{ id: 'built-in-commands', area: 'agent-runtime', title: '内置命令调用' },
{ id: 'llm-draft-generation', area: 'agent-runtime', title: 'LLM 草案生成' },
{ id: 'task-decomposition', area: 'agent-runtime', title: '任务拆分' },
{ id: 'orchestration', area: 'agent-runtime', title: '任务编排' },
{
id: 'agent-loop',
area: 'agent-runtime',
title: 'Planner / Generator / Evaluator 循环',
},
{
id: 'task-graph-agenda',
area: 'agent-runtime',
title: '任务图议程',
},
{
id: 'evaluator-repair-routing',
area: 'agent-runtime',
title: 'Evaluator 返工路由',
},
{
id: 'tool-call-budget',
area: 'agent-runtime',
title: '工具调用预算',
},
{
id: 'multi-agent-collaboration',
area: 'agent-runtime',
title: '多智能体协作',
},
{
id: 'role-level-collaboration',
area: 'agent-runtime',
title: '组内角色协作',
},
{ id: 'quality-review', area: 'agent-runtime', title: '质量评审' },
{ id: 'run-lifecycle', area: 'agent-runtime', title: 'Run 生命周期控制' },
{
id: 'repair-loop-carryover',
area: 'agent-runtime',
title: '返工范围与 Carry-over',
},
{ id: 'short-term-memory', area: 'agent-runtime', title: '短期记忆' },
{ id: 'long-term-memory', area: 'agent-runtime', title: '长期记忆' },
{ id: 'local-artifacts', area: 'local-runtime', title: '本地产物保存' },
{ id: 'local-preview', area: 'local-runtime', title: '本地 HTTP 预览' },
{
id: 'canvas-project-sync',
area: 'local-runtime',
title: '画板项目资源同步',
},
{ id: 'developer-window', area: 'dev-runtime', title: '开发窗口' },
{ id: 'guardrails', area: 'dev-runtime', title: '权限 Gate' },
{ id: 'trace-log', area: 'dev-runtime', title: '执行日志' },
] as const satisfies readonly GameCreationAgentCapabilityDescriptor[];
export interface GameCreationAppLimitedRunCommandDescriptor {
id: string;
title: string;
}
export const GAME_CREATION_APP_LIMITED_RUN_COMMANDS = [
{ id: 'game.static_smoke', title: '静态入口自检' },
] as const satisfies readonly GameCreationAppLimitedRunCommandDescriptor[];
export type GameCreationAppAgentGroup =
| 'design'
| 'art'
| 'code'
| 'balance'
| 'audio'
| 'publishing';
export type GameCreationAppTaskStatus =
| 'pending'
| 'running'
| 'waiting-for-confirmation'
| 'completed'
| 'failed';
export interface GameCreationAppTaskState {
id: string;
title: string;
group: GameCreationAppAgentGroup;
role: string;
status: GameCreationAppTaskStatus;
dependencies: string[];
artifacts: string[];
acceptanceCriteria: string[];
}
export const GAME_CREATION_APP_SEED_TASKS = [
{
id: 'design-director',
title: '拆解创作方向',
group: 'design',
role: 'Director',
status: 'pending',
dependencies: [],
artifacts: ['.agent/spec.md'],
acceptanceCriteria: ['创作目标、范围和专业组分工明确'],
},
{
id: 'design-foundation',
title: '确定玩法规格',
group: 'design',
role: 'Gameplay',
status: 'pending',
dependencies: ['design-director'],
artifacts: ['memory/project.md', 'game/game_design.md'],
acceptanceCriteria: ['核心循环、胜负条件和第一版关卡目标明确'],
},
{
id: 'balance-director',
title: '确定数值口径',
group: 'balance',
role: 'Director',
status: 'pending',
dependencies: ['design-foundation'],
artifacts: ['.agent/passes/pass-*/groups/balance/director.md'],
acceptanceCriteria: ['难度、节奏和得分口径可指导数值表'],
},
{
id: 'balance-seed',
title: '生成初版数值',
group: 'balance',
role: 'Difficulty',
status: 'pending',
dependencies: ['balance-director'],
artifacts: ['game/balance.json'],
acceptanceCriteria: ['速度、生命、得分和难度参数可被程序组读取'],
},
{
id: 'art-director',
title: '确定视觉方向',
group: 'art',
role: 'Director',
status: 'pending',
dependencies: ['design-foundation'],
artifacts: ['.agent/passes/pass-*/groups/art/director.md'],
acceptanceCriteria: ['角色、场景和 UI 的统一视觉方向明确'],
},
{
id: 'art-asset-plan',
title: '规划美术资产',
group: 'art',
role: 'Asset',
status: 'pending',
dependencies: ['art-director'],
artifacts: ['assets/manifest.art.json'],
acceptanceCriteria: ['角色、场景、UI 和动画需求已映射到画板或本地资产'],
},
{
id: 'art-polish',
title: '检查美术可用性',
group: 'art',
role: 'Polish',
status: 'pending',
dependencies: ['art-asset-plan'],
artifacts: ['.agent/passes/pass-*/groups/art/polish.md'],
acceptanceCriteria: ['首版资产不阻塞可玩原型和后续画板精修'],
},
{
id: 'audio-director',
title: '确定声音方向',
group: 'audio',
role: 'Director',
status: 'pending',
dependencies: ['design-foundation'],
artifacts: ['.agent/passes/pass-*/groups/audio/director.md'],
acceptanceCriteria: ['BGM 氛围和交互音效边界明确'],
},
{
id: 'audio-asset-plan',
title: '规划音乐音效',
group: 'audio',
role: 'SFX',
status: 'pending',
dependencies: ['audio-director'],
artifacts: ['assets/manifest.audio.json'],
acceptanceCriteria: ['BGM 和核心交互音效需求已明确'],
},
{
id: 'code-director',
title: '拆解程序实现',
group: 'code',
role: 'Director',
status: 'pending',
dependencies: [
'design-foundation',
'balance-seed',
'art-polish',
'audio-asset-plan',
],
artifacts: ['.agent/passes/pass-*/groups/code/director.md'],
acceptanceCriteria: ['渲染、输入、状态和数据读取边界明确'],
},
{
id: 'code-prototype',
title: '生成可运行原型',
group: 'code',
role: 'Code',
status: 'pending',
dependencies: ['code-director'],
artifacts: ['game/'],
acceptanceCriteria: ['本地 Web 游戏项目可以通过 HTTP server 打开'],
},
{
id: 'quality-review',
title: '执行质量评审',
group: 'code',
role: 'Review',
status: 'pending',
dependencies: ['code-prototype'],
artifacts: ['.agent/findings.md', '.agent/run.latest.json'],
acceptanceCriteria: ['玩法、资产、数值、程序和发布包装通过跨专业组质量评审'],
},
{
id: 'preview-readiness',
title: '执行静态自检',
group: 'code',
role: 'Preview',
status: 'pending',
dependencies: ['quality-review'],
artifacts: ['.agent/logs/command.log', '.agent/run.latest.json'],
acceptanceCriteria: ['HTML 自包含且通过本地静态 smoke'],
},
{
id: 'preview-playtest',
title: '预览并试玩验收',
group: 'code',
role: 'Playtest',
status: 'pending',
dependencies: ['preview-readiness'],
artifacts: ['.agent/logs/preview.log'],
acceptanceCriteria: ['预览不是空白页,主循环和基础输入可用'],
},
{
id: 'publish-strategy',
title: '整理运营定位',
group: 'publishing',
role: 'Director',
status: 'pending',
dependencies: ['preview-playtest'],
artifacts: ['.agent/passes/pass-*/groups/publishing/director.md'],
acceptanceCriteria: ['标题、卖点、标签和封面方向明确'],
},
{
id: 'publish-package',
title: '整理发布包装',
group: 'publishing',
role: 'Publish',
status: 'pending',
dependencies: ['publish-strategy'],
artifacts: ['exports/README.md'],
acceptanceCriteria: ['标题、简介、标签、封面需求和导出检查已完成'],
},
] satisfies readonly GameCreationAppTaskState[];
export function createGameCreationAppSeedTasks(): GameCreationAppTaskState[] {
return GAME_CREATION_APP_SEED_TASKS.map((task) => ({
...task,
dependencies: [...task.dependencies],
artifacts: [...task.artifacts],
acceptanceCriteria: [...task.acceptanceCriteria],
}));
}
export type GameCreationAppAssetSourceKind =
| 'uploaded'
| 'generated'
| 'canvas';
export interface GameCreationAppAssetSource {
kind: GameCreationAppAssetSourceKind;
canvasProjectId?: string | null;
resourceId?: string | null;
assetObjectId?: string | null;
taskId?: string | null;
prompt?: string | null;
model?: string | null;
}
export interface GameCreationAppAssetManifestEntry {
id: string;
kind: string;
mediaType: string;
localPath: string;
source: GameCreationAppAssetSource;
}
export type GameCreationAppPreviewStatus =
| 'stopped'
| 'starting'
| 'running'
| 'failed';
export interface GameCreationAppPreviewState {
status: GameCreationAppPreviewStatus;
url?: string | null;
port?: number | null;
}
export interface GameCreationAppCommandRunState {
commandId: string;
status: 'completed' | 'failed';
output: string;
logPath: string;
updatedAt: number;
}
export interface GameCreationAppManifest {
schemaVersion: string;
projectId: string;
name: string;
goal?: string | null;
tasks: GameCreationAppTaskState[];
assets: GameCreationAppAssetManifestEntry[];
preview?: GameCreationAppPreviewState | null;
commandRuns?: GameCreationAppCommandRunState[];
}
export interface GameCreationAgentToolCallTrace {
toolId: string;
status: string;
inputPaths: string[];
outputPaths: string[];
summary: string;
}
export interface GameCreationAgentRunStep {
pass: number;
agent: string;
phase: string;
taskId: string | null;
group: GameCreationAppAgentGroup | null;
role: string | null;
status: string;
inputPaths: string[];
outputPaths: string[];
summary: string;
toolCalls: GameCreationAgentToolCallTrace[];
}
export interface GameCreationAgentArtifactTrace {
path: string;
sizeBytes: number;
checksum: string;
}
export interface GameCreationAgentRepairRouteTrace {
issue: string;
taskIds: string[];
reason: string;
}
export interface GameCreationAgentRunTaskGraphTrace {
goal: string;
readyTaskIds: string[];
activeTaskIds: string[];
carriedTaskIds: string[];
repairFocus: string[];
repairRoutes: GameCreationAgentRepairRouteTrace[];
tasks: GameCreationAppTaskState[];
}
export interface GameCreationAgentPassPlanTrace {
pass: number;
mode: 'initial' | 'repair' | string;
summary: string;
activeTaskIds: string[];
carriedTaskIds: string[];
dependencyWaves: string[][];
repairFocus: string[];
repairRoutes: GameCreationAgentRepairRouteTrace[];
}
export interface GameCreationAgentRunTrace {
schemaVersion: typeof GAME_CREATION_AGENT_RUN_SCHEMA_VERSION;
runId: string;
commandId: string;
status: string;
lifecycleStatus?: string | null;
passes: number;
maxPasses: number;
toolCallCount: number;
maxToolCalls: number;
stopReason: string;
goal: string;
coordination: string;
steps: GameCreationAgentRunStep[];
artifacts: GameCreationAgentArtifactTrace[];
taskGraph: GameCreationAgentRunTaskGraphTrace;
passPlans: GameCreationAgentPassPlanTrace[];
nextStep: string;
error: string | null;
updatedAt: number;
}
export function selectGameCreationAppReadyTasks(
manifest: Pick<GameCreationAppManifest, 'tasks'>,
): GameCreationAppTaskState[] {
const tasks =
manifest.tasks.length > 0
? manifest.tasks
: createGameCreationAppSeedTasks();
const completed = new Set(
tasks.filter((task) => task.status === 'completed').map((task) => task.id),
);
return tasks.filter(
(task) =>
task.status === 'pending' &&
task.dependencies.every((dependency) => completed.has(dependency)),
);
}
export function createGameCreationAppManifest(
projectId: string,
name: string,
): GameCreationAppManifest {
return {
schemaVersion: GAME_CREATION_APP_MANIFEST_SCHEMA_VERSION,
projectId,
name,
goal: null,
tasks: createGameCreationAppSeedTasks(),
assets: [],
};
}