/**
 * WorkflowRuntime — the automation data-routing driver (M2; plan §M2, spec §A1/§A5).
 *
 * Responsibilities (control/data separation, spec §A1):
 *   - DagScheduler v2 owns CONTROL (ready/skip/loop/ports). The runtime owns DATA:
 *     for each ready node it collects upstream outputs along data edges (fromPort→toPort),
 *     resolves param expressions, invokes the registered NodeExecutor, stores outputs, and
 *     reports completion + firedPorts back to the scheduler.
 *   - run-from-node + output cache (spec §A5): cache key = hash(kind + resolved params +
 *     input signature + runIndex). A clean node hits cache (executor skipped); a changed node
 *     and its dirty downstream recompute. This is content-addressed, so successive run() calls
 *     after a param change recompute only the dirty subgraph.
 *   - loop control is runtime-owned (DagScheduler.decideLoop), not a user executor.
 *   - every node passes an injectable budget/permission gate before executing (plan D15).
 *
 * fail-loud: unknown kinds, gate rejections, and executor errors all throw and halt the run.
 */
import { DagScheduler } from "../dag-scheduler.js";
import { type PortMap } from "./data-item.js";
import { NodeRegistry } from "./node-registry.js";
import type { RunCheckpoint } from "./run-checkpoint-store.js";
import type { WorkflowDef, ExecutorHost } from "./node-schema.js";
/** Gate invoked before each node executes (budget / permission). Throw to halt the run. */
export interface ExecutionGate {
    check(nodeId: string, kind: string): void;
    /**
     * Optionally raise the gate's remaining allowance so a budget-paused run can resume (D15
     * "抬预算后 resume"). Gates without a budget may omit this. Implementations are fail-loud on
     * non-positive deltas.
     */
    extend?(delta: {
        executions?: number;
        durationMs?: number;
    }): void;
}
/**
 * Thrown by a gate (or `pause()`) to suspend the run gracefully. Unlike a plain error this is
 * not a failure: completed work stays cached, and a later `run()` on the same instance resumes
 * (cached nodes hit, only the not-yet-run remainder executes).
 */
