/** Scalar values stored in a decision graph blackboard. */ export type BlackboardValue = number | boolean | string; /** Named facts available to conditions, utilities, and actions. */ export type Blackboard = Record; /** Comparison operators supported by decision conditions. */ export type DecisionOperator = "=" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "eq" | "ne" | "lt" | "lte" | "gt" | "gte"; /** * Serializable decision node. * - `selector` runs children in order until one does not fail; `sequence` until one does not finish. * With `memory`, a composite whose child was running last tick resumes at that child instead of re-checking earlier ones. * - `condition` compares a blackboard key; `action` calls a registered action. * - `utility` runs the option with the highest weighted blackboard score. * - `invert` swaps `done` and `failed`; `cooldown` fails for `seconds` after its child finishes; * `wait` stays running for `seconds`; `random` picks a child by `weights` from the runtime's `rng` and keeps it while it runs. */ export type DecisionNode = { kind: "selector"; children: DecisionNode[]; memory?: boolean; } | { kind: "sequence"; children: DecisionNode[]; memory?: boolean; } | { kind: "condition"; key: string; op: DecisionOperator; value: BlackboardValue; } | { kind: "action"; action: string; params?: Record; } | { kind: "utility"; options: { score: { key: string; weight: number; }[]; node: DecisionNode; }[]; } | { kind: "invert"; child: DecisionNode; } | { kind: "cooldown"; seconds: number; child: DecisionNode; } | { kind: "wait"; seconds: number; } | { kind: "random"; children: DecisionNode[]; weights?: number[]; }; /** Root node for a serializable AI decision graph. */ export type DecisionGraph = DecisionNode; /** Outcome reported when a decision graph evaluates. */ export type DecisionStatus = "running" | "done" | "failed"; /** Callback implementation for an action node. */ export type DecisionAction = (ctx: Context, params: Record | undefined, blackboard: Blackboard) => DecisionStatus; /** Called when an action that was running last tick is not reached this tick, so it can release what it holds. */ export type DecisionAbort = (action: string, ctx: Context, params: Record | undefined, blackboard: Blackboard) => void; /** Optional hooks and injected randomness for {@link createDecisionGraphRuntime}. */ export interface DecisionGraphOptions { onAbort?: DecisionAbort; /** `[0, 1)` source for `random` nodes; pass `ctx.rng`. Required only when the graph has one. */ rng?: () => number; } /** Progress of a memory composite, `random` choice, or `wait` timer, keyed by node id (depth-first order). */ export interface DecisionNodeMemory { index: number; elapsed: number; tick: number; } /** Serializable state retained by an active decision graph. Fields besides `runningPath` are absent in older saves. */ export interface DecisionGraphSnapshot { runningPath: number[] | null; tick?: number; clock?: number; nodes?: Record; cooldowns?: Record; } /** Stateful evaluator for a serializable decision graph. */ export interface DecisionGraphRuntime { tick(ctx: Context, blackboard: Blackboard, dt: number): DecisionStatus; /** Name of the action left running by the last tick, or null. */ running(): string | null; /** Abort the compiled running action once, retaining graph memory/timers. Clears ownership before invoking user onAbort, even if it throws. */ abort(ctx: Context, blackboard: Blackboard): void; snapshot(): DecisionGraphSnapshot; restore(next: DecisionGraphSnapshot): void; } /** Creates a deterministic runtime for a serializable decision graph. * @capability ai-decision-graph Evaluate serializable selector, sequence, condition, action, utility, timer, and random AI decisions with interrupt hooks. */ export declare function createDecisionGraphRuntime(graph: DecisionGraph, actions: Record>, options?: DecisionGraphOptions): DecisionGraphRuntime;