import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; export type ClusterLevel = "low" | "medium" | "high"; export type ReviewDecision = "pass" | "retry" | "escalate" | "ask_user" | "timeout" | "error"; export type TaskStatus = | "queued" | "running" | "reviewing" | "paused_for_user" | "completed" | "timed_out" | "failed" | "blocked" | "cancelled"; export interface ClusterTaskInput { id: string; title: string; taskType: string; task: string; acceptanceCriteria: string[]; level: ClusterLevel; dependsOn?: string[]; cwd?: string; } export interface ClusterInput { goal: string; tasks: ClusterTaskInput[]; } export interface LevelConfig { model: string; thinkingLevel?: ThinkingLevel; tools?: string[]; timeoutMs?: number; } export interface ReviewerConfig { model?: string; thinkingLevel?: ThinkingLevel; tools?: string[]; timeoutMs?: number; } export interface LearningConfig { enabled: boolean; taskTypeUpgradeThreshold: number; historyRetentionDays: number; } export interface ClusterConfig { levels: Record; reviewer: ReviewerConfig; maxConcurrency: number; maxTasks: number; maxRetriesPerLevel: number; learning: LearningConfig; } export interface WorkerToolCall { name: string; args: Record; } export interface WorkerHistoryMessage { role?: string; content?: unknown; toolName?: string; toolCallId?: string; isError?: boolean; usage?: { input?: number; output?: number; cacheRead?: number; cacheWrite?: number; reasoning?: number; cost?: { total?: number }; totalTokens?: number; }; model?: string; stopReason?: string; errorMessage?: string; [key: string]: unknown; } export interface ApiRetryRecord { timestamp: number; attempt: number; delayMs: number; errorSummary: string; } export interface WorkerResult { exitCode: number; output: string; stderr: string; toolCalls: WorkerToolCall[]; model?: string; stopReason?: string; errorMessage?: string; usage: UsageStats; outputPath?: string; outputTruncated?: boolean; history: WorkerHistoryMessage[]; apiRetries?: ApiRetryRecord[]; } export interface UsageStats { input: number; output: number; cacheRead: number; cacheWrite: number; totalTokens: number; cost: number; contextTokens: number; turns: number; } export interface ReviewResult { decision: ReviewDecision; reason: string; missingCriteria: string[]; nextInstruction: string; rawOutput?: string; } export interface TaskAttempt { level: ClusterLevel; attempt: number; model?: string; startedAt: number; finishedAt?: number; worker?: WorkerResult; reviewer?: WorkerResult; review?: ReviewResult; } export interface TaskRuntime { id: string; title: string; taskType: string; task: string; acceptanceCriteria: string[]; dependsOn: string[]; cwd?: string; requestedLevel: ClusterLevel; initialLevel: ClusterLevel; levelSelectionReason: string; level: ClusterLevel; status: TaskStatus; attempts: TaskAttempt[]; output?: string; outputPath?: string; review?: ReviewResult; error?: string; startedAt?: number; finishedAt?: number; } export interface ClusterEvent { timestamp: number; taskId?: string; kind: "run" | "worker" | "review" | "state" | "control" | "error"; message: string; } export interface PausePeriod { startedAt: number; finishedAt?: number; } export interface ClusterState { runId: string; goal: string; cwd: string; executionDataVersion?: 1; status: "running" | "paused" | "completed" | "failed" | "cancelled"; tasks: TaskRuntime[]; events: ClusterEvent[]; startedAt: number; finishedAt?: number; paused: boolean; pausePeriods?: PausePeriod[]; } export interface ClusterRunResult { runId: string; status: ClusterState["status"]; summary: string; tasks: TaskRuntime[]; usage: UsageStats; } export interface ClusterDetails { runId: string; status: ClusterState["status"]; taskCount: number; completedCount: number; failedCount: number; pausedCount: number; state: ClusterState; result?: ClusterRunResult; } export interface UserDecision { action: "accept" | "retry" | "escalate" | "abandon"; } export interface UserDecisionRequest { runId: string; taskId: string; title: string; level: ClusterLevel; review: ReviewResult; } export interface ClusterSnapshot { version: 2; state: ClusterState; result?: ClusterRunResult; } export interface TaskLevelSelection { initialLevel: ClusterLevel; levelSelectionReason: string; } export interface LearningEvidence { projectKey: string; taskFingerprint: string; taskType: string; fromLevel: ClusterLevel; toLevel: ClusterLevel; runId: string; completedAt: number; configSignature: string; } export const LEVEL_ORDER: ClusterLevel[] = ["low", "medium", "high"]; export const COMPLETE_EXECUTION_DATA_VERSION = 1 as const; export function emptyUsage(): UsageStats { return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: 0, contextTokens: 0, turns: 0, }; } export function hasCompleteExecutionData(state: ClusterState): boolean { return state.executionDataVersion === COMPLETE_EXECUTION_DATA_VERSION; } export function isActiveClusterStatus(status: ClusterState["status"]): boolean { return status === "running" || status === "paused"; } export function isTerminalStatus(status: TaskStatus): boolean { return ["completed", "failed", "blocked", "cancelled", "timed_out"].includes(status); } export function isSuccessfulStatus(status: TaskStatus): boolean { return status === "completed"; }