export declare class WorkflowPauseSignal extends Error {
    readonly atNodeId?: string | undefined;
    constructor(atNodeId?: string | undefined);
}
/** Controlled cancellation requested by the controller/delete path. */
export declare class WorkflowRunCanceled extends Error {
    constructor(message?: string);
}
/** Per-node execution stats for the run trace (D33, IT-9). */
export interface NodeRunStats {
    /** Execution order (1-based; cache hits count too — they advance the dag). */
    seq: number;
    startedAt: string;
    finishedAt: string;
    durationMs: number;
    /** Executor attempts actually made (≥1; >1 means retries happened). */
    attempts: number;
    /** True when the content-addressed cache satisfied this node (no executor invocation). */
    cacheHit: boolean;
    /** Final per-node disposition (errorPort/continue keep the run alive but mark failed). */
    status: "completed" | "failed";
}
export interface RunResult {
    status: "completed" | "failed" | "paused";
    /** nodeId → its output PortMap. */
    outputs: Record<string, PortMap>;
    /** nodeIds whose executor actually ran in this run (cache misses). */
    executed: Set<string>;
    progress: ReturnType<DagScheduler["getProgress"]>;
    /** Set when status === "paused": the node the run suspended at. */
    pausedAt?: string;
    /** Ordered per-node trace (D33): timing, attempts, cache hits, disposition. */
    nodeStats: Record<string, NodeRunStats>;
}
export interface WorkflowRuntimeOptions {
    registry?: NodeRegistry;
    gate?: ExecutionGate;
    now?: () => Date;
    trigger?: Record<string, unknown>;
    /** This run's trigger KIND (manual/schedule/…) — exposed on ExecutorContext for IT-7b audits. */
    triggerKind?: string;
    log?: {
        info(m: string): void;
        warn(m: string): void;
    };
    /** Host capabilities for host-backed kinds (agent/tool/http/mcp/channel), D13. */
    host?: ExecutorHost;
    /** Cancellation propagated to host calls. */
    signal?: AbortSignal;
    /** Durable run checkpoint for crash-restart recovery (plan §M3). */
    checkpoint?: RunCheckpoint;
    /**
     * R5 跨 run 缓存(reuseCache):完成后不清 checkpoint 而是整表回写 —— 同一工作流的
     * 下一个 run seed 它,未变节点(同 kind+params+inputs 签名)命中跳过(ComfyUI 语义)。
     * 默认 false = 既有崩溃恢复语义(完成即清)。
     */
    preserveCheckpoint?: boolean;
    /** Per-node lifecycle callback for live status (canvas coloring). Fire-and-forget, not durable. */
    onNodeStatus?: (nodeId: string, status: "running" | "completed" | "failed") => void;
}
export declare class WorkflowRuntime {
    private def;
    private readonly registry;
    private readonly gate?;
    private readonly now;
    private readonly trigger?;
    private readonly triggerKind?;
    private readonly log?;
    private readonly host?;
    private readonly abortController?;
    private readonly signal;
    private readonly checkpoint?;
    private readonly preserveCheckpoint;
    private readonly onNodeStatus?;
    private dag;
    private readonly nodeDefs;
    private readonly nodeOutputs;
    /** Content-addressed output cache; persists across run() calls for run-from-node. */
    private readonly cache;
    /** loopBack source nodeId → loop controller nodeId. */
    private readonly loopBackOf;
    /** Cooperative pause request; honored before the next node executes. */
    private pauseRequested;
    /** Per-node trace (D33): seq/timing/attempts/cacheHit/disposition, keyed by nodeId. */
    private readonly nodeStats;
    private statsSeq;
    /** True once the durable checkpoint has been loaded into `cache` (load once per instance). */
    private checkpointLoaded;
    constructor(def: WorkflowDef, opts?: WorkflowRuntimeOptions);
    /** Patch a node's params (for run-from-node param changes). Invalidates nothing directly —
     * the content-addressed cache recomputes only what changed. */
    setNodeParams(nodeId: string, params: Record<string, unknown>): void;
    /** Request a cooperative pause: the in-flight run suspends before the next node executes. */
    pause(): void;
    /** Cancel the run and abort the signal exposed to long-running executors. */
    cancel(reason?: string): void;
    /**
     * Raise the budget gate's remaining allowance so a budget-paused run can resume (D15
     * "抬预算后 resume"). fail-loud if this runtime was built without an extensible budget gate.
     */
    extendBudget(delta: {
        executions?: number;
        durationMs?: number;
    }): void;
    /** Execute the workflow to completion (or until the gate halts / a branch fails / a pause). */
    run(): Promise<RunResult>;
    /**
     * Seed the content-addressed cache from a durable checkpoint (once per instance). After a
     * crash-restart a fresh runtime replays the DAG; nodes that completed before the crash hit
     * these entries and their executors are not re-invoked (no duplicate side effects).
     */
    private loadCheckpoint;
    /** Persist the full content-addressed cache so a crash mid-run can resume from here. */
    private persistCheckpoint;
    private executeNode;
    /** Loop entry: fire the "loop" port once to kick the first iteration. */
    private enterLoop;
    private decideLoopBack;
    /** Loop again? No condition → loop until the scheduler's maxIterations cap. */
    private evalLoopCondition;
    /** Collect inputs for a node from completed upstream outputs along forward data edges. */
    private collectInputs;
    private buildExprContext;
    private cacheKey;
    private isCanceled;
    private canceledError;
    private throwIfCanceled;
    /** Cancel-aware sleep for retry backoff: aborts immediately when the run is canceled. */
    private cancellableDelay;
    private buildDag;
}
