Repository Public
1/** Error classes of the kernel. Public ones are part of the contract; control-flow ones are internal. */23export class KernelError extends Error {4 constructor(message: string, options?: { cause?: unknown }) {5 super(message, options);6 this.name = new.target.name;7 }8}910/** Run logic made a different call at a given seq than the one recorded in the journal. */11export class NonDeterminismError extends KernelError {12 constructor(13 readonly runId: string,14 readonly seq: number,15 detail: string,16 ) {17 super(`Non-deterministic run logic at step ${seq} of run ${runId}: ${detail}`);18 }19}2021/** The lease was lost (fencing token changed, run no longer 'running', or heartbeat failed). */22export class LeaseLostError extends KernelError {23 constructor(readonly runId: string, detail = 'fencing check failed') {24 super(`Lease lost for run ${runId}: ${detail}`);25 }26}2728export type BudgetReason = 'run_budget' | 'mission_budget' | 'daily_cap';29/** Thrown by ctx.step for model_call steps once the budget is exhausted. Journaled, so replay rethrows it. */30export class BudgetExhaustedError extends KernelError {31 constructor(readonly reason: BudgetReason, message?: string) {32 super(message ?? `Budget exhausted (${reason})`);33 }34}3536/** A step whose exec threw. Identical on first execution and on replay (rebuilt from the journal). */37export class StepError extends KernelError {38 readonly stepSeq: number;39 readonly stepName: string;40 readonly errorName: string;41 readonly code: string | number | null;42 readonly status: number | null;43 readonly retryable: boolean | null;44 constructor(seq: number, stepName: string, e: RecordedError) {45 super(e.message);46 this.stepSeq = seq;47 this.stepName = stepName;48 this.errorName = e.name;49 this.code = e.code ?? null;50 this.status = e.status ?? null;51 this.retryable = e.retryable ?? null;52 }53}5455/** The kernel could not read/write its own state (database unavailable…). The run is left resumable. */56export class KernelStorageError extends KernelError {}5758export class WaitNotFoundError extends KernelError {}5960/** What is stored in steps.error. Never contains stacks or request bodies. */61export interface RecordedError {62 name: string;63 message: string;64 code?: string | number;65 status?: number;66 retryable?: boolean;67 reason?: string;68}6970export function recordError(err: unknown): RecordedError {71 if (!(err instanceof Error)) return { name: 'Error', message: String(err).slice(0, 4000) };72 const e = err as Error & { code?: unknown; status?: unknown; retryable?: unknown };73 const out: RecordedError = { name: e.name || 'Error', message: String(e.message ?? '').slice(0, 4000) };74 if (typeof e.code === 'string' || typeof e.code === 'number') out.code = e.code;75 if (typeof e.status === 'number') out.status = e.status;76 if (typeof e.retryable === 'boolean') out.retryable = e.retryable;77 return out;78}7980// ------------------------------------------------------------------------------------------81// Internal control flow (exported for the kernel's own modules and tests; never caught by logic).8283/** The run was suspended (durable wait / timer): the lease is released, the logic must unwind. */84export class Suspend extends KernelError {85 constructor() {86 super('run suspended (durable wait)');87 }88}89export class RunCancelled extends KernelError {90 constructor() {91 super('run cancelled');92 }93}94export class WorkerStopping extends KernelError {95 constructor() {96 super('worker stopping');97 }98}99export class ReconcileAborted extends KernelError {100 constructor(readonly seq: number, readonly stepName: string) {101 super(`Aborted by the owner while reconciling step ${seq} (${stepName})`);102 }103}104105/**106 * True for the errors that end the current execution of a run (suspension, cancel, shutdown, lost107 * lease, storage failure, reconcile abort). Run logic with a broad `catch` should rethrow these; if108 * it does not, the context stays closed and the kernel still settles the run correctly.109 */110export function isControlError(e: unknown): boolean {111 return (112 e instanceof Suspend ||113 e instanceof RunCancelled ||114 e instanceof WorkerStopping ||115 e instanceof LeaseLostError ||116 e instanceof KernelStorageError ||117 e instanceof ReconcileAborted118 );119}120