1
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user