202 lines
5.9 KiB
TypeScript
202 lines
5.9 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
|
||
import { buildSessionProgressView } from '@/lib/session-progress';
|
||
import type { ProcessArtifact, ProcessEvent, ProcessRun } from '@/types';
|
||
|
||
describe('session progress view builder', () => {
|
||
it('selects the latest active root run for the current session and builds its run tree', () => {
|
||
const processRuns: ProcessRun[] = [
|
||
{
|
||
run_id: 'old-root',
|
||
parent_run_id: null,
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'main',
|
||
actor_name: 'Main Agent',
|
||
title: '旧任务',
|
||
status: 'done',
|
||
started_at: '2026-05-22T08:00:00.000Z',
|
||
finished_at: '2026-05-22T08:05:00.000Z',
|
||
},
|
||
{
|
||
run_id: 'latest-root',
|
||
parent_run_id: null,
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'main',
|
||
actor_name: 'Main Agent',
|
||
title: '销售数据分析报告生成',
|
||
status: 'running',
|
||
started_at: '2026-05-22T09:00:00.000Z',
|
||
metadata: {
|
||
step_index: 3,
|
||
step_total: 5,
|
||
},
|
||
},
|
||
{
|
||
run_id: 'collect-data',
|
||
parent_run_id: 'latest-root',
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'collector',
|
||
actor_name: 'Data Agent',
|
||
title: '收集销售数据',
|
||
status: 'done',
|
||
started_at: '2026-05-22T09:01:00.000Z',
|
||
finished_at: '2026-05-22T09:03:00.000Z',
|
||
summary: '已获取 Q1 销售数据',
|
||
},
|
||
{
|
||
run_id: 'clean-data',
|
||
parent_run_id: 'latest-root',
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'cleaner',
|
||
actor_name: 'Cleaning Agent',
|
||
title: '数据清洗与预处理',
|
||
status: 'running',
|
||
started_at: '2026-05-22T09:04:00.000Z',
|
||
},
|
||
{
|
||
run_id: 'other-root',
|
||
parent_run_id: null,
|
||
session_id: 'web:other',
|
||
actor_type: 'agent',
|
||
actor_id: 'main',
|
||
actor_name: 'Main Agent',
|
||
title: '其他会话任务',
|
||
status: 'running',
|
||
started_at: '2026-05-22T10:00:00.000Z',
|
||
},
|
||
];
|
||
|
||
const processEvents: ProcessEvent[] = [
|
||
{
|
||
event_id: 'evt-clean',
|
||
run_id: 'clean-data',
|
||
parent_run_id: 'latest-root',
|
||
kind: 'run_progress',
|
||
actor_type: 'agent',
|
||
actor_id: 'cleaner',
|
||
actor_name: 'Cleaning Agent',
|
||
text: '清洗缺失值、异常值,统一格式',
|
||
created_at: '2026-05-22T09:05:00.000Z',
|
||
},
|
||
];
|
||
|
||
const processArtifacts: ProcessArtifact[] = [
|
||
{
|
||
artifact_id: 'artifact-json',
|
||
run_id: 'collect-data',
|
||
actor_type: 'agent',
|
||
actor_id: 'collector',
|
||
actor_name: 'Data Agent',
|
||
title: '销售数据',
|
||
artifact_type: 'json',
|
||
data: { rows: 120 },
|
||
created_at: '2026-05-22T09:03:30.000Z',
|
||
},
|
||
{
|
||
artifact_id: 'artifact-markdown',
|
||
run_id: 'clean-data',
|
||
actor_type: 'agent',
|
||
actor_id: 'cleaner',
|
||
actor_name: 'Cleaning Agent',
|
||
title: '清洗说明',
|
||
artifact_type: 'markdown',
|
||
content: '已完成数据标准化。',
|
||
created_at: '2026-05-22T09:05:30.000Z',
|
||
},
|
||
{
|
||
artifact_id: 'artifact-other-session',
|
||
run_id: 'other-root',
|
||
actor_type: 'agent',
|
||
actor_id: 'main',
|
||
title: '其他会话产物',
|
||
artifact_type: 'text',
|
||
content: '不应出现',
|
||
created_at: '2026-05-22T10:01:00.000Z',
|
||
},
|
||
];
|
||
|
||
const view = buildSessionProgressView({
|
||
sessionId: 'web:current',
|
||
processRuns,
|
||
processEvents,
|
||
processArtifacts,
|
||
locale: 'zh-CN',
|
||
});
|
||
|
||
expect(view).not.toBeNull();
|
||
expect(view?.rootRunId).toBe('latest-root');
|
||
expect(view?.title).toBe('销售数据分析报告生成');
|
||
expect(view?.progress).toMatchObject({
|
||
value: 3,
|
||
max: 5,
|
||
percent: 60,
|
||
label: '运行中:3 / 5 步',
|
||
});
|
||
expect(view?.steps.map((step) => step.runId)).toEqual(['collect-data', 'clean-data', 'latest-root']);
|
||
expect(view?.steps.find((step) => step.runId === 'clean-data')?.description).toBe('清洗缺失值、异常值,统一格式');
|
||
expect(view?.artifactTypeSummaries).toEqual([
|
||
{ type: 'json', count: 1, label: 'JSON' },
|
||
{ type: 'markdown', count: 1, label: 'Markdown' },
|
||
]);
|
||
expect(view?.artifacts.map((artifact) => artifact.artifactId)).toEqual(['artifact-markdown', 'artifact-json']);
|
||
});
|
||
|
||
it('falls back to completed child run counts when no explicit progress metadata exists', () => {
|
||
const processRuns: ProcessRun[] = [
|
||
{
|
||
run_id: 'root',
|
||
parent_run_id: null,
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'main',
|
||
actor_name: 'Main Agent',
|
||
title: '生成总结',
|
||
status: 'running',
|
||
started_at: '2026-05-22T09:00:00.000Z',
|
||
},
|
||
{
|
||
run_id: 'done-child',
|
||
parent_run_id: 'root',
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'writer',
|
||
actor_name: 'Writer',
|
||
title: '整理结果',
|
||
status: 'done',
|
||
started_at: '2026-05-22T09:01:00.000Z',
|
||
finished_at: '2026-05-22T09:02:00.000Z',
|
||
},
|
||
{
|
||
run_id: 'running-child',
|
||
parent_run_id: 'root',
|
||
session_id: 'web:current',
|
||
actor_type: 'agent',
|
||
actor_id: 'reviewer',
|
||
actor_name: 'Reviewer',
|
||
title: '复核结果',
|
||
status: 'running',
|
||
started_at: '2026-05-22T09:03:00.000Z',
|
||
},
|
||
];
|
||
|
||
const view = buildSessionProgressView({
|
||
sessionId: 'web:current',
|
||
processRuns,
|
||
processEvents: [],
|
||
processArtifacts: [],
|
||
locale: 'zh-CN',
|
||
});
|
||
|
||
expect(view?.progress).toMatchObject({
|
||
value: 1,
|
||
max: 2,
|
||
percent: 50,
|
||
label: '已完成 1 / 2 步',
|
||
});
|
||
});
|
||
});
|