import type { BackendTask, ProcessArtifact, ProcessEvent, ProcessRun } from '@/types'; export type TaskProcessSelection = { runs: ProcessRun[]; events: ProcessEvent[]; artifacts: ProcessArtifact[]; }; export type SelectTaskProcessInput = { task: BackendTask; liveRuns?: ProcessRun[]; liveEvents?: ProcessEvent[]; liveArtifacts?: ProcessArtifact[]; }; function mergeById( persisted: T[], live: T[], idFor: (item: T) => string, ): T[] { const merged = new Map(); for (const item of persisted) merged.set(idFor(item), item); for (const item of live) merged.set(idFor(item), item); return Array.from(merged.values()); } function runBelongsToTask(run: ProcessRun, taskId: string, runIds: Set): boolean { return runIds.has(run.run_id) || run.metadata?.task_id === taskId; } function expandTaskRunIds(runs: ProcessRun[], taskId: string, seedRunIds: Set): Set { const selected = new Set(seedRunIds); for (const run of runs) { if (run.metadata?.task_id === taskId) selected.add(run.run_id); } let changed = true; while (changed) { changed = false; for (const run of runs) { if (!run.parent_run_id || !selected.has(run.parent_run_id) || selected.has(run.run_id)) continue; selected.add(run.run_id); changed = true; } } return selected; } export function selectTaskProcess({ task, liveRuns = [], liveEvents = [], liveArtifacts = [], }: SelectTaskProcessInput): TaskProcessSelection { const persistedRuns = task.process_runs ?? []; const persistedEvents = task.process_events ?? []; const persistedArtifacts = task.process_artifacts ?? []; const allRuns = mergeById(persistedRuns, liveRuns, (run) => run.run_id); const seedRunIds = new Set([ ...task.run_ids.filter(Boolean), ...persistedRuns.map((run) => run.run_id), ]); const taskRunIds = expandTaskRunIds(allRuns, task.task_id, seedRunIds); const runs = allRuns.filter((run) => runBelongsToTask(run, task.task_id, taskRunIds)); return { runs, events: mergeById(persistedEvents, liveEvents, (event) => event.event_id).filter( (event) => taskRunIds.has(event.run_id) || event.metadata?.task_id === task.task_id ), artifacts: mergeById(persistedArtifacts, liveArtifacts, (artifact) => artifact.artifact_id).filter( (artifact) => taskRunIds.has(artifact.run_id) || artifact.metadata?.task_id === task.task_id ), }; }