import { expect, test } from "vitest"; import { buildTaskCycles, groupParallelSteps } from "@/lib/journey"; import type { JourneyEdge, JourneyStep } from "@/lib/types"; function step(overrides: Partial): JourneyStep { return { step_id: "plan:task-1", sequence: 1, step_type: "plan", title: "Planner 规划·整体结构", status: "completed", task_id: "task-1", attempt_id: null, validation_id: null, decision_id: null, reasoning: "当前缺少整体结构", reasoning_source: "contract", process: { label: "创建整体结构 Task", actor: "Planner", tool_name: null, trace_id: null, details: {} }, input_data: [], output_data: [], contract: { action: "创建", reasoning: "需要结构", goals: ["goal-1"], inputs: [], output: "整体结构", criteria: [] }, parallel_group_id: null, parallel_position: null, parallel_total: null, model: null, tokens: null, cost: null, duration_ms: null, created_at: "2026-07-21T00:00:00Z", evidence: { contract: null, tool_calls: [], artifact_refs: [], validation: null, decision: null }, ...overrides, }; } test("全局层按 Task 聚合规划、执行、验收和返工", () => { const values = [ step({}), step({ step_id: "execute:attempt-1", step_type: "execute", attempt_id: "attempt-1" }), step({ step_id: "decide:decision-1", step_type: "decide", decision_id: "decision-1", status: "retry" }), ]; const edges: JourneyEdge[] = [ { edge_id: "loop", source: "decide:decision-1", target: "execute:attempt-1", relation: "loop", label: "重试" }, ]; const cycles = buildTaskCycles(values, edges); expect(cycles).toHaveLength(1); expect(cycles[0].title).toBe("整体结构"); expect(cycles[0].loopCount).toBe(1); expect(cycles[0].steps).toHaveLength(3); }); test("步骤层把同一 Operation 的 Worker 表达为并行组", () => { const values = [ step({ step_id: "execute:a", step_type: "execute", parallel_group_id: "operation-1" }), step({ step_id: "execute:b", step_type: "execute", task_id: "task-2", parallel_group_id: "operation-1" }), ]; const groups = groupParallelSteps(values); expect(groups).toHaveLength(1); expect(groups[0].kind).toBe("parallel"); expect(groups[0].steps).toHaveLength(2); });