diff --git a/packages/engine/src/index.ts b/packages/engine/src/index.ts index 0bdebab..0f216c9 100644 --- a/packages/engine/src/index.ts +++ b/packages/engine/src/index.ts @@ -34,6 +34,15 @@ export type { RulesTestResult, } from './rules/index.js' +// Walker (new execution types — will replace runner types in PR 1b) +export type { + ExecutionContext as WalkerExecutionContext, + NodeExecutionRecord, + WalkerCallbacks, + WalkOptions, + WalkResult, +} from './walker/index.js' + // Codegen export { generateCode } from './codegen/index.js' export type { GenerateResult, GenerateOptions, GeneratedFile } from './codegen/index.js' diff --git a/packages/engine/src/walker/index.ts b/packages/engine/src/walker/index.ts new file mode 100644 index 0000000..e86c2e4 --- /dev/null +++ b/packages/engine/src/walker/index.ts @@ -0,0 +1,7 @@ +export type { + ExecutionContext, + NodeExecutionRecord, + WalkerCallbacks, + WalkOptions, + WalkResult, +} from './types.js' diff --git a/packages/engine/src/walker/types.ts b/packages/engine/src/walker/types.ts new file mode 100644 index 0000000..07cf331 --- /dev/null +++ b/packages/engine/src/walker/types.ts @@ -0,0 +1,82 @@ +import type { + ActionNode, + SwitchNode, + ParallelNode, + WaitNode, + ErrorNode, + TerminalNode, + TriggerNode, +} from '@ruminaider/flowprint-schema' + +/** + * Context passed to each node handler during graph execution. + * Created fresh for each execute() call. + */ +export interface ExecutionContext { + /** Original flow input. Treated as immutable during execution. */ + readonly input: Record + /** Accumulated state from prior nodes. Flat-merged after each node. */ + state: Record + /** Metadata about the currently executing node. */ + readonly node: { + readonly id: string + readonly type: string + readonly lane: string + } + /** Cancellation/timeout signal. Handlers should check signal.aborted. */ + readonly signal: AbortSignal +} + +/** + * Delta-only trace record for a single node execution. + * Stores what the node produced, not a full state snapshot. + */ +export interface NodeExecutionRecord { + nodeId: string + type: string + lane: string + startedAt: number + completedAt: number + /** What this node produced (delta). Full state reconstructable by replaying deltas. */ + output: Record + /** How this node was handled. */ + handler: 'expressions' | 'rules' | 'registered' | 'entry_point' | 'native' + /** Present only if the node errored. */ + error?: { message: string; stack?: string } +} + +/** + * Pluggable callbacks for the generic graph walker. + * TStep is generic so runner, simulator, and engine can each define their own step shape. + */ +export interface WalkerCallbacks { + onAction(nodeId: string, node: ActionNode, ctx: ExecutionContext): Promise + onSwitch(nodeId: string, node: SwitchNode, ctx: ExecutionContext): Promise + onParallel(nodeId: string, node: ParallelNode, ctx: ExecutionContext): Promise + onWait(nodeId: string, node: WaitNode, ctx: ExecutionContext): Promise + onError(nodeId: string, node: ErrorNode, ctx: ExecutionContext): Promise + onTrigger(nodeId: string, node: TriggerNode, ctx: ExecutionContext): Promise + onTerminal?(nodeId: string, node: TerminalNode, ctx: ExecutionContext): Promise + /** Called after each node completes. Used for trace recording. */ + onStep(record: TStep): void +} + +/** + * Options for walkGraph. + */ +export interface WalkOptions { + /** AbortController for the entire walk. */ + abortController?: AbortController +} + +/** + * Result of a complete graph walk. + */ +export interface WalkResult { + /** Final accumulated state after all nodes. */ + output: Record + /** Ordered list of step records. */ + trace: TStep[] + /** Terminal node outcome if reached. */ + outcome?: 'success' | 'failure' +}