/** * Runner Jobs API Client * Handles runner-job-related API requests */ import { apiGet, type ApiResponse } from "./client"; /** * Runner job status enum (matches backend RunnerJobStatus) */ export enum RunnerJobStatus { PENDING = "PENDING", QUEUED = "QUEUED", RUNNING = "RUNNING", COMPLETED = "COMPLETED", FAILED = "FAILED", CANCELLED = "CANCELLED", } /** * Runner job response interface (matches Prisma RunnerJob model) */ export interface RunnerJob { id: string; workspaceId: string; agentTaskId: string | null; type: string; status: RunnerJobStatus; priority: number; progressPercent: number; version: number; result: Record | null; error: string | null; createdAt: string; startedAt: string | null; completedAt: string | null; } /** * Filters for querying runner jobs */ export interface RunnerJobFilters { workspaceId?: string; status?: RunnerJobStatus | RunnerJobStatus[]; type?: string; agentTaskId?: string; page?: number; limit?: number; } /** * Paginated runner jobs response */ export interface PaginatedRunnerJobs { data: RunnerJob[]; meta?: { total?: number; page?: number; limit?: number; }; } /** * Fetch runner jobs with optional filters */ export async function fetchRunnerJobs(filters?: RunnerJobFilters): Promise { const params = new URLSearchParams(); if (filters?.status) { const statuses = Array.isArray(filters.status) ? filters.status : [filters.status]; for (const s of statuses) { params.append("status", s); } } if (filters?.type) { params.append("type", filters.type); } if (filters?.agentTaskId) { params.append("agentTaskId", filters.agentTaskId); } if (filters?.page !== undefined) { params.append("page", String(filters.page)); } if (filters?.limit !== undefined) { params.append("limit", String(filters.limit)); } const queryString = params.toString(); const endpoint = queryString ? `/api/runner-jobs?${queryString}` : "/api/runner-jobs"; const response = await apiGet>(endpoint, filters?.workspaceId); return response.data; } /** * Fetch a single runner job by ID */ export async function fetchRunnerJob(id: string, workspaceId?: string): Promise { return apiGet(`/api/runner-jobs/${id}`, workspaceId); } // ─── Job Steps ──────────────────────────────────────────────────────── /** * Job step phase enum (matches backend JobStepPhase) */ export enum JobStepPhase { SETUP = "SETUP", EXECUTION = "EXECUTION", VALIDATION = "VALIDATION", CLEANUP = "CLEANUP", } /** * Job step type enum (matches backend JobStepType) */ export enum JobStepType { COMMAND = "COMMAND", AI_ACTION = "AI_ACTION", GATE = "GATE", ARTIFACT = "ARTIFACT", } /** * Job step status enum (matches backend JobStepStatus) */ export enum JobStepStatus { PENDING = "PENDING", RUNNING = "RUNNING", COMPLETED = "COMPLETED", FAILED = "FAILED", SKIPPED = "SKIPPED", } /** * Job step response interface (matches Prisma JobStep model) */ export interface JobStep { id: string; jobId: string; ordinal: number; phase: JobStepPhase; name: string; type: JobStepType; status: JobStepStatus; output: string | null; tokensInput: number | null; tokensOutput: number | null; startedAt: string | null; completedAt: string | null; durationMs: number | null; } /** * Fetch job steps for a specific runner job */ export async function fetchJobSteps(jobId: string, workspaceId?: string): Promise { const response = await apiGet>( `/api/runner-jobs/${jobId}/steps`, workspaceId ); return response.data; }