import * as smoltalk from "smoltalk"; import { Checkpoint } from "./state/checkpointStore.js"; import { RuntimeContext } from "./state/context.js"; import { GlobalStoreJSON } from "./state/globalStore.js"; import { StateStack, StateStackJSON } from "./state/stateStack.js"; import { Approved, GraphState, Rejected, RunNodeResult } from "./types.js"; import type { HandlerEntry } from "./types.js"; export type InterruptApprove = { type: "approve"; }; export type InterruptReject = { type: "reject"; }; export type InterruptResponse = InterruptApprove | InterruptReject; export declare function approve(value?: any): InterruptResponse; export declare function reject(value?: any): InterruptResponse; /** Explicit "not my interrupt — ask the next handler." Identical in effect * to a handler returning nothing, but usable in value position (a match * arm must produce a value). Returning `undefined` keeps working; the * chain normalizes it to this shape at the boundary. */ export declare function pass(): InterruptResponse; export type InterruptData = { messages?: smoltalk.MessageJSON[]; toolCall?: smoltalk.ToolCallJSON; }; export type InterruptState = { stack: StateStackJSON; globals: GlobalStoreJSON; }; export type Interrupt = { type: "interrupt"; effect: string; message: string; origin: string; interruptId: string; data: T; debugger?: boolean; interruptData?: InterruptData; checkpointId?: number; checkpoint?: Checkpoint; state?: InterruptState; runId: string; expectsValue?: boolean; }; export declare function interrupt(opts: { effect: string; message: string; data: T; origin: string; runId: string; interruptId?: string; expectsValue?: boolean; }): Interrupt; export declare function createDebugInterrupt(data: T, checkpointId: number, checkpoint: Checkpoint, runId: string): Interrupt; export declare function isInterrupt(obj: any): obj is Interrupt; export declare function hasInterrupts(data: any): data is Interrupt[]; /** * Called from the generated CLI bootstrap (the `argv[1] === import.meta.url` * block) AFTER a top-level node returns. When a node is run directly from the * command line and produces an interrupt that no handler caught, the interrupt * comes back as an `Interrupt[]` in `result.data` — and the bootstrap would * otherwise just exit silently, leaving the user with no output and no clue. * * This prints a helpful message pointing at the handlers guide and exits * non-zero. It only runs on direct CLI execution: when the compiled module is * imported and the node is called from TypeScript, the bootstrap guard is false * and this is never reached — there, the caller is expected to inspect * `result.data` / `respondToInterrupts` itself, so a returned interrupt is fine. */ export declare function reportUnhandledInterrupts(result: RunNodeResult): void; export declare function isDebugger(obj: any): obj is Interrupt; export declare function isRejected(obj: any): obj is Rejected; export declare function isApproved(obj: any): obj is Approved; export type HandlerChainOutcome = { kind: "rejected"; value: any; } | { kind: "approved"; value: any; } | { kind: "propagated"; } | { kind: "noResponse"; }; /** The interrupt fields visible to handlers and relayed between processes: * everything identifying WHAT is being decided, without the per-dispatch * bookkeeping (ids, checkpoints) the origin process owns. */ export type InterruptInfo = { effect: string; message: string; data: any; origin: string; expectsValue?: boolean; }; /** Merge two chain-segment outcomes with single-process precedence: * reject > propagate > approve > noResponse. `inner` is the segment closer * to the interrupt (e.g. the child process), `outer` the segment farther * from it (e.g. the parent). A double-approve merges through the EFFECT's * approval merge (effectMerge.ts) — std::guard grants accumulate; every * other effect keeps the historical IPC default, where the outer value * wins but a VALUELESS outer approve defers to the inner value (the * outcome travels as JSON, which cannot distinguish an absent value from * an explicit undefined). */ export declare function mergeChainOutcomes(effect: string, inner: HandlerChainOutcome, outer: HandlerChainOutcome): HandlerChainOutcome; /** The distributed handler chain, evaluated from this process outward: * run the local chain; local reject is final (fail-fast, matching the * single-process short-circuit); otherwise, if this process is itself a * subprocess, consult the parent and merge. Nested subprocesses recurse * through this same function on each hop. * * `interruptId`: the interrupt's id — the CHILD's id when relaying, or the * freshly-minted one at the origin dispatch — so every process's * handlerDecision/interruptResolved statelog events correlate with the * originating interrupt (ids are preserved verbatim end-to-end). * * `parentDecided` lets the origin caller (`interruptWithHandlers`) * attribute the verdict: it distinguishes a verdict the parent hop actually * participated in from one settled purely by local handlers (the * `resolvedBy: "ipc" | "handler"` tag). Neither this function nor * `runHandlerChain` emits terminal statelog events — the origin's * `renderVerdict` is the sole emitter, so relay hops (a parent process * evaluating a child's interrupt) contribute only handlerDecision events * to the shared trace. */ export declare function gatherChainOutcome(interruptObj: InterruptInfo, ctx: RuntimeContext, stack: StateStack | undefined, interruptId: string, eligible?: (entry: HandlerEntry) => boolean): Promise<{ outcome: HandlerChainOutcome; parentDecided: boolean; }>; export declare function interruptWithHandlers(effect: string, message: string, data: T, origin: string, ctx: RuntimeContext, stack?: StateStack, opts?: { expectsValue?: boolean; eligible?: (entry: HandlerEntry) => boolean; }): Promise[] | Approved | Rejected>; export declare function respondToInterrupts(args: { ctx: RuntimeContext; interrupts: Interrupt[]; responses: InterruptResponse[]; overrides?: Record; metadata?: Record; }): Promise;