Files
Genarrative/src/components/creative-agent/creativeAgentViewModel.test.ts
T
2026-05-08 11:44:42 +08:00

321 lines
9.1 KiB
TypeScript

import { expect, test } from 'vitest';
import type {
CreativeAgentSessionSnapshot,
CreativeAgentSseEvent,
} from '../../../packages/shared/src/contracts/creativeAgent';
import { buildCreativeAgentProcessItems } from './creativeAgentViewModel';
function createSession(
overrides: Partial<CreativeAgentSessionSnapshot> = {},
): CreativeAgentSessionSnapshot {
return {
sessionId: 'creative-session-1',
stage: 'target_ready',
inputSummary: {
text: '做一个生日拼图',
entryContext: 'creation_home',
images: [],
materialSummary: '做一个生日拼图',
unsupportedCapabilities: [],
},
messages: [],
puzzleTemplateCatalog: [],
puzzleTemplateSelection: null,
puzzleImageGenerationPlan: null,
targetBinding: {
playType: 'puzzle',
targetSessionId: 'puzzle-session-1',
targetStage: 'puzzle-result',
resultProfileId: 'puzzle-profile-1',
},
updatedAt: '2026-05-05T10:00:00.000Z',
...overrides,
};
}
test('buildCreativeAgentProcessItems expands creative agent sse details', () => {
const eventLog: CreativeAgentSseEvent[] = [
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'perceiving',
},
},
{
event: 'thought_summary_delta',
data: {
sessionId: 'creative-session-1',
thoughtId: 'thought-1',
textDelta: '正在理解生日素材,',
},
},
{
event: 'thought_summary_delta',
data: {
sessionId: 'creative-session-1',
thoughtId: 'thought-1',
textDelta: '并准备转成拼图关卡。',
},
},
{
event: 'tool_started',
data: {
sessionId: 'creative-session-1',
toolCallId: 'tool-1',
toolName: 'retrieve_puzzle_template_catalog',
summary: '读取拼图模板',
},
},
{
event: 'tool_completed',
data: {
sessionId: 'creative-session-1',
toolCallId: 'tool-1',
toolName: 'retrieve_puzzle_template_catalog',
summary: '已读取拼图模板',
},
},
{
event: 'puzzle_template_catalog',
data: {
sessionId: 'creative-session-1',
templates: [
{
templateId: 'puzzle.default-creative',
title: '创意拼图',
summary: '把图文灵感做成拼图。',
previewImageSrc: null,
supportedLevelMode: 'single_or_multi',
minLevelCount: 1,
maxLevelCount: 6,
defaultLevelCount: 1,
costRange: {
minPoints: 2,
maxPoints: 12,
pricingUnit: 'point',
reason: '按关卡数估算',
},
requiredDraftFields: ['workTitle'],
imagePolicy: {
allowUploadedImageDirectly: true,
allowGeneratedImages: true,
allowPerLevelReferenceImage: true,
defaultCandidateCountPerLevel: 1,
},
},
],
},
},
{
event: 'puzzle_template_selection',
data: {
sessionId: 'creative-session-1',
selection: {
templateId: 'puzzle.default-creative',
title: '创意拼图',
reason: '适合把生日素材做成拼图。',
costRange: {
minPoints: 2,
maxPoints: 12,
pricingUnit: 'point',
reason: '按关卡数估算',
},
supportedLevelMode: 'single_or_multi',
selectedLevelMode: 'multi_level',
plannedLevelCount: 3,
requiresUserConfirmation: true,
},
},
},
{
event: 'puzzle_level_plan',
data: {
sessionId: 'creative-session-1',
plan: {
mode: 'multi_level',
templateId: 'puzzle.default-creative',
estimatedCostRange: {
minPoints: 2,
maxPoints: 12,
pricingUnit: 'point',
reason: '按关卡数估算',
},
levels: [
{
levelId: 'level-1',
levelName: '生日开场',
pictureDescription: '蛋糕和礼物',
imagePrompt: '蛋糕和礼物',
pictureReference: null,
candidateCount: 1,
},
],
},
},
},
{
event: 'done',
data: {
sessionId: 'creative-session-1',
},
},
];
const items = buildCreativeAgentProcessItems(eventLog, createSession());
expect(items.map((item) => item.title)).toContain('素材已理解');
expect(items.map((item) => item.title)).toContain('思考摘要');
expect(items.find((item) => item.title === '思考摘要')?.detail).toBe(
'正在理解生日素材,并准备转成拼图关卡。',
);
expect(items.find((item) => item.title === '思考摘要')?.tone).toBe('done');
expect(items.map((item) => item.title)).toContain('开始:读取拼图模板');
expect(items.find((item) => item.title === '开始:读取拼图模板')?.tone).toBe(
'done',
);
expect(items.map((item) => item.title)).toContain('读取 1 个模板');
expect(items.map((item) => item.title)).toContain('选择 创意拼图');
expect(items.map((item) => item.title)).toContain('规划 1 个关卡');
expect(items.at(-1)?.detailLines).toContain('目标会话:puzzle-session-1');
expect(items.some((item) => item.tone === 'active')).toBe(false);
});
test('buildCreativeAgentProcessItems only keeps current running stage active', () => {
const eventLog: CreativeAgentSseEvent[] = [
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'perceiving',
},
},
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'thinking',
},
},
];
const items = buildCreativeAgentProcessItems(
eventLog,
createSession({
stage: 'thinking',
targetBinding: null,
}),
);
expect(items.find((item) => item.title === '素材已理解')?.tone).toBe('done');
expect(items.find((item) => item.title === '正在构思')?.tone).toBe('active');
expect(items.filter((item) => item.tone === 'active')).toHaveLength(1);
});
test('buildCreativeAgentProcessItems stops spinners after waiting confirmation', () => {
const eventLog: CreativeAgentSseEvent[] = [
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'perceiving',
},
},
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'selecting_puzzle_template',
},
},
{
event: 'thought_summary_delta',
data: {
sessionId: 'creative-session-1',
thoughtId: 'thought-1',
textDelta: '已经选择合适模板。',
},
},
{
event: 'tool_started',
data: {
sessionId: 'creative-session-1',
toolCallId: 'tool-start',
toolName: 'retrieve_puzzle_template_catalog',
summary: '读取拼图模板',
},
},
{
event: 'tool_completed',
data: {
sessionId: 'creative-session-1',
toolCallId: 'tool-done',
toolName: 'retrieve_puzzle_template_catalog',
summary: '已读取拼图模板',
},
},
{
event: 'stage',
data: {
sessionId: 'creative-session-1',
stage: 'waiting_template_confirmation',
},
},
];
const items = buildCreativeAgentProcessItems(
eventLog,
createSession({
stage: 'waiting_template_confirmation',
targetBinding: null,
}),
);
expect(items.find((item) => item.title === '思考摘要')?.tone).toBe('done');
expect(items.find((item) => item.title === '开始:读取拼图模板')?.tone).toBe(
'done',
);
expect(items.find((item) => item.title === '等待确认')?.tone).toBe('warning');
expect(items.some((item) => item.tone === 'active')).toBe(false);
});
test('buildCreativeAgentProcessItems falls back to session snapshots', () => {
const session = createSession({
puzzleTemplateSelection: {
templateId: 'puzzle.default-creative',
title: '创意拼图',
reason: '适合拼图创作。',
costRange: {
minPoints: 2,
maxPoints: 12,
pricingUnit: 'point',
reason: '按关卡数估算',
},
supportedLevelMode: 'single_or_multi',
selectedLevelMode: 'single_level',
plannedLevelCount: 1,
requiresUserConfirmation: true,
},
});
const items = buildCreativeAgentProcessItems([], session);
expect(items.map((item) => item.title)).toContain('选择 创意拼图');
expect(items.map((item) => item.title)).toContain('拼图草稿已绑定');
});
test('buildCreativeAgentProcessItems renders waiting session fallback as static', () => {
const items = buildCreativeAgentProcessItems(
[],
createSession({
stage: 'waiting_template_confirmation',
targetBinding: null,
}),
);
expect(items.map((item) => item.title)).toContain('等待确认');
expect(items.find((item) => item.title === '等待确认')?.tone).toBe('warning');
expect(items.some((item) => item.tone === 'active')).toBe(false);
});