import type { JourneyEdge, JourneyStep, TaskCycle } from "@/lib/types"; export function buildTaskCycles(steps: JourneyStep[], edges: JourneyEdge[]): TaskCycle[] { const groups = new Map(); for (const step of steps) { const values = groups.get(step.task_id) ?? []; values.push(step); groups.set(step.task_id, values); } return [...groups.entries()] .map(([taskId, values]) => { const plan = values.find((step) => step.step_type === "plan"); const last = values.at(-1)!; return { taskId, title: plan?.contract?.output ?? plan?.title.replace("Planner 规划·", "") ?? last.title, status: last.status, steps: values, goals: plan?.contract?.goals ?? [], loopCount: edges.filter( (edge) => edge.relation === "loop" && values.some((step) => step.step_id === edge.source), ).length, parallel: values.some((step) => Boolean(step.parallel_group_id)), }; }) .sort((left, right) => left.steps[0].sequence - right.steps[0].sequence); } export type StepGroup = | { kind: "single"; id: string; steps: [JourneyStep] } | { kind: "parallel"; id: string; steps: JourneyStep[] }; export function groupParallelSteps(steps: JourneyStep[]): StepGroup[] { const ordered = [...steps].sort((left, right) => left.sequence - right.sequence); const output: StepGroup[] = []; const consumed = new Set(); for (const step of ordered) { if (consumed.has(step.step_id)) continue; if (step.parallel_group_id && step.step_type === "execute") { const parallel = ordered.filter( (candidate) => candidate.step_type === "execute" && candidate.parallel_group_id === step.parallel_group_id, ); parallel.forEach((candidate) => consumed.add(candidate.step_id)); output.push({ kind: "parallel", id: step.parallel_group_id, steps: parallel }); continue; } consumed.add(step.step_id); output.push({ kind: "single", id: step.step_id, steps: [step] }); } return output; } export function statusLabel(status: string): string { return { accept: "已接受", accepted: "已接受", completed: "已完成", passed: "已通过", failed: "未通过", retry: "重新执行", revise: "正在修订", split: "已拆分", block: "阶段等待", blocked: "阶段等待", running: "进行中", submitted: "已提交", needs_replan: "等待决策", }[status.toLowerCase()] ?? status; }