@multiplier-labs/stepflow 0.3.4 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/{chunk-5XJBAPXF.js → chunk-4IDPWWGS.js} +15 -4
- package/dist/chunk-4IDPWWGS.js.map +1 -0
- package/dist/{chunk-U3PCVK6O.js → chunk-T6GAZBTQ.js} +70 -38
- package/dist/chunk-T6GAZBTQ.js.map +1 -0
- package/dist/{chunk-FMPJBK2N.js → chunk-TVSADUYU.js} +3 -5
- package/dist/{chunk-FMPJBK2N.js.map → chunk-TVSADUYU.js.map} +1 -1
- package/dist/events/index.d.ts +43 -3
- package/dist/events/index.js +7 -3
- package/dist/{index-Cd0IZ40L.d.ts → index-CdXDv30T.d.ts} +10 -2
- package/dist/index.d.ts +5 -4
- package/dist/index.js +159 -46
- package/dist/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +2 -2
- package/dist/scheduler/index.js +1 -1
- package/dist/storage/index.d.ts +6 -4
- package/dist/storage/index.js +1 -1
- package/dist/{types-DSEjiLMj.d.ts → types-BfWe5yP6.d.ts} +2 -0
- package/package.json +26 -14
- package/.codekin/reports/code-review/2026-04-11_code-review-daily.md +0 -146
- package/.codekin/reports/code-review/2026-04-13_code-review-daily.md +0 -74
- package/.codekin/reports/comments/2026-04-04_comment-assessment.md +0 -179
- package/.codekin/reports/comments/2026-04-11_comment-assessment.md +0 -161
- package/.codekin/reports/comments/2026-04-14_comment-assessment.md +0 -34
- package/.codekin/reports/complexity/2026-04-03_complexity-report.md +0 -152
- package/.codekin/reports/complexity/2026-04-11_complexity-report.md +0 -152
- package/.codekin/reports/complexity/2026-04-14_complexity-report.md +0 -34
- package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +0 -94
- package/.codekin/reports/dependencies/2026-04-11_dependency-health.md +0 -93
- package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +0 -10
- package/.codekin/reports/docs-audit/2026-04-11_docs-audit.md +0 -138
- package/.codekin/reports/docs-audit/2026-04-13_docs-audit.md +0 -121
- package/.codekin/reports/security/2026-04-03_security-audit.md +0 -208
- package/.codekin/reports/security/2026-04-11_security-audit.md +0 -297
- package/.github/CODEOWNERS +0 -15
- package/.github/dependabot.yml +0 -23
- package/.github/workflows/ci.yml +0 -38
- package/.github/workflows/publish.yml +0 -42
- package/.github/workflows/security.yml +0 -29
- package/CHANGELOG.md +0 -34
- package/SECURITY.md +0 -40
- package/dist/chunk-5XJBAPXF.js.map +0 -1
- package/dist/chunk-U3PCVK6O.js.map +0 -1
- package/docs/github-packages-setup.md +0 -97
- package/docs/stepflow-api-reference.md +0 -1663
- package/src/core/engine/concurrency.ts +0 -229
- package/src/core/engine/lifecycle.ts +0 -176
- package/src/core/engine.test.ts +0 -1435
- package/src/core/engine.ts +0 -598
- package/src/core/index.ts +0 -7
- package/src/core/orchestrator/persistence.ts +0 -165
- package/src/core/orchestrator/plan-resolution.ts +0 -140
- package/src/core/orchestrator/state-transitions.ts +0 -109
- package/src/core/orchestrator/step-runner.ts +0 -427
- package/src/core/orchestrator.ts +0 -252
- package/src/core/types.ts +0 -220
- package/src/events/index.ts +0 -8
- package/src/events/memory.test.ts +0 -107
- package/src/events/memory.ts +0 -92
- package/src/events/socketio.test.ts +0 -378
- package/src/events/socketio.ts +0 -262
- package/src/events/types.ts +0 -118
- package/src/events/webhook.test.ts +0 -949
- package/src/events/webhook.ts +0 -807
- package/src/index.ts +0 -270
- package/src/planning/evaluate-condition.test.ts +0 -153
- package/src/planning/evaluate-condition.ts +0 -105
- package/src/planning/index.ts +0 -55
- package/src/planning/planner.ts +0 -494
- package/src/planning/planning.test.ts +0 -727
- package/src/planning/registry.test.ts +0 -398
- package/src/planning/registry.ts +0 -283
- package/src/planning/types.ts +0 -566
- package/src/scheduler/cron.test.ts +0 -479
- package/src/scheduler/cron.ts +0 -438
- package/src/scheduler/index.ts +0 -8
- package/src/scheduler/postgres-persistence.ts +0 -530
- package/src/scheduler/sqlite-persistence.test.ts +0 -235
- package/src/scheduler/sqlite-persistence.ts +0 -286
- package/src/scheduler/types.ts +0 -73
- package/src/storage/index.ts +0 -27
- package/src/storage/memory.test.ts +0 -349
- package/src/storage/memory.ts +0 -227
- package/src/storage/postgres-core.ts +0 -550
- package/src/storage/postgres-migration.test.ts +0 -69
- package/src/storage/postgres-transaction-pagination.test.ts +0 -107
- package/src/storage/postgres.ts +0 -835
- package/src/storage/sqlite-core.ts +0 -151
- package/src/storage/sqlite.test.ts +0 -642
- package/src/storage/sqlite.ts +0 -717
- package/src/storage/types.ts +0 -343
- package/src/utils/errors.test.ts +0 -150
- package/src/utils/errors.ts +0 -161
- package/src/utils/id.ts +0 -21
- package/src/utils/index.ts +0 -10
- package/src/utils/logger.test.ts +0 -121
- package/src/utils/logger.ts +0 -96
- package/src/utils/pinned-fetch.test.ts +0 -84
- package/src/utils/pinned-fetch.ts +0 -118
- package/src/utils/postgres-deps.ts +0 -79
- package/src/utils/retry.test.ts +0 -177
- package/src/utils/retry.ts +0 -121
- package/src/utils/safe-json.test.ts +0 -166
- package/src/utils/safe-json.ts +0 -107
- package/src/utils/webhook-signature.test.ts +0 -111
- package/src/utils/webhook-signature.ts +0 -74
- package/tsconfig.json +0 -21
- package/tsup.config.ts +0 -14
- package/vitest.config.ts +0 -9
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/errors.ts","../src/core/orchestrator/persistence.ts","../src/core/orchestrator/state-transitions.ts","../src/utils/retry.ts","../src/core/orchestrator/step-runner.ts","../src/core/orchestrator/plan-resolution.ts","../src/core/orchestrator.ts","../src/core/engine/concurrency.ts","../src/core/engine/lifecycle.ts","../src/core/engine.ts","../src/planning/evaluate-condition.ts","../src/planning/registry.ts","../src/planning/planner.ts"],"sourcesContent":["/**\n * Custom error classes for the workflow engine.\n */\n\nimport type { WorkflowError } from '../core/types';\n\n/**\n * Base error class for workflow-related errors.\n */\nexport class WorkflowEngineError extends Error {\n readonly code: string;\n readonly details?: Record<string, unknown>;\n\n constructor(code: string, message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'WorkflowEngineError';\n this.code = code;\n this.details = details;\n }\n\n /**\n * Convert to a WorkflowError record for storage.\n */\n toRecord(): WorkflowError {\n return {\n code: this.code,\n message: this.message,\n details: this.details,\n };\n }\n\n /**\n * Create a WorkflowError record from any error.\n */\n static fromError(error: unknown, defaultCode = 'UNKNOWN_ERROR'): WorkflowError {\n if (error instanceof WorkflowEngineError) {\n return error.toRecord();\n }\n\n if (error instanceof Error) {\n return {\n code: defaultCode,\n message: error.message,\n };\n }\n\n return {\n code: defaultCode,\n message: String(error),\n };\n }\n}\n\n/**\n * Error thrown when a workflow is not found in the registry.\n */\nexport class WorkflowNotFoundError extends WorkflowEngineError {\n constructor(kind: string) {\n super('WORKFLOW_NOT_FOUND', `Workflow \"${kind}\" is not registered`, { kind });\n this.name = 'WorkflowNotFoundError';\n }\n}\n\n/**\n * Error thrown when a workflow is already registered.\n */\nexport class WorkflowAlreadyRegisteredError extends WorkflowEngineError {\n constructor(kind: string) {\n super('WORKFLOW_ALREADY_REGISTERED', `Workflow \"${kind}\" is already registered`, { kind });\n this.name = 'WorkflowAlreadyRegisteredError';\n }\n}\n\n/**\n * Error thrown when a run is not found.\n */\nexport class RunNotFoundError extends WorkflowEngineError {\n constructor(runId: string) {\n super('RUN_NOT_FOUND', `Run \"${runId}\" not found`, { runId });\n this.name = 'RunNotFoundError';\n }\n}\n\n/**\n * Error thrown when a step fails.\n */\nexport class StepError extends WorkflowEngineError {\n readonly stepKey: string;\n readonly attempt: number;\n readonly cause?: Error;\n\n constructor(stepKey: string, message: string, attempt: number, cause?: Error) {\n super('STEP_ERROR', message, { stepKey, attempt });\n this.name = 'StepError';\n this.stepKey = stepKey;\n this.attempt = attempt;\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when a step times out.\n */\nexport class StepTimeoutError extends WorkflowEngineError {\n readonly stepKey: string;\n readonly timeoutMs: number;\n\n constructor(stepKey: string, timeoutMs: number) {\n super('STEP_TIMEOUT', `Step \"${stepKey}\" timed out after ${timeoutMs}ms`, {\n stepKey,\n timeoutMs,\n });\n this.name = 'StepTimeoutError';\n this.stepKey = stepKey;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when a workflow is canceled.\n */\nexport class WorkflowCanceledError extends WorkflowEngineError {\n constructor(runId: string) {\n super('WORKFLOW_CANCELED', `Workflow run \"${runId}\" was canceled`, { runId });\n this.name = 'WorkflowCanceledError';\n }\n}\n\n/**\n * Error thrown when waitForRun times out polling for a terminal status.\n */\nexport class WaitForRunTimeoutError extends WorkflowEngineError {\n readonly runId: string;\n readonly timeoutMs: number;\n\n constructor(runId: string, timeoutMs: number) {\n super('WAIT_FOR_RUN_TIMEOUT', `Timeout waiting for run ${runId} after ${timeoutMs}ms`, {\n runId,\n timeoutMs,\n });\n this.name = 'WaitForRunTimeoutError';\n this.runId = runId;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when a workflow times out.\n */\nexport class WorkflowTimeoutError extends WorkflowEngineError {\n readonly timeoutMs: number;\n\n constructor(runId: string, timeoutMs: number) {\n super('WORKFLOW_TIMEOUT', `Workflow run \"${runId}\" timed out after ${timeoutMs}ms`, {\n runId,\n timeoutMs,\n });\n this.name = 'WorkflowTimeoutError';\n this.timeoutMs = timeoutMs;\n }\n}\n","/**\n * Orchestrator persistence layer.\n *\n * Wraps the storage adapter and event transport with intent-named helpers\n * so the orchestrator and step-runner can stay focused on control flow\n * instead of repeating field shapes for every status transition.\n *\n * All side-effect calls the orchestrator makes against storage or the event\n * transport flow through this module — keeping the rest of the pipeline\n * pure(-ish) and easy to read.\n */\nimport type { StorageAdapter, WorkflowRunStepRecord } from '../../storage/types';\nimport type { EventTransport, WorkflowEvent } from '../../events/types';\nimport type { Logger, WorkflowError } from '../types';\nimport { WorkflowEngineError } from '../../utils/errors';\n\n/**\n * Mark the run as running. On a fresh start, also stamp `startedAt`;\n * on resume, leave the original `startedAt` alone.\n */\nexport async function markRunRunning(\n storage: StorageAdapter,\n runId: string,\n isResume: boolean\n): Promise<void> {\n await storage.updateRun(runId, {\n status: 'running',\n ...(isResume ? {} : { startedAt: new Date() }),\n });\n}\n\n/**\n * Persist the workflow checkpoint after a step completes:\n * the accumulated step results plus the list of completed step keys.\n */\nexport async function saveCheckpoint(\n storage: StorageAdapter,\n runId: string,\n results: Record<string, unknown>,\n completedSteps: string[]\n): Promise<void> {\n await storage.updateRun(runId, {\n context: { ...results },\n completedSteps: [...completedSteps],\n });\n}\n\n/**\n * Mark the run as succeeded, persisting results and finishedAt.\n */\nexport async function markRunSucceeded(\n storage: StorageAdapter,\n runId: string,\n results: Record<string, unknown>\n): Promise<void> {\n await storage.updateRun(runId, {\n status: 'succeeded',\n context: results,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Persist a non-success terminal state for the run (failed / canceled / timeout).\n * `status` is the storage-level status — the orchestrator decides this from the\n * raised error using `state-transitions.ts`.\n */\nexport async function markRunFinal(\n storage: StorageAdapter,\n runId: string,\n status: 'failed' | 'canceled',\n results: Record<string, unknown>,\n error: WorkflowError\n): Promise<void> {\n await storage.updateRun(runId, {\n status,\n context: results,\n error,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Create a fresh step record in 'running' state for the given attempt.\n * Returns the persisted record so the caller can read its generated id.\n */\nexport async function createStepRecord(\n storage: StorageAdapter,\n runId: string,\n stepKey: string,\n stepName: string,\n attempt: number\n): Promise<WorkflowRunStepRecord> {\n return storage.createStep({\n runId,\n stepKey,\n stepName,\n status: 'running',\n attempt,\n startedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as succeeded, recording its result and finishedAt.\n */\nexport async function markStepSucceeded(\n storage: StorageAdapter,\n stepId: string,\n result: unknown\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: 'succeeded',\n result,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as failed (or canceled, if the abort signal already fired)\n * with the normalized engine error attached.\n */\nexport async function markStepFailed(\n storage: StorageAdapter,\n stepId: string,\n error: unknown,\n isCanceled: boolean\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: isCanceled ? 'canceled' : 'failed',\n error: WorkflowEngineError.fromError(error),\n finishedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as canceled without an error payload — used when an in-flight\n * retry sleep is interrupted by an abort signal.\n */\nexport async function markStepCanceled(\n storage: StorageAdapter,\n stepId: string\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: 'canceled',\n finishedAt: new Date(),\n });\n}\n\n/**\n * Emit a workflow event without ever throwing back into the caller.\n * Event emission failures are logged but never abort the workflow,\n * so a flaky transport can't take down a run.\n */\nexport function safeEmitEvent(\n events: EventTransport,\n logger: Logger,\n event: WorkflowEvent\n): void {\n try {\n events.emit(event);\n } catch (error) {\n logger.error('Failed to emit event:', error);\n }\n}\n","/**\n * Pure state-transition decisions for the orchestrator.\n *\n * Every function in here is deterministic and side-effect-free: given\n * the current shape of an event, error, or step config they return what\n * the next state should be. The orchestrator and step-runner read these\n * decisions and apply them via persistence helpers.\n *\n * State-transition rules captured here:\n *\n * Run terminal status:\n * - WorkflowTimeoutError → status='failed', eventType='run.timeout'\n * - WorkflowCanceledError → status='canceled', eventType='run.canceled'\n * - any other error → status='failed', eventType='run.failed'\n *\n * Step error policy resolution (precedence):\n * - step.onError > definition.defaultOnError > 'fail'\n * - step.maxRetries > 3\n * - step.retryDelay (ms) > 1000\n * - step.retryBackoff (multiplier) > 2\n *\n * Step retry decision (after a non-cancellation failure):\n * - onError === 'skip' → 'skip'\n * - onError === 'retry' && attempt <= maxRetries → 'retry'\n * - otherwise (incl. retries exhausted, 'fail') → 'fail'\n */\nimport type { WorkflowDefinition, WorkflowStep } from '../types';\nimport { WorkflowCanceledError, WorkflowTimeoutError } from '../../utils/errors';\n\n/**\n * Storage-level statuses the orchestrator may persist for a non-success run.\n */\nexport type RunFinalStatus = 'failed' | 'canceled';\n\n/**\n * Event types emitted on a non-success run completion.\n */\nexport type RunFinalEventType = 'run.timeout' | 'run.canceled' | 'run.failed';\n\n/**\n * Result of mapping an error to a terminal run state.\n */\nexport interface RunFinalDecision {\n status: RunFinalStatus;\n eventType: RunFinalEventType;\n}\n\n/**\n * Map a thrown workflow error to the final run status + event type.\n * Note: a workflow timeout is persisted as `failed` for storage compatibility,\n * but the emitted event distinguishes it via `run.timeout`.\n */\nexport function decideRunFinalState(error: unknown): RunFinalDecision {\n if (error instanceof WorkflowTimeoutError) {\n return { status: 'failed', eventType: 'run.timeout' };\n }\n if (error instanceof WorkflowCanceledError) {\n return { status: 'canceled', eventType: 'run.canceled' };\n }\n return { status: 'failed', eventType: 'run.failed' };\n}\n\n/**\n * Step-level error policy resolved from a step + workflow definition.\n */\nexport interface StepErrorPolicy {\n onError: 'fail' | 'skip' | 'retry';\n maxRetries: number;\n retryDelay: number;\n retryBackoff: number;\n}\n\n/**\n * Resolve the effective error policy for a step.\n * Step-level config overrides workflow defaults; workflow defaults override\n * the engine defaults (`fail` / 3 / 1000ms / 2x).\n */\nexport function resolveStepErrorPolicy<TInput>(\n step: WorkflowStep<TInput>,\n definition: WorkflowDefinition<TInput>\n): StepErrorPolicy {\n return {\n onError: step.onError ?? definition.defaultOnError ?? 'fail',\n maxRetries: step.maxRetries ?? 3,\n retryDelay: step.retryDelay ?? 1000,\n retryBackoff: step.retryBackoff ?? 2,\n };\n}\n\n/**\n * Decision returned after a step attempt fails.\n *\n * - 'skip' : swallow the error and treat the step as a no-op (returns undefined)\n * - 'retry' : back off and try again\n * - 'fail' : escalate (StepError) and abort the workflow\n */\nexport type StepFailureAction = 'skip' | 'retry' | 'fail';\n\n/**\n * Decide what to do after a step attempt has failed (and was not canceled).\n */\nexport function decideStepFailureAction(\n policy: StepErrorPolicy,\n attempt: number\n): StepFailureAction {\n if (policy.onError === 'skip') return 'skip';\n if (policy.onError === 'retry' && attempt <= policy.maxRetries) return 'retry';\n return 'fail';\n}\n","/**\n * Retry utilities for the workflow engine.\n */\n\nimport { WorkflowCanceledError } from './errors';\n\n/**\n * Options for retry behavior.\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Initial delay between retries in ms (default: 1000) */\n delay: number;\n /** Backoff multiplier (default: 2) */\n backoff: number;\n /** Optional abort signal to cancel retries */\n signal?: AbortSignal;\n /** Optional callback before each retry */\n onRetry?: (attempt: number, error: Error, nextDelay: number) => void;\n}\n\n/**\n * Default retry options.\n */\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\n maxRetries: 3,\n delay: 1000,\n backoff: 2,\n};\n\n/**\n * Sleep for a given number of milliseconds.\n * Can be canceled via AbortSignal.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new WorkflowCanceledError('run'));\n return;\n }\n\n const cleanup = () => {\n clearTimeout(timeoutId);\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n };\n\n let onAbort: (() => void) | undefined;\n\n const timeoutId = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n\n if (signal) {\n onAbort = () => {\n cleanup();\n reject(new WorkflowCanceledError('run'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n}\n\n/**\n * Execute a function with retry logic.\n *\n * @param fn - The async function to execute\n * @param options - Retry configuration\n * @returns The result of the function\n * @throws The last error if all retries are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> = {}\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\n let lastError: Error | undefined;\n let currentDelay = opts.delay;\n\n for (let attempt = 1; attempt <= opts.maxRetries + 1; attempt++) {\n // Check if aborted before attempting\n if (opts.signal?.aborted) {\n throw new WorkflowCanceledError('run');\n }\n\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // If this was the last attempt, throw\n if (attempt > opts.maxRetries) {\n throw lastError;\n }\n\n // Call onRetry callback if provided\n opts.onRetry?.(attempt, lastError, currentDelay);\n\n // Wait before next attempt\n await sleep(currentDelay, opts.signal);\n\n // Apply backoff multiplier\n currentDelay = Math.round(currentDelay * opts.backoff);\n }\n }\n\n // This should never be reached, but TypeScript needs it\n throw lastError ?? new Error('Retry failed');\n}\n\n/**\n * Calculate the delay for a specific retry attempt.\n */\nexport function calculateRetryDelay(\n attempt: number,\n baseDelay: number,\n backoff: number\n): number {\n return Math.round(baseDelay * Math.pow(backoff, attempt - 1));\n}\n","/**\n * Step runner — executes a single workflow step with hooks, retries,\n * cancellation, and timeout handling.\n *\n * The shape of the previous monolithic `executeStep` was a `while (true)`\n * loop containing a `try`/`catch` with multiple nested `if` branches per\n * error path (cancel, hook, skip, retry, fail). This file flattens that:\n *\n * - Each error path is its own intent-named helper\n * (handleSkipAction, handleRetryAction, runOnStepErrorHook, etc.)\n * - The main loop nesting is at most 3 levels (while → try → switch)\n *\n * State-transition rules covered here (see also state-transitions.ts):\n *\n * pre-attempt:\n * - abort signal already raised → throw WorkflowCanceledError\n *\n * per-attempt:\n * - handler resolves → markStepSucceeded, emit step.completed, return\n * - handler rejects + canceled → markStepFailed(canceled), emit step.failed, rethrow\n * - handler rejects + policy=skip → emit step.skipped, return undefined\n * - handler rejects + policy=retry → emit step.retry, sleep, continue\n * - handler rejects + policy=fail → throw StepError\n */\nimport type {\n WorkflowDefinition,\n WorkflowStep,\n WorkflowContext,\n Logger,\n} from '../types';\nimport type { StorageAdapter, WorkflowRunStepRecord } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport {\n StepError,\n StepTimeoutError,\n WorkflowCanceledError,\n} from '../../utils/errors';\nimport { sleep, calculateRetryDelay } from '../../utils/retry';\nimport {\n createStepRecord,\n markStepSucceeded,\n markStepFailed,\n markStepCanceled,\n safeEmitEvent,\n} from './persistence';\nimport {\n resolveStepErrorPolicy,\n decideStepFailureAction,\n type StepErrorPolicy,\n} from './state-transitions';\n\n/**\n * Inputs to `executeStep` beyond the step + context themselves.\n */\nexport interface StepExecutionOptions<TInput = Record<string, unknown>> {\n definition: WorkflowDefinition<TInput>;\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n abortController: AbortController;\n}\n\n/**\n * Execute a single workflow step with error handling and retries.\n *\n * Returns the step's result on success, or `undefined` if the resolved\n * error policy is `skip` and the step failed. Throws on cancellation,\n * timeout, or `fail` policy.\n */\nexport async function executeStep<TInput>(\n step: WorkflowStep<TInput>,\n context: WorkflowContext<TInput>,\n options: StepExecutionOptions<TInput>\n): Promise<unknown> {\n const { definition, storage, events, logger, abortController } = options;\n const policy = resolveStepErrorPolicy(step, definition);\n\n let attempt = 0;\n\n while (true) {\n attempt++;\n throwIfCanceled(abortController, context.runId);\n\n const stepRecord = await beginStepAttempt(\n storage,\n events,\n logger,\n context,\n step,\n attempt\n );\n\n if (definition.hooks?.beforeStep) {\n await definition.hooks.beforeStep(context, step);\n }\n\n try {\n const result = await runStepHandler(step, context, abortController);\n await completeStepAttempt(\n storage,\n events,\n logger,\n stepRecord,\n context,\n step,\n result,\n definition\n );\n return result;\n } catch (error) {\n const lastError = toError(error);\n const isCanceled =\n error instanceof WorkflowCanceledError || abortController.signal.aborted;\n\n await markStepFailed(storage, stepRecord.id, error, isCanceled);\n\n if (isCanceled) {\n emitStepFailedEvent(events, logger, context, step, lastError, attempt);\n throw error;\n }\n\n await runOnStepErrorHook(definition, context, step, lastError, logger);\n emitStepFailedEvent(events, logger, context, step, lastError, attempt);\n\n const action = decideStepFailureAction(policy, attempt);\n\n if (action === 'skip') {\n handleSkipAction(events, logger, context, step, lastError);\n return undefined;\n }\n\n if (action === 'retry') {\n await handleRetryAction(\n storage,\n events,\n logger,\n abortController,\n context,\n step,\n attempt,\n policy,\n lastError,\n stepRecord.id\n );\n continue;\n }\n\n // action === 'fail' — explicit fail strategy or retries exhausted\n throw new StepError(step.key, lastError.message, attempt, lastError);\n }\n }\n}\n\n/**\n * Throw a WorkflowCanceledError if the abort signal has already been raised.\n * Called at the top of each attempt so we don't even create a step record\n * after cancellation.\n */\nfunction throwIfCanceled(abortController: AbortController, runId: string): void {\n if (abortController.signal.aborted) {\n throw new WorkflowCanceledError(runId);\n }\n}\n\n/**\n * Persist a fresh step record for this attempt, set it as the current step\n * id on the context (so handlers can attach granular telemetry), and emit\n * `step.started`.\n */\nasync function beginStepAttempt<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n attempt: number\n): Promise<WorkflowRunStepRecord> {\n const stepRecord = await createStepRecord(\n storage,\n context.runId,\n step.key,\n step.name,\n attempt\n );\n context.stepId = stepRecord.id;\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.started',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { attempt },\n });\n return stepRecord;\n}\n\n/**\n * Invoke the step handler. If the step has its own timeout, race against it\n * AND the abort signal; otherwise just race against the abort signal so a\n * workflow-level timeout/cancellation still interrupts the step.\n */\nasync function runStepHandler<TInput>(\n step: WorkflowStep<TInput>,\n context: WorkflowContext<TInput>,\n abortController: AbortController\n): Promise<unknown> {\n if (step.timeout) {\n return executeWithTimeout(\n () => step.handler(context),\n step.timeout,\n abortController.signal,\n step.key\n );\n }\n return raceWithAbort(step.handler(context), abortController.signal);\n}\n\n/**\n * Mark the step as succeeded, run the afterStep hook (if any), and emit\n * `step.completed`.\n */\nasync function completeStepAttempt<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n stepRecord: WorkflowRunStepRecord,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n result: unknown,\n definition: WorkflowDefinition<TInput>\n): Promise<void> {\n await markStepSucceeded(storage, stepRecord.id, result);\n if (definition.hooks?.afterStep) {\n await definition.hooks.afterStep(context, step, result);\n }\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.completed',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { result },\n });\n}\n\n/**\n * Coerce an unknown thrown value into a real Error, preserving message\n * text for non-Error throws.\n */\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Run the user's onStepError hook (if defined). Hook failures are logged\n * but never propagated — they must not mask the original step error.\n */\nasync function runOnStepErrorHook<TInput>(\n definition: WorkflowDefinition<TInput>,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error,\n logger: Logger\n): Promise<void> {\n if (!definition.hooks?.onStepError) return;\n try {\n await definition.hooks.onStepError(context, step, lastError);\n } catch (hookError) {\n logger.error('onStepError hook failed for run ' + context.runId + ':', hookError);\n }\n}\n\n/**\n * Emit a `step.failed` event with the canonical payload.\n */\nfunction emitStepFailedEvent<TInput>(\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error,\n attempt: number\n): void {\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.failed',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { error: lastError.message, attempt },\n });\n}\n\n/**\n * Apply the `skip` failure action: warn, emit `step.skipped`, then the\n * caller returns `undefined` from the step.\n */\nfunction handleSkipAction<TInput>(\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error\n): void {\n logger.warn(`Step \"${step.key}\" failed, skipping (strategy: skip)`);\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { reason: 'error', error: lastError.message },\n });\n}\n\n/**\n * Apply the `retry` failure action: emit `step.retry`, sleep with backoff,\n * and let the loop fall through to the next attempt. If the sleep itself\n * is interrupted by cancellation, mark the step record canceled before\n * rethrowing.\n */\nasync function handleRetryAction<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n abortController: AbortController,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n attempt: number,\n policy: StepErrorPolicy,\n lastError: Error,\n stepRecordId: string\n): Promise<void> {\n const delay = calculateRetryDelay(attempt, policy.retryDelay, policy.retryBackoff);\n logger.warn(\n `Step \"${step.key}\" failed, retrying in ${delay}ms (attempt ${attempt}/${policy.maxRetries})`\n );\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.retry',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { attempt, maxRetries: policy.maxRetries, delay, error: lastError.message },\n });\n\n try {\n await sleep(delay, abortController.signal);\n } catch (sleepError) {\n if (sleepError instanceof WorkflowCanceledError) {\n await markStepCanceled(storage, stepRecordId);\n }\n throw sleepError;\n }\n}\n\n/**\n * Execute a function with a timeout.\n *\n * Uses Promise.race to resolve as soon as either the function completes, the\n * timeout fires, or the abort signal triggers. The `finally` block is critical:\n * without it, the losing promise's timer/listener would remain active, leaking\n * memory — especially problematic in long-running engines processing many steps.\n */\nexport async function executeWithTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number,\n signal: AbortSignal,\n stepKey: string\n): Promise<T> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n try {\n return await Promise.race([\n fn(),\n new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new StepTimeoutError(stepKey, timeoutMs));\n }, timeoutMs);\n\n onAbort = () => {\n clearTimeout(timeoutId);\n reject(new WorkflowCanceledError('run'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]);\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n\n/**\n * Race a promise against an abort signal.\n *\n * Steps without their own timeout still need to respect workflow-level timeouts\n * and cancellation. This wraps the step handler in a Promise.race so that an\n * abort signal (from workflow timeout or user cancellation) can interrupt it.\n *\n * The `finally` cleanup removes the abort listener to prevent accumulating\n * listeners on the signal across many steps — without it, each step would\n * leave a dangling listener even after completing successfully.\n */\nexport async function raceWithAbort<T>(\n promise: Promise<T>,\n signal: AbortSignal\n): Promise<T> {\n if (signal.aborted) {\n throw new WorkflowCanceledError('run');\n }\n\n let onAbort: (() => void) | undefined;\n\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n onAbort = () => reject(new WorkflowCanceledError('run'));\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n","/**\n * Plan resolution — turns ExecuteOptions into the runtime artefacts\n * the orchestrator needs to start running steps.\n *\n * Today the engine has no separate planner module: the \"plan\" is just the\n * declarative WorkflowDefinition combined with the optional resume\n * checkpoint and the supplied input/metadata. This module is the seam\n * where, in the future, recipe/plan resolution and input validation can\n * grow without bloating execute-workflow.ts.\n *\n * Responsibilities:\n * 1. Build the WorkflowContext from the run options + checkpoint, with a\n * `context.emit` helper that routes through safeEmitEvent.\n * 2. Set up the workflow-level timeout: returns a handle the caller\n * clears in both the success and failure paths, and a getter for\n * the WorkflowTimeoutError that fired (so the catch block can\n * surface it instead of the abort-derived error).\n * 3. Compute the initial set of completed-step keys (used by the loop\n * to skip steps already done in a previous run).\n */\nimport type {\n WorkflowDefinition,\n WorkflowContext,\n Logger,\n SpawnChildOptions,\n} from '../types';\nimport type { EventTransport } from '../../events/types';\nimport { WorkflowTimeoutError } from '../../utils/errors';\nimport { createScopedLogger } from '../../utils/logger';\nimport { safeEmitEvent } from './persistence';\n\n/**\n * Inputs needed to resolve a workflow plan + build its execution context.\n */\nexport interface BuildContextOptions {\n runId: string;\n definition: WorkflowDefinition;\n input: Record<string, unknown>;\n metadata: Record<string, unknown>;\n events: EventTransport;\n logger: Logger;\n abortController: AbortController;\n spawnChild: (options: SpawnChildOptions) => Promise<string>;\n /** Existing checkpoint results to preload into context.results. */\n checkpointResults?: Record<string, unknown>;\n}\n\n/**\n * Build the WorkflowContext that will be threaded through every step\n * handler. On resume, preload `context.results` from the checkpoint.\n */\nexport function buildContext(options: BuildContextOptions): WorkflowContext {\n const {\n runId,\n definition,\n input,\n metadata,\n events,\n logger,\n abortController,\n spawnChild,\n checkpointResults,\n } = options;\n\n return {\n runId,\n stepId: '', // set per-step by the step-runner before each handler call\n kind: definition.kind,\n input,\n results: checkpointResults ? { ...checkpointResults } : {},\n metadata,\n logger: createScopedLogger(logger, runId),\n signal: abortController.signal,\n spawnChild,\n emit: (eventType: string, payload?: unknown) => {\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType,\n timestamp: new Date(),\n payload,\n });\n },\n };\n}\n\n/**\n * Handle returned by setupWorkflowTimeout. The orchestrator must call\n * `clear()` on both success and failure paths to release the timer, and\n * may read `getTimeoutError()` in the catch path: if non-null, the abort\n * was triggered by our timeout (not user cancellation), and the caller\n * should surface that error instead of the generic abort-derived one.\n */\nexport interface WorkflowTimeoutHandle {\n clear: () => void;\n getTimeoutError: () => WorkflowTimeoutError | undefined;\n}\n\n/**\n * Arm a workflow-level timeout if the definition specifies one.\n *\n * On fire: constructs a WorkflowTimeoutError (recoverable via\n * `getTimeoutError`) and aborts the controller, which causes any\n * in-flight step handler racing the abort signal to reject.\n *\n * If the definition has no timeout, returns no-op handles.\n */\nexport function setupWorkflowTimeout(\n runId: string,\n definition: WorkflowDefinition,\n abortController: AbortController\n): WorkflowTimeoutHandle {\n if (!definition.timeout) {\n return {\n clear: () => {},\n getTimeoutError: () => undefined,\n };\n }\n\n let timeoutError: WorkflowTimeoutError | undefined;\n const timeoutId = setTimeout(() => {\n timeoutError = new WorkflowTimeoutError(runId, definition.timeout!);\n abortController.abort();\n }, definition.timeout);\n\n return {\n clear: () => clearTimeout(timeoutId),\n getTimeoutError: () => timeoutError,\n };\n}\n\n/**\n * Initial list of step keys to consider already complete — empty for a\n * fresh run, the checkpoint's set for a resume.\n */\nexport function initialCompletedSteps(\n checkpoint?: { completedStepKeys: Set<string> }\n): string[] {\n return checkpoint ? Array.from(checkpoint.completedStepKeys) : [];\n}\n","/**\n * Workflow Orchestrator\n *\n * This module is the heart of the workflow execution system.\n * It manages the execution of workflow steps, handles errors,\n * emits events, and persists state.\n */\n\nimport type {\n WorkflowDefinition,\n RunResult,\n Logger,\n SpawnChildOptions,\n} from './types';\nimport type { StorageAdapter } from '../storage/types';\nimport type { EventTransport } from '../events/types';\nimport { WorkflowEngineError, WorkflowCanceledError } from '../utils/errors';\nimport {\n markRunRunning,\n saveCheckpoint,\n markRunSucceeded,\n markRunFinal,\n safeEmitEvent,\n} from './orchestrator/persistence';\nimport { decideRunFinalState } from './orchestrator/state-transitions';\nimport { executeStep } from './orchestrator/step-runner';\nimport {\n buildContext,\n setupWorkflowTimeout,\n initialCompletedSteps,\n} from './orchestrator/plan-resolution';\n\n/**\n * Checkpoint data for resuming workflows.\n */\nexport interface WorkflowCheckpoint {\n /** Set of step keys that have been completed */\n completedStepKeys: Set<string>;\n /** Accumulated results from completed steps */\n results: Record<string, unknown>;\n}\n\n/**\n * Options for executing a workflow.\n */\nexport interface ExecuteOptions {\n /** The run ID */\n runId: string;\n /** The workflow definition */\n definition: WorkflowDefinition;\n /** Input parameters */\n input: Record<string, unknown>;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n /** Storage adapter */\n storage: StorageAdapter;\n /** Event transport */\n events: EventTransport;\n /** Logger instance */\n logger: Logger;\n /** Abort controller for cancellation */\n abortController: AbortController;\n /** Function to spawn child workflows */\n spawnChild: (options: SpawnChildOptions) => Promise<string>;\n /** Optional checkpoint for resuming from a previous execution */\n checkpoint?: WorkflowCheckpoint;\n}\n\n/**\n * Execute a workflow definition.\n * This is the main execution logic that runs all steps sequentially.\n */\nexport async function executeWorkflow(options: ExecuteOptions): Promise<RunResult> {\n const {\n runId,\n definition,\n input,\n metadata = {},\n storage,\n events,\n logger,\n abortController,\n spawnChild,\n checkpoint,\n } = options;\n\n const startTime = Date.now();\n const isResume = !!checkpoint;\n\n // Update run status to running (if not already)\n // On resume, don't overwrite the original startedAt\n await markRunRunning(storage, runId, isResume);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: isResume ? 'run.resumed' : 'run.started',\n timestamp: new Date(),\n payload: isResume ? { resumedFrom: Array.from(checkpoint.completedStepKeys) } : undefined,\n });\n\n const completedSteps = initialCompletedSteps(checkpoint);\n\n const context = buildContext({\n runId,\n definition,\n input,\n metadata,\n events,\n logger,\n abortController,\n spawnChild,\n checkpointResults: checkpoint?.results,\n });\n\n const timeoutHandle = setupWorkflowTimeout(runId, definition, abortController);\n\n try {\n // Execute beforeRun hook\n if (definition.hooks?.beforeRun) {\n await definition.hooks.beforeRun(context);\n }\n\n // Execute each step in sequence\n for (const step of definition.steps) {\n // Check for cancellation\n if (abortController.signal.aborted) {\n throw new WorkflowCanceledError(runId);\n }\n\n context.currentStep = step.key;\n\n // Skip already completed steps when resuming\n if (checkpoint?.completedStepKeys.has(step.key)) {\n logger.info(`Skipping step \"${step.key}\" (already completed in previous run)`);\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { reason: 'checkpoint' },\n });\n continue;\n }\n\n // Check skip condition\n if (step.skipIf) {\n const shouldSkip = await step.skipIf(context);\n if (shouldSkip) {\n logger.info(`Skipping step \"${step.key}\" (condition met)`);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n });\n\n continue;\n }\n }\n\n // Execute the step\n const result = await executeStep(step, context, {\n definition,\n storage,\n events,\n logger,\n abortController,\n });\n\n // Store result in context\n context.results[step.key] = result;\n\n // Track completed step\n completedSteps.push(step.key);\n\n // Save checkpoint (accumulated results + completed steps)\n await saveCheckpoint(storage, runId, context.results, completedSteps);\n }\n\n timeoutHandle.clear();\n\n const duration = Date.now() - startTime;\n const runResult: RunResult = {\n status: 'succeeded',\n results: context.results,\n duration,\n };\n\n // Execute afterRun hook\n if (definition.hooks?.afterRun) {\n await definition.hooks.afterRun(context, runResult);\n }\n\n // Update run status\n await markRunSucceeded(storage, runId, context.results);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'run.completed',\n timestamp: new Date(),\n payload: { results: context.results, duration },\n });\n\n return runResult;\n\n } catch (error) {\n timeoutHandle.clear();\n\n const duration = Date.now() - startTime;\n\n const actualError = timeoutHandle.getTimeoutError() ?? error;\n const workflowError = WorkflowEngineError.fromError(actualError);\n\n // Determine final status + event type from the surfaced error.\n const { status, eventType } = decideRunFinalState(actualError);\n\n const runResult: RunResult = {\n status,\n results: context.results,\n error: workflowError,\n duration,\n };\n\n // Execute afterRun hook (even on failure)\n if (definition.hooks?.afterRun) {\n try {\n await definition.hooks.afterRun(context, runResult);\n } catch (hookError) {\n logger.error('afterRun hook failed for run ' + runId + ':', hookError);\n }\n }\n\n // Update run status\n await markRunFinal(storage, runId, status, context.results, workflowError);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType,\n timestamp: new Date(),\n payload: { error: workflowError.message, duration },\n });\n\n return runResult;\n }\n}\n\n","/**\n * Concurrency control for the WorkflowEngine.\n *\n * Owns:\n * - the priority-ordered queue of pending runs (`runQueue`)\n * - the set of in-flight run abort controllers (`activeRuns`)\n * - the timer handles used to defer launches via setTimeout/setImmediate\n *\n * Responsibilities:\n * - `hasCapacity()` against the configured `maxConcurrency` ceiling\n * - priority-ordered enqueue (higher priority first, FIFO within a priority)\n * - dispatch loop that drains the queue while capacity exists, with a\n * try/catch around each dispatch so a single bad run cannot tear down\n * the loop and strand the rest of the queue (preserves the audit\n * 2026-04-27 C3 fix in `processQueue`).\n * - dispatch-failure telemetry: log + emit `run.failed` + best-effort\n * storage update with `QUEUE_DISPATCH_FAILED`.\n *\n * NOT responsible for:\n * - building the `executeWorkflow` invocation (that lives in WorkflowEngine\n * so the orchestrator/spawnChild wiring stays where it is)\n * - storage initialization / shutdown sequencing (see `lifecycle.ts`)\n */\n\nimport type { StorageAdapter } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport type { Logger, WorkflowDefinition } from '../types';\n\n/**\n * Queued run waiting to be executed when capacity is available.\n */\nexport interface QueuedRun {\n runId: string;\n definition: WorkflowDefinition;\n input: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n priority: number;\n queuedAt: Date;\n}\n\ntype TimerHandle = ReturnType<typeof setTimeout> | ReturnType<typeof setImmediate>;\n\nexport interface ConcurrencyManagerDeps {\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n /** Maximum concurrent runs; undefined or <=0 means unlimited. */\n maxConcurrency?: number;\n}\n\nexport class ConcurrencyManager {\n private readonly activeRuns = new Map<string, AbortController>();\n private readonly runQueue: QueuedRun[] = [];\n private readonly timerHandles = new Set<TimerHandle>();\n private readonly storage: StorageAdapter;\n private readonly events: EventTransport;\n private readonly logger: Logger;\n private readonly maxConcurrency: number | undefined;\n\n constructor(deps: ConcurrencyManagerDeps) {\n this.storage = deps.storage;\n this.events = deps.events;\n this.logger = deps.logger;\n this.maxConcurrency = deps.maxConcurrency;\n }\n\n hasCapacity(): boolean {\n if (this.maxConcurrency === undefined || this.maxConcurrency <= 0) {\n return true;\n }\n return this.activeRuns.size < this.maxConcurrency;\n }\n\n getActiveCount(): number {\n return this.activeRuns.size;\n }\n\n getQueuedCount(): number {\n return this.runQueue.length;\n }\n\n isActive(runId: string): boolean {\n return this.activeRuns.has(runId);\n }\n\n /** Insert a run in priority order (higher priority first, FIFO within same). */\n enqueue(run: QueuedRun): void {\n let inserted = false;\n for (let i = 0; i < this.runQueue.length; i++) {\n if (run.priority > this.runQueue[i].priority) {\n this.runQueue.splice(i, 0, run);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n this.runQueue.push(run);\n }\n }\n\n /** Remove a run from the queue if present. Returns true if it was queued. */\n removeFromQueue(runId: string): boolean {\n const idx = this.runQueue.findIndex((q) => q.runId === runId);\n if (idx === -1) return false;\n this.runQueue.splice(idx, 1);\n return true;\n }\n\n registerActive(runId: string, controller: AbortController): void {\n this.activeRuns.set(runId, controller);\n }\n\n unregisterActive(runId: string): void {\n this.activeRuns.delete(runId);\n }\n\n abortActive(runId: string): boolean {\n const controller = this.activeRuns.get(runId);\n if (!controller) return false;\n controller.abort();\n return true;\n }\n\n /**\n * Abort every in-flight run. `onAbort` is called for each run id before its\n * controller is signaled (so callers can log, emit, etc.).\n */\n abortAllActive(onAbort?: (runId: string) => void): void {\n for (const [runId, controller] of this.activeRuns) {\n if (onAbort) onAbort(runId);\n controller.abort();\n }\n }\n\n /** Forget all active-run bookkeeping without aborting (used during shutdown). */\n clearActive(): void {\n this.activeRuns.clear();\n }\n\n /**\n * Schedule a launch via setTimeout (when `delay` is truthy) or setImmediate\n * (otherwise). Tracks the handle so it can be cleared during shutdown.\n */\n scheduleLaunch(fn: () => void, delay?: number): void {\n if (delay) {\n const handle = setTimeout(fn, delay);\n this.timerHandles.add(handle);\n } else {\n const handle = setImmediate(fn);\n this.timerHandles.add(handle);\n }\n }\n\n clearTimers(): void {\n for (const handle of this.timerHandles) {\n if (typeof handle === 'object' && 'ref' in handle) {\n clearImmediate(handle as ReturnType<typeof setImmediate>);\n } else {\n clearTimeout(handle as ReturnType<typeof setTimeout>);\n }\n }\n this.timerHandles.clear();\n }\n\n /**\n * Drain the queue while capacity is available, dispatching each item via\n * `dispatch(run)`. Each iteration is wrapped in try/catch so that a failure\n * dispatching one queued item (e.g., an event-transport that throws) cannot\n * tear down the loop and leave remaining items stuck in the queue. Failed\n * dispatches are logged, the run is marked as failed in storage as\n * best-effort telemetry, and the loop advances to the next item.\n *\n * Emits `run.dequeued` for each dispatched run (this is what the C3\n * resilience test exercises by having the emit throw).\n */\n processQueue(dispatch: (run: QueuedRun) => void): void {\n while (this.hasCapacity() && this.runQueue.length > 0) {\n const next = this.runQueue.shift()!;\n\n try {\n this.logger.debug(`Starting queued run ${next.runId}`);\n\n this.events.emit({\n runId: next.runId,\n kind: next.definition.kind,\n eventType: 'run.dequeued',\n timestamp: new Date(),\n });\n\n dispatch(next);\n } catch (err) {\n this.recordQueueDispatchFailure(next, err);\n }\n }\n }\n\n /**\n * Record a queue-dispatch failure: log it, emit a failure event, and\n * best-effort mark the run as failed in storage. All side-effects are\n * defensively wrapped so this method itself never throws.\n */\n private recordQueueDispatchFailure(queued: QueuedRun, err: unknown): void {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.error(`Failed to dispatch queued run ${queued.runId}`, err);\n\n try {\n this.events.emit({\n runId: queued.runId,\n kind: queued.definition.kind,\n eventType: 'run.failed',\n timestamp: new Date(),\n payload: { error: { code: 'QUEUE_DISPATCH_FAILED', message } },\n });\n } catch (emitErr) {\n this.logger.error(`Failed to emit dispatch-failure event for ${queued.runId}`, emitErr);\n }\n\n // Fire-and-forget; we don't want to block the queue loop on storage I/O.\n this.storage\n .updateRun(queued.runId, {\n status: 'failed',\n finishedAt: new Date(),\n error: { code: 'QUEUE_DISPATCH_FAILED', message },\n })\n .catch((updateErr) => {\n this.logger.error(`Failed to record dispatch failure for ${queued.runId}`, updateErr);\n });\n }\n}\n","/**\n * Lifecycle and resume orchestration for the WorkflowEngine.\n *\n * Owns the cross-cutting \"engine itself\" lifecycle:\n * - `initialize()` — bring up storage adapters that need explicit init\n * (e.g., PostgresStorageAdapter)\n * - `shutdown()` — drain timers, abort in-flight runs, close transports\n * - `resumeRun()` / `getResumableRuns()` / `resumeAllInterrupted()` —\n * restart interrupted runs from their persisted checkpoints\n *\n * NOT responsible for:\n * - per-step execution (that lives in `orchestrator.ts`)\n * - queue/active/timer bookkeeping (that lives in `engine/concurrency.ts`;\n * this module delegates to a `ConcurrencyManager`)\n * - building the `executeWorkflow` invocation (the engine still owns that\n * so the orchestrator/spawnChild wiring stays in one place; this module\n * calls it via the injected `launchRun` callback)\n */\n\nimport type { StorageAdapter, WorkflowRunRecord } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport type { Logger, WorkflowDefinition, WorkflowKind } from '../types';\nimport { RunNotFoundError, WorkflowNotFoundError } from '../../utils/errors';\nimport type { ConcurrencyManager } from './concurrency';\n\n/**\n * Callback the engine provides for actually launching a run. Lifecycle uses\n * it to start a resumed run with its checkpoint; the engine's implementation\n * registers the abort controller, schedules the launch via the concurrency\n * manager, and invokes the orchestrator.\n */\nexport type LaunchRunFn = (\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number,\n checkpoint?: { completedStepKeys: Set<string>; results: Record<string, unknown> }\n) => void;\n\nexport interface LifecycleManagerDeps {\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n registry: Map<WorkflowKind, WorkflowDefinition>;\n concurrency: ConcurrencyManager;\n launchRun: LaunchRunFn;\n}\n\nexport class LifecycleManager {\n private readonly storage: StorageAdapter;\n private readonly events: EventTransport;\n private readonly logger: Logger;\n private readonly registry: Map<WorkflowKind, WorkflowDefinition>;\n private readonly concurrency: ConcurrencyManager;\n private readonly launchRun: LaunchRunFn;\n\n constructor(deps: LifecycleManagerDeps) {\n this.storage = deps.storage;\n this.events = deps.events;\n this.logger = deps.logger;\n this.registry = deps.registry;\n this.concurrency = deps.concurrency;\n this.launchRun = deps.launchRun;\n }\n\n /**\n * Initialize the engine's storage adapter if it requires it.\n * Safe to call when the adapter has no `initialize` hook.\n */\n async initialize(): Promise<void> {\n if (this.storage.initialize) {\n await this.storage.initialize();\n }\n }\n\n /**\n * Shutdown the engine gracefully:\n * 1. clear pending timer handles (so no further launches fire)\n * 2. abort all in-flight runs\n * 3. close the event transport\n * 4. close the storage adapter\n * 5. drop active-run bookkeeping\n */\n async shutdown(): Promise<void> {\n this.logger.info('Shutting down workflow engine...');\n\n this.concurrency.clearTimers();\n\n this.concurrency.abortAllActive((runId) => {\n this.logger.debug(`Canceling active run: ${runId}`);\n });\n\n if (this.events.close) {\n this.events.close();\n }\n\n if (this.storage.close) {\n await this.storage.close();\n }\n\n this.concurrency.clearActive();\n this.logger.info('Workflow engine shutdown complete');\n }\n\n /**\n * Resume an interrupted workflow run from its checkpoint.\n * The run must be in 'queued' or 'running' status.\n */\n async resumeRun(runId: string): Promise<string> {\n const run = await this.storage.getRun(runId);\n if (!run) {\n throw new RunNotFoundError(runId);\n }\n\n if (!['queued', 'running'].includes(run.status)) {\n throw new Error(`Cannot resume run ${runId}: status is \"${run.status}\"`);\n }\n\n const definition = this.registry.get(run.kind);\n if (!definition) {\n throw new WorkflowNotFoundError(run.kind);\n }\n\n if (this.concurrency.isActive(runId)) {\n this.logger.warn(`Run ${runId} is already active, skipping resume`);\n return runId;\n }\n\n this.logger.info(`Resuming run ${runId} from checkpoint`);\n\n const completedStepKeys = new Set(run.completedSteps ?? []);\n\n this.launchRun(runId, definition, run.input, run.metadata, undefined, {\n completedStepKeys,\n results: run.context,\n });\n\n return runId;\n }\n\n /**\n * Get all runs that were interrupted and can be resumed.\n * Returns runs with status 'queued' or 'running'.\n */\n async getResumableRuns(): Promise<WorkflowRunRecord[]> {\n const result = await this.storage.listRuns({\n status: ['queued', 'running'],\n });\n return result.items;\n }\n\n /**\n * Resume every interrupted run whose workflow kind is currently registered.\n * Useful for recovering after a server restart.\n */\n async resumeAllInterrupted(): Promise<string[]> {\n const resumableRuns = await this.getResumableRuns();\n const resumedIds: string[] = [];\n\n for (const run of resumableRuns) {\n if (this.registry.has(run.kind)) {\n try {\n await this.resumeRun(run.id);\n resumedIds.push(run.id);\n } catch (error) {\n this.logger.error(`Failed to resume run ${run.id}:`, error);\n }\n } else {\n this.logger.warn(`Cannot resume run ${run.id}: workflow \"${run.kind}\" not registered`);\n }\n }\n\n return resumedIds;\n }\n}\n","/**\n * Main WorkflowEngine class.\n *\n * This is the primary entry point for the workflow engine.\n * It provides methods for registering workflows, starting runs,\n * and managing workflow execution.\n *\n * Internal concerns are decomposed into co-located submodules under\n * `./engine/` (see `engine/concurrency.ts`, `engine/lifecycle.ts`).\n * WorkflowEngine itself stays the thin public face.\n */\n\nimport type {\n WorkflowKind,\n WorkflowDefinition,\n WorkflowContext,\n Logger,\n SpawnChildOptions,\n} from './types';\nimport type { StorageAdapter, WorkflowRunRecord } from '../storage/types';\nimport type { EventTransport, EventCallback, Unsubscribe, WorkflowEvent } from '../events/types';\nimport { MemoryStorageAdapter } from '../storage/memory';\nimport { MemoryEventTransport } from '../events/memory';\nimport { executeWorkflow } from './orchestrator';\nimport {\n WorkflowNotFoundError,\n WorkflowAlreadyRegisteredError,\n RunNotFoundError,\n WaitForRunTimeoutError,\n} from '../utils/errors';\nimport { ConsoleLogger } from '../utils/logger';\nimport { ConcurrencyManager, type QueuedRun } from './engine/concurrency';\nimport { LifecycleManager } from './engine/lifecycle';\n\n// ============================================================================\n// Configuration Types\n// ============================================================================\n\n/**\n * Configuration for the workflow engine.\n */\nexport interface WorkflowEngineConfig {\n /** Storage adapter for persistence (default: MemoryStorageAdapter) */\n storage?: StorageAdapter;\n\n /** Event transport for real-time updates (default: MemoryEventTransport) */\n events?: EventTransport;\n\n /** Logger instance (default: ConsoleLogger) */\n logger?: Logger;\n\n /** Global settings */\n settings?: {\n /** Default timeout for workflows in ms */\n defaultTimeout?: number;\n\n /** Maximum concurrent workflows */\n maxConcurrency?: number;\n };\n}\n\n/**\n * Options for starting a workflow run.\n */\nexport interface StartRunOptions<TInput = Record<string, unknown>> {\n /** Workflow type to run */\n kind: WorkflowKind;\n\n /** Input parameters */\n input?: TInput;\n\n /** Optional metadata (e.g., userId, topicId) */\n metadata?: Record<string, unknown>;\n\n /** Parent run ID (for child workflows) */\n parentRunId?: string;\n\n /** Delay before starting (ms) */\n delay?: number;\n\n /** Priority for queue ordering (higher = runs first, default: 0) */\n priority?: number;\n}\n\n// ============================================================================\n// WorkflowEngine Class\n// ============================================================================\n\n/**\n * Main workflow engine class.\n *\n * @example\n * ```typescript\n * const engine = new WorkflowEngine({\n * storage: new MemoryStorageAdapter(),\n * });\n *\n * engine.registerWorkflow({\n * kind: 'my.workflow',\n * name: 'My Workflow',\n * steps: [\n * {\n * key: 'step1',\n * name: 'First Step',\n * handler: async (ctx) => {\n * return { message: 'Hello!' };\n * },\n * },\n * ],\n * });\n *\n * const runId = await engine.startRun({ kind: 'my.workflow' });\n * ```\n */\nexport class WorkflowEngine {\n private registry = new Map<WorkflowKind, WorkflowDefinition>();\n private storage: StorageAdapter;\n private events: EventTransport;\n private logger: Logger;\n private settings: NonNullable<WorkflowEngineConfig['settings']>;\n private concurrency: ConcurrencyManager;\n private lifecycle: LifecycleManager;\n\n constructor(config: WorkflowEngineConfig = {}) {\n this.storage = config.storage ?? new MemoryStorageAdapter();\n this.events = config.events ?? new MemoryEventTransport();\n this.logger = config.logger ?? new ConsoleLogger();\n this.settings = config.settings ?? {};\n this.concurrency = new ConcurrencyManager({\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n maxConcurrency: this.settings.maxConcurrency,\n });\n this.lifecycle = new LifecycleManager({\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n registry: this.registry,\n concurrency: this.concurrency,\n launchRun: (runId, def, input, metadata, delay, checkpoint) =>\n this.launchRun(runId, def, input, metadata, delay, checkpoint),\n });\n }\n\n /**\n * Initialize the engine and its storage/event adapters.\n * Call this before starting runs if your storage adapter requires initialization\n * (e.g., PostgresStorageAdapter).\n */\n async initialize(): Promise<void> {\n return this.lifecycle.initialize();\n }\n\n /**\n * Get the current number of active runs.\n */\n getActiveRunCount(): number {\n return this.concurrency.getActiveCount();\n }\n\n /**\n * Get the number of queued runs waiting for capacity.\n */\n getQueuedRunCount(): number {\n return this.concurrency.getQueuedCount();\n }\n\n // ============================================================================\n // Workflow Registration\n // ============================================================================\n\n /**\n * Register a workflow definition.\n * Must be called before runs of this type can be started.\n *\n * @param definition - The workflow definition\n * @throws WorkflowAlreadyRegisteredError if already registered\n */\n registerWorkflow<TInput = Record<string, unknown>>(\n definition: WorkflowDefinition<TInput>\n ): void {\n if (this.registry.has(definition.kind)) {\n throw new WorkflowAlreadyRegisteredError(definition.kind);\n }\n this.registry.set(definition.kind, definition as WorkflowDefinition);\n this.logger.debug(`Registered workflow: ${definition.kind}`);\n }\n\n /**\n * Unregister a workflow definition.\n *\n * @param kind - The workflow kind to unregister\n * @returns true if the workflow was unregistered, false if not found\n */\n unregisterWorkflow(kind: WorkflowKind): boolean {\n const deleted = this.registry.delete(kind);\n if (deleted) {\n this.logger.debug(`Unregistered workflow: ${kind}`);\n }\n return deleted;\n }\n\n /**\n * Get a registered workflow definition.\n *\n * @param kind - The workflow kind\n * @returns The workflow definition or undefined\n */\n getWorkflow(kind: WorkflowKind): WorkflowDefinition | undefined {\n return this.registry.get(kind);\n }\n\n /**\n * Get all registered workflow kinds.\n */\n getRegisteredWorkflows(): WorkflowKind[] {\n return Array.from(this.registry.keys());\n }\n\n // ============================================================================\n // Run Management\n // ============================================================================\n\n /**\n * Start a new workflow run (non-blocking).\n * The run executes asynchronously and this method returns immediately.\n * If maxConcurrency is set and reached, the run is queued.\n *\n * @param options - Run options including kind and input\n * @returns The generated run ID\n * @throws WorkflowNotFoundError if the workflow kind is not registered\n */\n async startRun<TInput = Record<string, unknown>>(\n options: StartRunOptions<TInput>\n ): Promise<string> {\n const definition = this.registry.get(options.kind);\n if (!definition) {\n throw new WorkflowNotFoundError(options.kind);\n }\n\n // Create run record (status: queued)\n const run = await this.storage.createRun({\n kind: options.kind,\n status: 'queued',\n parentRunId: options.parentRunId,\n input: (options.input ?? {}) as Record<string, unknown>,\n metadata: options.metadata ?? {},\n context: {},\n });\n\n const runId = run.id;\n\n // Emit run created event\n this.events.emit({\n runId,\n kind: options.kind,\n eventType: 'run.created',\n timestamp: new Date(),\n payload: { input: options.input, metadata: options.metadata, priority: options.priority ?? 0 },\n });\n\n // Check if we have capacity to start immediately\n if (this.concurrency.hasCapacity()) {\n // Start execution immediately\n this.executeRun(\n runId,\n definition,\n (options.input ?? {}) as Record<string, unknown>,\n options.metadata,\n options.delay\n );\n } else {\n // Queue the run for later execution\n this.concurrency.enqueue({\n runId,\n definition,\n input: (options.input ?? {}) as Record<string, unknown>,\n metadata: options.metadata,\n priority: options.priority ?? 0,\n queuedAt: new Date(),\n });\n\n this.logger.debug(`Run ${runId} queued (${this.concurrency.getQueuedCount()} in queue)`);\n\n // Emit queued event\n this.events.emit({\n runId,\n kind: options.kind,\n eventType: 'run.queued',\n timestamp: new Date(),\n payload: { queuePosition: this.concurrency.getQueuedCount() },\n });\n }\n\n return runId;\n }\n\n /**\n * Execute a run (internal method).\n */\n private executeRun(\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number\n ): void {\n this.launchRun(runId, definition, input, metadata, delay);\n }\n\n /**\n * Launch a workflow run asynchronously.\n * Shared by both executeRun (new runs) and resumeRun (checkpoint recovery).\n */\n private launchRun(\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number,\n checkpoint?: { completedStepKeys: Set<string>; results: Record<string, unknown> }\n ): void {\n const abortController = new AbortController();\n this.concurrency.registerActive(runId, abortController);\n\n const execute = async () => {\n try {\n await executeWorkflow({\n runId,\n definition,\n input,\n metadata,\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n abortController,\n spawnChild: (childOptions: SpawnChildOptions) => this.spawnChild(runId, childOptions),\n checkpoint,\n });\n } finally {\n this.concurrency.unregisterActive(runId);\n this.processQueue();\n }\n };\n\n // executeWorkflow has its own try/catch that converts errors into a failed\n // run record, but the surrounding `finally` (unregisterActive + processQueue)\n // could still throw, and `setTimeout`/`setImmediate` discards the returned\n // promise — leaving any rejection unhandled and capable of crashing Node.\n // Wrap the launch so those rejections are logged instead.\n const guarded = () => {\n execute().catch((err) => {\n this.concurrency.unregisterActive(runId);\n this.logger.error(`Unhandled error launching run ${runId}`, err);\n });\n };\n\n this.concurrency.scheduleLaunch(guarded, delay);\n }\n\n /**\n * Drain the queue, dispatching each ready run via `executeRun`. Resilience\n * against per-item dispatch failures lives in `ConcurrencyManager.processQueue`.\n */\n private processQueue(): void {\n this.concurrency.processQueue((next) => {\n this.executeRun(next.runId, next.definition, next.input, next.metadata);\n });\n }\n\n /**\n * Start a child workflow from within a parent workflow.\n * Called internally by the context.spawnChild helper.\n */\n private async spawnChild(parentRunId: string, options: SpawnChildOptions): Promise<string> {\n return this.startRun({\n kind: options.kind,\n input: options.input,\n metadata: options.metadata,\n parentRunId,\n });\n }\n\n /**\n * Cancel a running workflow.\n * Signals the workflow to stop at the next cancellation point.\n *\n * @param runId - The run ID to cancel\n * @throws {RunNotFoundError} If no run with the given ID exists\n */\n async cancelRun(runId: string): Promise<void> {\n const run = await this.storage.getRun(runId);\n if (!run) {\n throw new RunNotFoundError(runId);\n }\n\n // Don't overwrite terminal statuses\n if (['succeeded', 'failed', 'canceled', 'timeout'].includes(run.status)) {\n return;\n }\n\n // Remove from queue if queued, then signal abort if active\n this.concurrency.removeFromQueue(runId);\n this.concurrency.abortActive(runId);\n\n // Update status in storage (the orchestrator will also update on completion)\n await this.storage.updateRun(runId, {\n status: 'canceled',\n finishedAt: new Date(),\n });\n\n this.events.emit({\n runId,\n kind: run.kind,\n eventType: 'run.canceled',\n timestamp: new Date(),\n });\n }\n\n /**\n * Get the current status of a run.\n *\n * @param runId - The run ID to look up\n * @returns The run record or null if not found\n */\n async getRunStatus(runId: string): Promise<WorkflowRunRecord | null> {\n return this.storage.getRun(runId);\n }\n\n private static readonly TERMINAL_STATUSES = ['succeeded', 'failed', 'canceled', 'timeout'];\n private static readonly TERMINAL_EVENT_TYPES = ['run.completed', 'run.failed', 'run.canceled', 'run.timeout'];\n\n /**\n * Wait for a run to complete.\n * Subscribes to run events and resolves when a terminal event fires.\n * Falls back to an initial storage read to avoid race conditions.\n *\n * @param runId - The run ID to wait for\n * @param options - Wait options\n * @returns The final run record\n */\n async waitForRun(\n runId: string,\n options: { timeout?: number } = {}\n ): Promise<WorkflowRunRecord> {\n const timeout = options.timeout ?? 60000;\n\n return new Promise<WorkflowRunRecord>(async (resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let unsubscribe: (() => void) | undefined;\n let settled = false;\n\n const cleanup = () => {\n if (timeoutId) clearTimeout(timeoutId);\n if (unsubscribe) unsubscribe();\n };\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n cleanup();\n fn();\n };\n\n // Set up timeout\n timeoutId = setTimeout(() => {\n settle(() => reject(new WaitForRunTimeoutError(runId, timeout)));\n }, timeout);\n\n // Subscribe to run events FIRST to avoid missing terminal events\n unsubscribe = this.events.subscribe(runId, async (event) => {\n if (WorkflowEngine.TERMINAL_EVENT_TYPES.includes(event.eventType)) {\n try {\n const run = await this.storage.getRun(runId);\n settle(() => {\n if (!run) {\n reject(new RunNotFoundError(runId));\n } else {\n resolve(run);\n }\n });\n } catch (err) {\n settle(() => reject(err));\n }\n }\n });\n\n // THEN check storage for already-terminal runs\n try {\n const existingRun = await this.storage.getRun(runId);\n if (!existingRun) {\n settle(() => reject(new RunNotFoundError(runId)));\n return;\n }\n if (WorkflowEngine.TERMINAL_STATUSES.includes(existingRun.status)) {\n settle(() => resolve(existingRun));\n return;\n }\n } catch (err) {\n settle(() => reject(err));\n }\n });\n }\n\n // ============================================================================\n // Resume Support\n // ============================================================================\n\n /**\n * Resume an interrupted workflow run from its checkpoint.\n * The run must be in 'queued' or 'running' status.\n *\n * @param runId - The run ID to resume\n * @returns The run ID (same as input)\n * @throws {RunNotFoundError} If no run with the given ID exists\n * @throws {Error} If the run status is not 'queued' or 'running'\n * @throws {WorkflowNotFoundError} If the workflow kind is not registered\n */\n async resumeRun(runId: string): Promise<string> {\n return this.lifecycle.resumeRun(runId);\n }\n\n /**\n * Get all runs that were interrupted and can be resumed.\n * Returns runs with status 'queued' or 'running'.\n */\n async getResumableRuns(): Promise<WorkflowRunRecord[]> {\n return this.lifecycle.getResumableRuns();\n }\n\n /**\n * Resume all interrupted runs.\n * Useful for recovering after a server restart.\n *\n * @returns Array of resumed run IDs\n */\n async resumeAllInterrupted(): Promise<string[]> {\n return this.lifecycle.resumeAllInterrupted();\n }\n\n // ============================================================================\n // Event Subscription\n // ============================================================================\n\n /**\n * Subscribe to events for a specific run.\n *\n * @param runId - The run ID to subscribe to\n * @param callback - Event handler\n * @returns Unsubscribe function\n */\n subscribeToRun(runId: string, callback: EventCallback): Unsubscribe {\n return this.events.subscribe(runId, callback);\n }\n\n /**\n * Subscribe to all workflow events.\n *\n * @param callback - Event handler\n * @returns Unsubscribe function\n */\n subscribeToAll(callback: EventCallback): Unsubscribe {\n return this.events.subscribeAll(callback);\n }\n\n // ============================================================================\n // Storage Access\n // ============================================================================\n\n /**\n * Get the storage adapter.\n * Useful for querying runs and steps directly.\n */\n getStorage(): StorageAdapter {\n return this.storage;\n }\n\n /**\n * Get the event transport.\n * Useful for custom event handling.\n */\n getEvents(): EventTransport {\n return this.events;\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n /**\n * Shutdown the engine gracefully.\n * Cancels all active runs and closes resources.\n */\n async shutdown(): Promise<void> {\n return this.lifecycle.shutdown();\n }\n}\n","/**\n * Shared condition evaluation helpers used by the planner and registry.\n *\n * Extracted to a single module so the planner's recipe scoring and the\n * registry's `query({ matchConditions })` filter cannot drift apart.\n */\n\nimport RE2 from 're2';\nimport type { ConditionOperator } from './types';\n\n/**\n * Maximum length (in characters) accepted for a `matches` regex pattern.\n *\n * Recipe conditions can come from user-supplied configuration; even with RE2's\n * linear-time guarantee, very large patterns waste CPU/memory at compile time\n * and inflate the per-evaluation cost. Cap the source length so a pathological\n * recipe cannot hand the planner a megabyte of regex.\n */\nexport const MAX_REGEX_PATTERN_LENGTH = 512;\n\n/**\n * Get a nested value from an object using dot notation.\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n path: string\n): unknown {\n return path.split('.').reduce<unknown>((current, key) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\n/**\n * Evaluate a single condition against a value.\n *\n * The `matches` operator uses RE2 (not the JS RegExp engine) to avoid\n * catastrophic-backtracking DoS from untrusted recipe inputs.\n */\nexport function evaluateCondition(\n operator: ConditionOperator,\n fieldValue: unknown,\n conditionValue: unknown\n): boolean {\n switch (operator) {\n case 'eq':\n return fieldValue === conditionValue;\n\n case 'neq':\n return fieldValue !== conditionValue;\n\n case 'gt':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue > conditionValue\n : false;\n\n case 'gte':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue >= conditionValue\n : false;\n\n case 'lt':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue < conditionValue\n : false;\n\n case 'lte':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue <= conditionValue\n : false;\n\n case 'contains':\n if (typeof fieldValue === 'string' && typeof conditionValue === 'string') {\n return fieldValue.includes(conditionValue);\n }\n if (Array.isArray(fieldValue)) {\n return fieldValue.includes(conditionValue);\n }\n return false;\n\n case 'matches':\n if (typeof fieldValue === 'string' && typeof conditionValue === 'string') {\n if (conditionValue.length > MAX_REGEX_PATTERN_LENGTH) {\n return false;\n }\n try {\n return new RE2(conditionValue).test(fieldValue);\n } catch {\n return false;\n }\n }\n return false;\n\n case 'exists':\n return fieldValue !== undefined && fieldValue !== null && fieldValue !== '';\n\n case 'notExists':\n return fieldValue === undefined || fieldValue === null || fieldValue === '';\n\n default:\n return false;\n }\n}\n","/**\n * Recipe and Step Handler registries.\n * Provides storage and retrieval of recipes and handlers.\n */\n\nimport type { WorkflowStep } from '../core/types';\nimport { evaluateCondition, getNestedValue } from './evaluate-condition';\nimport type {\n Recipe,\n RecipeRegistry,\n RecipeQueryOptions,\n RegisteredStepHandler,\n StepHandlerRegistry,\n WorkflowKind,\n} from './types';\n\n// ============================================================================\n// Step Handler Registry Implementation\n// ============================================================================\n\n/**\n * In-memory implementation of the step handler registry.\n */\nexport class MemoryStepHandlerRegistry implements StepHandlerRegistry {\n private handlers = new Map<string, RegisteredStepHandler>();\n private tagIndex = new Map<string, Set<string>>();\n\n /** Register a step handler. Throws if a handler with the same ID is already registered. */\n register<TInput = Record<string, unknown>>(\n handler: RegisteredStepHandler<TInput>\n ): void {\n if (this.handlers.has(handler.id)) {\n throw new Error(`Step handler '${handler.id}' is already registered`);\n }\n\n this.handlers.set(handler.id, handler as RegisteredStepHandler);\n\n // Index by tags\n if (handler.tags) {\n for (const tag of handler.tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(handler.id);\n }\n }\n }\n\n /** Get a handler by its unique ID, or undefined if not registered. */\n get(id: string): RegisteredStepHandler | undefined {\n return this.handlers.get(id);\n }\n\n /** Check whether a handler with the given ID is registered. */\n has(id: string): boolean {\n return this.handlers.has(id);\n }\n\n /** List all registered step handlers. */\n list(): RegisteredStepHandler[] {\n return Array.from(this.handlers.values());\n }\n\n /** List all handlers tagged with the given tag. */\n listByTag(tag: string): RegisteredStepHandler[] {\n const ids = this.tagIndex.get(tag);\n if (!ids) return [];\n\n return Array.from(ids)\n .map(id => this.handlers.get(id))\n .filter((h): h is RegisteredStepHandler => h !== undefined);\n }\n\n /**\n * Resolve a handler reference to a WorkflowStep handler function.\n * Returns undefined if the handler is not found.\n */\n resolve(handlerRef: string): WorkflowStep['handler'] | undefined {\n const registered = this.handlers.get(handlerRef);\n return registered?.handler;\n }\n\n /**\n * Clear all registered handlers (useful for testing).\n */\n clear(): void {\n this.handlers.clear();\n this.tagIndex.clear();\n }\n}\n\n// ============================================================================\n// Recipe Registry Implementation\n// ============================================================================\n\n/**\n * In-memory implementation of the recipe registry.\n */\nexport class MemoryRecipeRegistry implements RecipeRegistry {\n private recipes = new Map<string, Recipe>();\n private kindIndex = new Map<WorkflowKind, Set<string>>();\n private variantIndex = new Map<string, string>(); // \"kind:variant\" -> recipeId\n private tagIndex = new Map<string, Set<string>>();\n\n /** Register a single recipe. Throws if a recipe with the same ID or kind:variant pair is already registered. */\n register(recipe: Recipe): void {\n if (this.recipes.has(recipe.id)) {\n throw new Error(`Recipe '${recipe.id}' is already registered`);\n }\n\n this.recipes.set(recipe.id, recipe);\n\n // Index by workflow kind\n if (!this.kindIndex.has(recipe.workflowKind)) {\n this.kindIndex.set(recipe.workflowKind, new Set());\n }\n this.kindIndex.get(recipe.workflowKind)!.add(recipe.id);\n\n // Index by kind:variant\n const variantKey = `${recipe.workflowKind}:${recipe.variant}`;\n if (this.variantIndex.has(variantKey)) {\n throw new Error(\n `Recipe variant '${recipe.variant}' for '${recipe.workflowKind}' is already registered`\n );\n }\n this.variantIndex.set(variantKey, recipe.id);\n\n // Index by tags\n if (recipe.tags) {\n for (const tag of recipe.tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(recipe.id);\n }\n }\n }\n\n /** Register multiple recipes at once. */\n registerAll(recipes: Recipe[]): void {\n for (const recipe of recipes) {\n this.register(recipe);\n }\n }\n\n /** Get a recipe by its unique ID, or undefined if not registered. */\n get(recipeId: string): Recipe | undefined {\n return this.recipes.get(recipeId);\n }\n\n /** Check whether a recipe with the given ID is registered. */\n has(recipeId: string): boolean {\n return this.recipes.has(recipeId);\n }\n\n /** Get all recipes registered for a given workflow kind. */\n getByKind(workflowKind: WorkflowKind): Recipe[] {\n const ids = this.kindIndex.get(workflowKind);\n if (!ids) return [];\n\n return Array.from(ids)\n .map(id => this.recipes.get(id))\n .filter((r): r is Recipe => r !== undefined);\n }\n\n /** Get the recipe for a specific workflow kind and variant combination. */\n getVariant(workflowKind: WorkflowKind, variant: string): Recipe | undefined {\n const variantKey = `${workflowKind}:${variant}`;\n const recipeId = this.variantIndex.get(variantKey);\n if (!recipeId) return undefined;\n return this.recipes.get(recipeId);\n }\n\n /**\n * Get the default recipe for a workflow kind.\n * Returns the 'default' variant if one exists, otherwise falls back to the\n * recipe with the lowest numeric priority value (lower number = higher precedence).\n */\n getDefault(workflowKind: WorkflowKind): Recipe | undefined {\n // First try to find a 'default' variant\n const defaultRecipe = this.getVariant(workflowKind, 'default');\n if (defaultRecipe) return defaultRecipe;\n\n // Fall back to the recipe with the lowest numeric priority (highest precedence).\n // Note: this ascending order is the inverse of RuleBasedPlanner.selectRecipe,\n // which uses descending priority as a tiebreaker in condition-based scoring.\n const recipes = this.getByKind(workflowKind);\n if (recipes.length === 0) return undefined;\n\n return recipes.reduce((lowest, current) => {\n const currentPriority = current.priority ?? 0;\n const lowestPriority = lowest.priority ?? 0;\n return currentPriority < lowestPriority ? current : lowest;\n });\n }\n\n /** List all variant names registered for a workflow kind. */\n listVariants(workflowKind: WorkflowKind): string[] {\n const recipes = this.getByKind(workflowKind);\n return recipes.map(r => r.variant);\n }\n\n /** Query recipes with optional filters for kind, variant, tags, and input conditions. */\n query(options: RecipeQueryOptions): Recipe[] {\n let results = this.list();\n\n if (options.workflowKind) {\n results = results.filter(r => r.workflowKind === options.workflowKind);\n }\n\n if (options.variant) {\n results = results.filter(r => r.variant === options.variant);\n }\n\n if (options.tags && options.tags.length > 0) {\n results = results.filter(r =>\n options.tags!.some(tag => r.tags?.includes(tag))\n );\n }\n\n if (options.matchConditions) {\n results = results.filter(r => {\n if (!r.conditions || r.conditions.length === 0) return true;\n return this.evaluateConditions(r.conditions, options.matchConditions!);\n });\n }\n\n return results;\n }\n\n /** List all registered recipes. */\n list(): Recipe[] {\n return Array.from(this.recipes.values());\n }\n\n /**\n * Clear all registered recipes (useful for testing).\n */\n clear(): void {\n this.recipes.clear();\n this.kindIndex.clear();\n this.variantIndex.clear();\n this.tagIndex.clear();\n }\n\n /**\n * Evaluate recipe conditions against an input.\n * Returns true if all conditions match.\n */\n private evaluateConditions(\n conditions: Recipe['conditions'],\n input: Record<string, unknown>\n ): boolean {\n if (!conditions || conditions.length === 0) return true;\n\n return conditions.every(condition => {\n const fieldValue = getNestedValue(input, condition.field);\n return evaluateCondition(condition.operator, fieldValue, condition.value);\n });\n }\n}\n\n// ============================================================================\n// Default Instances\n// ============================================================================\n\n/**\n * Create a combined registry that holds both recipes and step handlers.\n */\nexport interface CombinedRegistry {\n recipes: MemoryRecipeRegistry;\n handlers: MemoryStepHandlerRegistry;\n}\n\n/**\n * Create a new combined registry instance.\n */\nexport function createRegistry(): CombinedRegistry {\n return {\n recipes: new MemoryRecipeRegistry(),\n handlers: new MemoryStepHandlerRegistry(),\n };\n}\n","/**\n * Rule-based planner implementation.\n * Selects recipes and generates plans based on conditions and input analysis.\n */\n\nimport { generateId } from '../utils/id';\nimport { evaluateCondition, getNestedValue } from './evaluate-condition';\nimport type {\n Plan,\n PlannedStep,\n Planner,\n PlanModification,\n PlanningContext,\n PlanValidationResult,\n Recipe,\n RecipeCondition,\n RecipeRegistry,\n RecipeSelectionResult,\n ResourceEstimate,\n StepHandlerRegistry,\n WorkflowKind,\n} from './types';\n\n/**\n * Score a recipe's conditions against input.\n * Returns a score from 0-100 based on how well conditions match.\n */\nfunction scoreConditions(\n conditions: RecipeCondition[] | undefined,\n input: Record<string, unknown>\n): number {\n // No conditions = default match with low score\n if (!conditions || conditions.length === 0) {\n return 10;\n }\n\n let matched = 0;\n for (const condition of conditions) {\n const fieldValue = getNestedValue(input, condition.field);\n if (evaluateCondition(condition.operator, fieldValue, condition.value)) {\n matched++;\n }\n }\n\n // All conditions must match for any positive score\n if (matched < conditions.length) {\n return 0;\n }\n\n // Base score 50 ensures condition-matched recipes beat unconditional defaults (score 10).\n // Each additional condition adds 10 points, capped at 100 so forced recipes (100) still win.\n return Math.min(100, 50 + conditions.length * 10);\n}\n\n// ============================================================================\n// Rule-Based Planner Implementation\n// ============================================================================\n\n/**\n * Configuration for the RuleBasedPlanner.\n */\nexport interface RuleBasedPlannerConfig {\n /** Recipe registry to use */\n recipeRegistry: RecipeRegistry;\n\n /** Step handler registry for validation */\n handlerRegistry?: StepHandlerRegistry;\n\n /** Whether to validate handler references during planning */\n validateHandlers?: boolean;\n\n /** Resource estimation defaults (used by estimateResources) */\n resourceEstimates?: {\n /** Estimated API calls per step (default: 1) */\n apiCallsPerStep?: number;\n /** Estimated tokens per step (default: 500) */\n tokensPerStep?: number;\n /** Estimated duration per step in ms (default: 2000) */\n durationPerStep?: number;\n /** Estimated API calls per child workflow (default: 5) */\n apiCallsPerChild?: number;\n };\n}\n\n/**\n * Rule-based planner that selects recipes based on condition matching.\n */\nexport class RuleBasedPlanner implements Planner {\n private recipeRegistry: RecipeRegistry;\n private handlerRegistry?: StepHandlerRegistry;\n private validateHandlers: boolean;\n private resourceEstimates: Required<NonNullable<RuleBasedPlannerConfig['resourceEstimates']>>;\n\n constructor(config: RuleBasedPlannerConfig) {\n this.recipeRegistry = config.recipeRegistry;\n this.handlerRegistry = config.handlerRegistry;\n this.validateHandlers = config.validateHandlers ?? false;\n this.resourceEstimates = {\n apiCallsPerStep: config.resourceEstimates?.apiCallsPerStep ?? 1,\n tokensPerStep: config.resourceEstimates?.tokensPerStep ?? 500,\n durationPerStep: config.resourceEstimates?.durationPerStep ?? 2000,\n apiCallsPerChild: config.resourceEstimates?.apiCallsPerChild ?? 5,\n };\n }\n\n /**\n * Select the best recipe for a workflow kind and input.\n */\n async selectRecipe(\n workflowKind: WorkflowKind,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<RecipeSelectionResult> {\n // Check for forced recipe in hints\n if (context?.hints?.forceRecipeId) {\n const forced = this.recipeRegistry.get(context.hints.forceRecipeId);\n if (forced) {\n return {\n recipe: forced,\n score: 100,\n reason: `Forced recipe: ${context.hints.forceRecipeId}`,\n };\n }\n }\n\n // Check for preferred variant in hints\n if (context?.hints?.preferredVariant) {\n const preferred = this.recipeRegistry.getVariant(\n workflowKind,\n context.hints.preferredVariant\n );\n if (preferred) {\n return {\n recipe: preferred,\n score: 90,\n reason: `Preferred variant: ${context.hints.preferredVariant}`,\n };\n }\n }\n\n // Get all recipes for this workflow kind\n const recipes = this.recipeRegistry.getByKind(workflowKind);\n\n if (recipes.length === 0) {\n throw new Error(`No recipes found for workflow kind: ${workflowKind}`);\n }\n\n // Score each recipe\n const scored = recipes.map(recipe => ({\n recipe,\n conditionScore: scoreConditions(recipe.conditions, input),\n priorityScore: recipe.priority ?? 0,\n }));\n\n // Sort by condition score (desc), then priority (desc)\n scored.sort((a, b) => {\n if (b.conditionScore !== a.conditionScore) {\n return b.conditionScore - a.conditionScore;\n }\n return b.priorityScore - a.priorityScore;\n });\n\n // Find best matching recipe\n const best = scored.find(s => s.conditionScore > 0);\n\n if (best) {\n const reason = this.buildSelectionReason(best.recipe, input);\n return {\n recipe: best.recipe,\n score: best.conditionScore,\n reason,\n };\n }\n\n // Fall back to default recipe\n const defaultRecipe = this.recipeRegistry.getDefault(workflowKind);\n if (defaultRecipe) {\n return {\n recipe: defaultRecipe,\n score: 10,\n reason: `Fallback to default recipe: ${defaultRecipe.id}`,\n };\n }\n\n // Last resort: use first recipe\n return {\n recipe: recipes[0],\n score: 5,\n reason: `No matching recipe, using first available: ${recipes[0].id}`,\n };\n }\n\n /**\n * Generate a plan from a recipe and input.\n */\n async generatePlan(\n recipe: Recipe,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<Plan> {\n const modifications: PlanModification[] = [];\n\n // Start with recipe steps\n let steps = recipe.steps.map(step => this.recipeStepToPlannedStep(step));\n\n // Apply hint-based modifications\n if (context?.hints) {\n const { skipSteps, includeSteps, additionalConfig } = context.hints;\n\n // Mark steps to skip\n if (skipSteps && skipSteps.length > 0) {\n for (const stepKey of skipSteps) {\n const stepIndex = steps.findIndex(s => s.key === stepKey);\n if (stepIndex >= 0) {\n steps = steps.filter(s => s.key !== stepKey);\n modifications.push({\n type: 'remove_step',\n stepKey,\n value: null,\n reason: `Skipped via planning hints`,\n });\n }\n }\n }\n\n // Apply additional config to all steps\n if (additionalConfig) {\n for (const step of steps) {\n step.config = { ...step.config, ...additionalConfig };\n }\n modifications.push({\n type: 'modify_step',\n value: additionalConfig,\n reason: 'Applied additional config from planning hints',\n });\n }\n }\n\n // Apply constraint-based modifications\n if (context?.constraints) {\n const constraintMods = this.applyConstraints(steps, context.constraints);\n modifications.push(...constraintMods.modifications);\n steps = constraintMods.steps;\n }\n\n // Build the plan\n const plan: Plan = {\n id: generateId(),\n recipeId: recipe.id,\n variant: recipe.variant,\n modifications,\n steps,\n defaults: recipe.defaults ?? {},\n reasoning: this.buildPlanReasoning(recipe, modifications, context),\n createdAt: new Date(),\n };\n\n // Estimate resources\n plan.resourceEstimate = this.estimateResources(plan);\n\n return plan;\n }\n\n /**\n * Combined operation: select recipe and generate plan.\n */\n async plan(\n workflowKind: WorkflowKind,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<Plan> {\n const selection = await this.selectRecipe(workflowKind, input, context);\n const plan = await this.generatePlan(selection.recipe, input, context);\n\n // Add selection reasoning to plan\n plan.reasoning = `${selection.reason}. ${plan.reasoning ?? ''}`.trim();\n\n return plan;\n }\n\n /**\n * Validate a plan before execution.\n */\n validatePlan(plan: Plan): PlanValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check plan has steps\n if (!plan.steps || plan.steps.length === 0) {\n errors.push('Plan has no steps');\n }\n\n // Check for duplicate step keys\n const stepKeys = new Set<string>();\n for (const step of plan.steps) {\n if (stepKeys.has(step.key)) {\n errors.push(`Duplicate step key: ${step.key}`);\n }\n stepKeys.add(step.key);\n }\n\n // Validate each step\n for (const step of plan.steps) {\n if (!step.key) {\n errors.push('Step missing key');\n }\n if (!step.name) {\n warnings.push(`Step '${step.key}' missing name`);\n }\n if (!step.handlerRef) {\n errors.push(`Step '${step.key}' missing handlerRef`);\n }\n\n // Validate handler exists (if registry available)\n if (this.validateHandlers && this.handlerRegistry) {\n if (!this.handlerRegistry.has(step.handlerRef)) {\n errors.push(`Step '${step.key}' references unknown handler: ${step.handlerRef}`);\n }\n }\n }\n\n // Check child workflows\n if (plan.childWorkflows) {\n for (const child of plan.childWorkflows) {\n if (!child.kind) {\n errors.push('Child workflow missing kind');\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n }\n\n /**\n * Estimate resources required for a plan.\n */\n estimateResources(plan: Plan): ResourceEstimate {\n const { apiCallsPerStep, tokensPerStep, durationPerStep, apiCallsPerChild } = this.resourceEstimates;\n\n const stepCount = plan.steps.length;\n const childCount = plan.childWorkflows?.length ?? 0;\n\n return {\n apiCalls: stepCount * apiCallsPerStep + childCount * apiCallsPerChild,\n tokens: stepCount * tokensPerStep,\n duration: stepCount * durationPerStep,\n };\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n /**\n * Convert a recipe step to a planned step.\n */\n private recipeStepToPlannedStep(step: Recipe['steps'][0]): PlannedStep {\n return {\n key: step.key,\n name: step.name,\n handlerRef: step.handlerRef,\n config: step.config ?? {},\n onError: step.onError,\n maxRetries: step.maxRetries,\n retryDelay: step.retryDelay,\n retryBackoff: step.retryBackoff,\n timeout: step.timeout,\n skipCondition: step.skipCondition,\n };\n }\n\n /**\n * Apply constraints to steps and generate modifications.\n */\n private applyConstraints(\n steps: PlannedStep[],\n constraints: NonNullable<PlanningContext['constraints']>\n ): { steps: PlannedStep[]; modifications: PlanModification[] } {\n const modifications: PlanModification[] = [];\n const perStepTimeout = constraints.maxDuration\n ? Math.floor(constraints.maxDuration / steps.length)\n : undefined;\n\n // Apply all constraint mutations in a single pass\n const modifiedSteps = steps.map(step => {\n const modified = { ...step };\n\n if (constraints.priority === 'speed') {\n modified.timeout = modified.timeout ? Math.min(modified.timeout, 30000) : 30000;\n modified.maxRetries = Math.min(modified.maxRetries ?? 3, 1);\n }\n\n if (constraints.priority === 'cost') {\n modified.maxRetries = 0;\n }\n\n if (perStepTimeout !== undefined) {\n modified.timeout = modified.timeout\n ? Math.min(modified.timeout, perStepTimeout)\n : perStepTimeout;\n }\n\n return modified;\n });\n\n // Record what was applied\n if (constraints.priority === 'speed') {\n modifications.push({\n type: 'set_default',\n value: { priority: 'speed' },\n reason: 'Optimized for speed: reduced timeouts and retries',\n });\n }\n if (constraints.priority === 'cost') {\n modifications.push({\n type: 'set_default',\n value: { priority: 'cost' },\n reason: 'Optimized for cost: disabled retries',\n });\n }\n if (constraints.maxDuration) {\n modifications.push({\n type: 'set_default',\n value: { maxDuration: constraints.maxDuration },\n reason: `Applied duration constraint: ${constraints.maxDuration}ms total`,\n });\n }\n\n return { steps: modifiedSteps, modifications };\n }\n\n /**\n * Build a human-readable selection reason.\n */\n private buildSelectionReason(\n recipe: Recipe,\n input: Record<string, unknown>\n ): string {\n const parts: string[] = [`Selected recipe: ${recipe.id}`];\n\n if (recipe.conditions && recipe.conditions.length > 0) {\n const conditionDescriptions = recipe.conditions.map(c => {\n const value = getNestedValue(input, c.field);\n return `${c.field} ${c.operator} ${JSON.stringify(c.value)} (actual: ${JSON.stringify(value)})`;\n });\n parts.push(`Matched conditions: ${conditionDescriptions.join(', ')}`);\n }\n\n if (recipe.priority !== undefined && recipe.priority > 0) {\n parts.push(`Priority: ${recipe.priority}`);\n }\n\n return parts.join('. ');\n }\n\n /**\n * Build reasoning text for a plan.\n */\n private buildPlanReasoning(\n recipe: Recipe,\n modifications: PlanModification[],\n context?: PlanningContext\n ): string {\n const parts: string[] = [];\n\n parts.push(`Using recipe '${recipe.name}' (${recipe.variant} variant)`);\n\n if (modifications.length > 0) {\n parts.push(`Applied ${modifications.length} modification(s)`);\n }\n\n if (context?.constraints) {\n const constraintList: string[] = [];\n if (context.constraints.priority) {\n constraintList.push(`priority=${context.constraints.priority}`);\n }\n if (context.constraints.maxDuration) {\n constraintList.push(`maxDuration=${context.constraints.maxDuration}ms`);\n }\n if (context.constraints.maxApiCalls) {\n constraintList.push(`maxApiCalls=${context.constraints.maxApiCalls}`);\n }\n if (constraintList.length > 0) {\n parts.push(`Constraints: ${constraintList.join(', ')}`);\n }\n }\n\n return parts.join('. ') + '.';\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/errors.ts","../src/core/orchestrator/persistence.ts","../src/core/orchestrator/state-transitions.ts","../src/utils/retry.ts","../src/core/orchestrator/step-runner.ts","../src/core/orchestrator/plan-resolution.ts","../src/core/orchestrator.ts","../src/core/engine/concurrency.ts","../src/core/engine/lifecycle.ts","../src/core/engine.ts","../src/planning/evaluate-condition.ts","../src/planning/registry.ts","../src/planning/planner.ts"],"sourcesContent":["/**\n * Custom error classes for the workflow engine.\n */\n\nimport type { WorkflowError } from '../core/types';\n\n/**\n * Base error class for workflow-related errors.\n */\nexport class WorkflowEngineError extends Error {\n readonly code: string;\n readonly details?: Record<string, unknown>;\n\n constructor(code: string, message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'WorkflowEngineError';\n this.code = code;\n this.details = details;\n }\n\n /**\n * Convert to a WorkflowError record for storage.\n */\n toRecord(): WorkflowError {\n return {\n code: this.code,\n message: this.message,\n details: this.details,\n };\n }\n\n /**\n * Create a WorkflowError record from any error.\n */\n static fromError(error: unknown, defaultCode = 'UNKNOWN_ERROR'): WorkflowError {\n if (error instanceof WorkflowEngineError) {\n return error.toRecord();\n }\n\n if (error instanceof Error) {\n return {\n code: defaultCode,\n message: error.message,\n };\n }\n\n return {\n code: defaultCode,\n message: String(error),\n };\n }\n}\n\n/**\n * Error thrown when a workflow is not found in the registry.\n */\nexport class WorkflowNotFoundError extends WorkflowEngineError {\n constructor(kind: string) {\n super('WORKFLOW_NOT_FOUND', `Workflow \"${kind}\" is not registered`, { kind });\n this.name = 'WorkflowNotFoundError';\n }\n}\n\n/**\n * Error thrown when a workflow is already registered.\n */\nexport class WorkflowAlreadyRegisteredError extends WorkflowEngineError {\n constructor(kind: string) {\n super('WORKFLOW_ALREADY_REGISTERED', `Workflow \"${kind}\" is already registered`, { kind });\n this.name = 'WorkflowAlreadyRegisteredError';\n }\n}\n\n/**\n * Error thrown when a run is not found.\n */\nexport class RunNotFoundError extends WorkflowEngineError {\n constructor(runId: string) {\n super('RUN_NOT_FOUND', `Run \"${runId}\" not found`, { runId });\n this.name = 'RunNotFoundError';\n }\n}\n\n/**\n * Error thrown when a step fails.\n */\nexport class StepError extends WorkflowEngineError {\n readonly stepKey: string;\n readonly attempt: number;\n readonly cause?: Error;\n\n constructor(stepKey: string, message: string, attempt: number, cause?: Error) {\n super('STEP_ERROR', message, { stepKey, attempt });\n this.name = 'StepError';\n this.stepKey = stepKey;\n this.attempt = attempt;\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when a step times out.\n */\nexport class StepTimeoutError extends WorkflowEngineError {\n readonly stepKey: string;\n readonly timeoutMs: number;\n\n constructor(stepKey: string, timeoutMs: number) {\n super('STEP_TIMEOUT', `Step \"${stepKey}\" timed out after ${timeoutMs}ms`, {\n stepKey,\n timeoutMs,\n });\n this.name = 'StepTimeoutError';\n this.stepKey = stepKey;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when a workflow is canceled.\n */\nexport class WorkflowCanceledError extends WorkflowEngineError {\n constructor(runId: string) {\n super('WORKFLOW_CANCELED', `Workflow run \"${runId}\" was canceled`, { runId });\n this.name = 'WorkflowCanceledError';\n }\n}\n\n/**\n * Error thrown when waitForRun times out polling for a terminal status.\n */\nexport class WaitForRunTimeoutError extends WorkflowEngineError {\n readonly runId: string;\n readonly timeoutMs: number;\n\n constructor(runId: string, timeoutMs: number) {\n super('WAIT_FOR_RUN_TIMEOUT', `Timeout waiting for run ${runId} after ${timeoutMs}ms`, {\n runId,\n timeoutMs,\n });\n this.name = 'WaitForRunTimeoutError';\n this.runId = runId;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when a workflow times out.\n */\nexport class WorkflowTimeoutError extends WorkflowEngineError {\n readonly timeoutMs: number;\n\n constructor(runId: string, timeoutMs: number) {\n super('WORKFLOW_TIMEOUT', `Workflow run \"${runId}\" timed out after ${timeoutMs}ms`, {\n runId,\n timeoutMs,\n });\n this.name = 'WorkflowTimeoutError';\n this.timeoutMs = timeoutMs;\n }\n}\n","/**\n * Orchestrator persistence layer.\n *\n * Wraps the storage adapter and event transport with intent-named helpers\n * so the orchestrator and step-runner can stay focused on control flow\n * instead of repeating field shapes for every status transition.\n *\n * All side-effect calls the orchestrator makes against storage or the event\n * transport flow through this module — keeping the rest of the pipeline\n * pure(-ish) and easy to read.\n */\nimport type { StorageAdapter, WorkflowRunStepRecord } from '../../storage/types';\nimport type { EventTransport, WorkflowEvent } from '../../events/types';\nimport type { Logger, WorkflowError } from '../types';\nimport { WorkflowEngineError } from '../../utils/errors';\n\n/**\n * Mark the run as running. On a fresh start, also stamp `startedAt`;\n * on resume, leave the original `startedAt` alone.\n */\nexport async function markRunRunning(\n storage: StorageAdapter,\n runId: string,\n isResume: boolean\n): Promise<void> {\n await storage.updateRun(runId, {\n status: 'running',\n ...(isResume ? {} : { startedAt: new Date() }),\n });\n}\n\n/**\n * Persist the workflow checkpoint after a step completes:\n * the accumulated step results plus the list of completed step keys.\n */\nexport async function saveCheckpoint(\n storage: StorageAdapter,\n runId: string,\n results: Record<string, unknown>,\n completedSteps: string[]\n): Promise<void> {\n await storage.updateRun(runId, {\n context: { ...results },\n completedSteps: [...completedSteps],\n });\n}\n\n/**\n * Mark the run as succeeded, persisting results and finishedAt.\n */\nexport async function markRunSucceeded(\n storage: StorageAdapter,\n runId: string,\n results: Record<string, unknown>\n): Promise<void> {\n await storage.updateRun(runId, {\n status: 'succeeded',\n context: results,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Persist a non-success terminal state for the run (failed / canceled / timeout).\n * `status` is the storage-level status — the orchestrator decides this from the\n * raised error using `state-transitions.ts`.\n */\nexport async function markRunFinal(\n storage: StorageAdapter,\n runId: string,\n status: 'failed' | 'canceled',\n results: Record<string, unknown>,\n error: WorkflowError\n): Promise<void> {\n await storage.updateRun(runId, {\n status,\n context: results,\n error,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Create a fresh step record in 'running' state for the given attempt.\n * Returns the persisted record so the caller can read its generated id.\n */\nexport async function createStepRecord(\n storage: StorageAdapter,\n runId: string,\n stepKey: string,\n stepName: string,\n attempt: number\n): Promise<WorkflowRunStepRecord> {\n return storage.createStep({\n runId,\n stepKey,\n stepName,\n status: 'running',\n attempt,\n startedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as succeeded, recording its result and finishedAt.\n */\nexport async function markStepSucceeded(\n storage: StorageAdapter,\n stepId: string,\n result: unknown\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: 'succeeded',\n result,\n finishedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as failed (or canceled, if the abort signal already fired)\n * with the normalized engine error attached.\n */\nexport async function markStepFailed(\n storage: StorageAdapter,\n stepId: string,\n error: unknown,\n isCanceled: boolean\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: isCanceled ? 'canceled' : 'failed',\n error: WorkflowEngineError.fromError(error),\n finishedAt: new Date(),\n });\n}\n\n/**\n * Mark a step as canceled without an error payload — used when an in-flight\n * retry sleep is interrupted by an abort signal.\n */\nexport async function markStepCanceled(\n storage: StorageAdapter,\n stepId: string\n): Promise<void> {\n await storage.updateStep(stepId, {\n status: 'canceled',\n finishedAt: new Date(),\n });\n}\n\n/**\n * Emit a workflow event without ever throwing back into the caller.\n * Event emission failures are logged but never abort the workflow,\n * so a flaky transport can't take down a run.\n */\nexport function safeEmitEvent(\n events: EventTransport,\n logger: Logger,\n event: WorkflowEvent\n): void {\n try {\n events.emit(event);\n } catch (error) {\n logger.error('Failed to emit event:', error);\n }\n}\n","/**\n * Pure state-transition decisions for the orchestrator.\n *\n * Every function in here is deterministic and side-effect-free: given\n * the current shape of an event, error, or step config they return what\n * the next state should be. The orchestrator and step-runner read these\n * decisions and apply them via persistence helpers.\n *\n * State-transition rules captured here:\n *\n * Run terminal status:\n * - WorkflowTimeoutError → status='failed', eventType='run.timeout'\n * - WorkflowCanceledError → status='canceled', eventType='run.canceled'\n * - any other error → status='failed', eventType='run.failed'\n *\n * Step error policy resolution (precedence):\n * - step.onError > definition.defaultOnError > 'fail'\n * - step.maxRetries > 3\n * - step.retryDelay (ms) > 1000\n * - step.retryBackoff (multiplier) > 2\n *\n * Step retry decision (after a non-cancellation failure):\n * - onError === 'skip' → 'skip'\n * - onError === 'retry' && attempt <= maxRetries → 'retry'\n * - otherwise (incl. retries exhausted, 'fail') → 'fail'\n */\nimport type { WorkflowDefinition, WorkflowStep } from '../types';\nimport { WorkflowCanceledError, WorkflowTimeoutError } from '../../utils/errors';\n\n/**\n * Storage-level statuses the orchestrator may persist for a non-success run.\n */\nexport type RunFinalStatus = 'failed' | 'canceled';\n\n/**\n * Event types emitted on a non-success run completion.\n */\nexport type RunFinalEventType = 'run.timeout' | 'run.canceled' | 'run.failed';\n\n/**\n * Result of mapping an error to a terminal run state.\n */\nexport interface RunFinalDecision {\n status: RunFinalStatus;\n eventType: RunFinalEventType;\n}\n\n/**\n * Map a thrown workflow error to the final run status + event type.\n * Note: a workflow timeout is persisted as `failed` for storage compatibility,\n * but the emitted event distinguishes it via `run.timeout`.\n */\nexport function decideRunFinalState(error: unknown): RunFinalDecision {\n if (error instanceof WorkflowTimeoutError) {\n return { status: 'failed', eventType: 'run.timeout' };\n }\n if (error instanceof WorkflowCanceledError) {\n return { status: 'canceled', eventType: 'run.canceled' };\n }\n return { status: 'failed', eventType: 'run.failed' };\n}\n\n/**\n * Step-level error policy resolved from a step + workflow definition.\n */\nexport interface StepErrorPolicy {\n onError: 'fail' | 'skip' | 'retry';\n maxRetries: number;\n retryDelay: number;\n retryBackoff: number;\n}\n\n/**\n * Resolve the effective error policy for a step.\n * Step-level config overrides workflow defaults; workflow defaults override\n * the engine defaults (`fail` / 3 / 1000ms / 2x).\n */\nexport function resolveStepErrorPolicy<TInput>(\n step: WorkflowStep<TInput>,\n definition: WorkflowDefinition<TInput>\n): StepErrorPolicy {\n return {\n onError: step.onError ?? definition.defaultOnError ?? 'fail',\n maxRetries: step.maxRetries ?? 3,\n retryDelay: step.retryDelay ?? 1000,\n retryBackoff: step.retryBackoff ?? 2,\n };\n}\n\n/**\n * Decision returned after a step attempt fails.\n *\n * - 'skip' : swallow the error and treat the step as a no-op (returns undefined)\n * - 'retry' : back off and try again\n * - 'fail' : escalate (StepError) and abort the workflow\n */\nexport type StepFailureAction = 'skip' | 'retry' | 'fail';\n\n/**\n * Decide what to do after a step attempt has failed (and was not canceled).\n */\nexport function decideStepFailureAction(\n policy: StepErrorPolicy,\n attempt: number\n): StepFailureAction {\n if (policy.onError === 'skip') return 'skip';\n if (policy.onError === 'retry' && attempt <= policy.maxRetries) return 'retry';\n return 'fail';\n}\n","/**\n * Retry utilities for the workflow engine.\n */\n\nimport { WorkflowCanceledError } from './errors';\n\n/**\n * Options for retry behavior.\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries: number;\n /** Initial delay between retries in ms (default: 1000) */\n delay: number;\n /** Backoff multiplier (default: 2) */\n backoff: number;\n /** Optional abort signal to cancel retries */\n signal?: AbortSignal;\n /** Optional callback before each retry */\n onRetry?: (attempt: number, error: Error, nextDelay: number) => void;\n}\n\n/**\n * Default retry options.\n */\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\n maxRetries: 3,\n delay: 1000,\n backoff: 2,\n};\n\n/**\n * Sleep for a given number of milliseconds.\n * Can be canceled via AbortSignal.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new WorkflowCanceledError('run'));\n return;\n }\n\n const cleanup = () => {\n clearTimeout(timeoutId);\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n };\n\n let onAbort: (() => void) | undefined;\n\n const timeoutId = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n\n if (signal) {\n onAbort = () => {\n cleanup();\n reject(new WorkflowCanceledError('run'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n}\n\n/**\n * Execute a function with retry logic.\n *\n * @param fn - The async function to execute\n * @param options - Retry configuration\n * @returns The result of the function\n * @throws The last error if all retries are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> = {}\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\n let lastError: Error | undefined;\n let currentDelay = opts.delay;\n\n for (let attempt = 1; attempt <= opts.maxRetries + 1; attempt++) {\n // Check if aborted before attempting\n if (opts.signal?.aborted) {\n throw new WorkflowCanceledError('run');\n }\n\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // If this was the last attempt, throw\n if (attempt > opts.maxRetries) {\n throw lastError;\n }\n\n // Call onRetry callback if provided\n opts.onRetry?.(attempt, lastError, currentDelay);\n\n // Wait before next attempt\n await sleep(currentDelay, opts.signal);\n\n // Apply backoff multiplier\n currentDelay = Math.round(currentDelay * opts.backoff);\n }\n }\n\n // This should never be reached, but TypeScript needs it\n throw lastError ?? new Error('Retry failed');\n}\n\n/**\n * Calculate the delay for a specific retry attempt.\n */\nexport function calculateRetryDelay(\n attempt: number,\n baseDelay: number,\n backoff: number\n): number {\n return Math.round(baseDelay * Math.pow(backoff, attempt - 1));\n}\n","/**\n * Step runner — executes a single workflow step with hooks, retries,\n * cancellation, and timeout handling.\n *\n * The shape of the previous monolithic `executeStep` was a `while (true)`\n * loop containing a `try`/`catch` with multiple nested `if` branches per\n * error path (cancel, hook, skip, retry, fail). This file flattens that:\n *\n * - Each error path is its own intent-named helper\n * (handleSkipAction, handleRetryAction, runOnStepErrorHook, etc.)\n * - The main loop nesting is at most 3 levels (while → try → switch)\n *\n * State-transition rules covered here (see also state-transitions.ts):\n *\n * pre-attempt:\n * - abort signal already raised → throw WorkflowCanceledError\n *\n * per-attempt:\n * - handler resolves → markStepSucceeded, emit step.completed, return\n * - handler rejects + canceled → markStepFailed(canceled), emit step.failed, rethrow\n * - handler rejects + policy=skip → emit step.skipped, return undefined\n * - handler rejects + policy=retry → emit step.retry, sleep, continue\n * - handler rejects + policy=fail → throw StepError\n */\nimport type {\n WorkflowDefinition,\n WorkflowStep,\n WorkflowContext,\n Logger,\n} from '../types';\nimport type { StorageAdapter, WorkflowRunStepRecord } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport {\n StepError,\n StepTimeoutError,\n WorkflowCanceledError,\n} from '../../utils/errors';\nimport { sleep, calculateRetryDelay } from '../../utils/retry';\nimport {\n createStepRecord,\n markStepSucceeded,\n markStepFailed,\n markStepCanceled,\n safeEmitEvent,\n} from './persistence';\nimport {\n resolveStepErrorPolicy,\n decideStepFailureAction,\n type StepErrorPolicy,\n} from './state-transitions';\n\n/**\n * Inputs to `executeStep` beyond the step + context themselves.\n */\nexport interface StepExecutionOptions<TInput = Record<string, unknown>> {\n definition: WorkflowDefinition<TInput>;\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n abortController: AbortController;\n}\n\n/**\n * Execute a single workflow step with error handling and retries.\n *\n * Returns the step's result on success, or `undefined` if the resolved\n * error policy is `skip` and the step failed. Throws on cancellation,\n * timeout, or `fail` policy.\n */\nexport async function executeStep<TInput>(\n step: WorkflowStep<TInput>,\n context: WorkflowContext<TInput>,\n options: StepExecutionOptions<TInput>\n): Promise<unknown> {\n const { definition, storage, events, logger, abortController } = options;\n const policy = resolveStepErrorPolicy(step, definition);\n\n let attempt = 0;\n\n while (true) {\n attempt++;\n throwIfCanceled(abortController, context.runId);\n\n const stepRecord = await beginStepAttempt(\n storage,\n events,\n logger,\n context,\n step,\n attempt\n );\n\n if (definition.hooks?.beforeStep) {\n await definition.hooks.beforeStep(context, step);\n }\n\n try {\n throwIfCanceled(abortController, context.runId);\n const result = await runStepHandler(step, context, abortController);\n await completeStepAttempt(\n storage,\n events,\n logger,\n stepRecord,\n context,\n step,\n result,\n definition\n );\n return result;\n } catch (error) {\n const lastError = toError(error);\n const isCanceled =\n error instanceof WorkflowCanceledError || abortController.signal.aborted;\n\n await markStepFailed(storage, stepRecord.id, error, isCanceled);\n\n if (isCanceled) {\n emitStepFailedEvent(events, logger, context, step, lastError, attempt);\n throw error;\n }\n\n await runOnStepErrorHook(definition, context, step, lastError, logger);\n emitStepFailedEvent(events, logger, context, step, lastError, attempt);\n\n const action = decideStepFailureAction(policy, attempt);\n\n if (action === 'skip') {\n handleSkipAction(events, logger, context, step, lastError);\n return undefined;\n }\n\n if (action === 'retry') {\n await handleRetryAction(\n storage,\n events,\n logger,\n abortController,\n context,\n step,\n attempt,\n policy,\n lastError,\n stepRecord.id\n );\n continue;\n }\n\n // action === 'fail' — explicit fail strategy or retries exhausted\n throw new StepError(step.key, lastError.message, attempt, lastError);\n }\n }\n}\n\n/**\n * Throw a WorkflowCanceledError if the abort signal has already been raised.\n * Called at the top of each attempt so we don't even create a step record\n * after cancellation.\n */\nfunction throwIfCanceled(abortController: AbortController, runId: string): void {\n if (abortController.signal.aborted) {\n throw new WorkflowCanceledError(runId);\n }\n}\n\n/**\n * Persist a fresh step record for this attempt, set it as the current step\n * id on the context (so handlers can attach granular telemetry), and emit\n * `step.started`.\n */\nasync function beginStepAttempt<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n attempt: number\n): Promise<WorkflowRunStepRecord> {\n const stepRecord = await createStepRecord(\n storage,\n context.runId,\n step.key,\n step.name,\n attempt\n );\n context.stepId = stepRecord.id;\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.started',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { attempt },\n });\n return stepRecord;\n}\n\n/**\n * Invoke the step handler. If the step has its own timeout, race against it\n * AND the abort signal; otherwise just race against the abort signal so a\n * workflow-level timeout/cancellation still interrupts the step.\n */\nasync function runStepHandler<TInput>(\n step: WorkflowStep<TInput>,\n context: WorkflowContext<TInput>,\n abortController: AbortController\n): Promise<unknown> {\n if (step.timeout) {\n return executeWithTimeout(\n () => step.handler(context),\n step.timeout,\n abortController.signal,\n step.key\n );\n }\n return raceWithAbort(step.handler(context), abortController.signal);\n}\n\n/**\n * Mark the step as succeeded, run the afterStep hook (if any), and emit\n * `step.completed`.\n */\nasync function completeStepAttempt<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n stepRecord: WorkflowRunStepRecord,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n result: unknown,\n definition: WorkflowDefinition<TInput>\n): Promise<void> {\n await markStepSucceeded(storage, stepRecord.id, result);\n if (definition.hooks?.afterStep) {\n await definition.hooks.afterStep(context, step, result);\n }\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.completed',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { result },\n });\n}\n\n/**\n * Coerce an unknown thrown value into a real Error, preserving message\n * text for non-Error throws.\n */\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Run the user's onStepError hook (if defined). Hook failures are logged\n * but never propagated — they must not mask the original step error.\n */\nasync function runOnStepErrorHook<TInput>(\n definition: WorkflowDefinition<TInput>,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error,\n logger: Logger\n): Promise<void> {\n if (!definition.hooks?.onStepError) return;\n try {\n await definition.hooks.onStepError(context, step, lastError);\n } catch (hookError) {\n logger.error('onStepError hook failed for run ' + context.runId + ':', hookError);\n }\n}\n\n/**\n * Emit a `step.failed` event with the canonical payload.\n */\nfunction emitStepFailedEvent<TInput>(\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error,\n attempt: number\n): void {\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.failed',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { error: lastError.message, attempt },\n });\n}\n\n/**\n * Apply the `skip` failure action: warn, emit `step.skipped`, then the\n * caller returns `undefined` from the step.\n */\nfunction handleSkipAction<TInput>(\n events: EventTransport,\n logger: Logger,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n lastError: Error\n): void {\n logger.warn(`Step \"${step.key}\" failed, skipping (strategy: skip)`);\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { reason: 'error', error: lastError.message },\n });\n}\n\n/**\n * Apply the `retry` failure action: emit `step.retry`, sleep with backoff,\n * and let the loop fall through to the next attempt. If the sleep itself\n * is interrupted by cancellation, mark the step record canceled before\n * rethrowing.\n */\nasync function handleRetryAction<TInput>(\n storage: StorageAdapter,\n events: EventTransport,\n logger: Logger,\n abortController: AbortController,\n context: WorkflowContext<TInput>,\n step: WorkflowStep<TInput>,\n attempt: number,\n policy: StepErrorPolicy,\n lastError: Error,\n stepRecordId: string\n): Promise<void> {\n const delay = calculateRetryDelay(attempt, policy.retryDelay, policy.retryBackoff);\n logger.warn(\n `Step \"${step.key}\" failed, retrying in ${delay}ms (attempt ${attempt}/${policy.maxRetries})`\n );\n safeEmitEvent(events, logger, {\n runId: context.runId,\n kind: context.kind,\n eventType: 'step.retry',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { attempt, maxRetries: policy.maxRetries, delay, error: lastError.message },\n });\n\n try {\n await sleep(delay, abortController.signal);\n } catch (sleepError) {\n if (sleepError instanceof WorkflowCanceledError) {\n await markStepCanceled(storage, stepRecordId);\n }\n throw sleepError;\n }\n}\n\n/**\n * Execute a function with a timeout.\n *\n * Uses Promise.race to resolve as soon as either the function completes, the\n * timeout fires, or the abort signal triggers. The `finally` block is critical:\n * without it, the losing promise's timer/listener would remain active, leaking\n * memory — especially problematic in long-running engines processing many steps.\n */\nexport async function executeWithTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number,\n signal: AbortSignal,\n stepKey: string\n): Promise<T> {\n if (signal.aborted) throw new WorkflowCanceledError('run');\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n try {\n return await Promise.race([\n fn(),\n new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new StepTimeoutError(stepKey, timeoutMs));\n }, timeoutMs);\n\n onAbort = () => {\n clearTimeout(timeoutId);\n reject(new WorkflowCanceledError('run'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]);\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n\n/**\n * Race a promise against an abort signal.\n *\n * Steps without their own timeout still need to respect workflow-level timeouts\n * and cancellation. This wraps the step handler in a Promise.race so that an\n * abort signal (from workflow timeout or user cancellation) can interrupt it.\n *\n * The `finally` cleanup removes the abort listener to prevent accumulating\n * listeners on the signal across many steps — without it, each step would\n * leave a dangling listener even after completing successfully.\n */\nexport async function raceWithAbort<T>(\n promise: Promise<T>,\n signal: AbortSignal\n): Promise<T> {\n if (signal.aborted) {\n throw new WorkflowCanceledError('run');\n }\n\n let onAbort: (() => void) | undefined;\n\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n onAbort = () => reject(new WorkflowCanceledError('run'));\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n}\n","/**\n * Plan resolution — turns ExecuteOptions into the runtime artefacts\n * the orchestrator needs to start running steps.\n *\n * Today the engine has no separate planner module: the \"plan\" is just the\n * declarative WorkflowDefinition combined with the optional resume\n * checkpoint and the supplied input/metadata. This module is the seam\n * where, in the future, recipe/plan resolution and input validation can\n * grow without bloating execute-workflow.ts.\n *\n * Responsibilities:\n * 1. Build the WorkflowContext from the run options + checkpoint, with a\n * `context.emit` helper that routes through safeEmitEvent.\n * 2. Set up the workflow-level timeout: returns a handle the caller\n * clears in both the success and failure paths, and a getter for\n * the WorkflowTimeoutError that fired (so the catch block can\n * surface it instead of the abort-derived error).\n * 3. Compute the initial set of completed-step keys (used by the loop\n * to skip steps already done in a previous run).\n */\nimport type {\n WorkflowDefinition,\n WorkflowContext,\n Logger,\n SpawnChildOptions,\n} from '../types';\nimport type { EventTransport } from '../../events/types';\nimport { WorkflowTimeoutError } from '../../utils/errors';\nimport { createScopedLogger } from '../../utils/logger';\nimport { safeEmitEvent } from './persistence';\n\n/**\n * Inputs needed to resolve a workflow plan + build its execution context.\n */\nexport interface BuildContextOptions {\n runId: string;\n definition: WorkflowDefinition;\n input: Record<string, unknown>;\n metadata: Record<string, unknown>;\n events: EventTransport;\n logger: Logger;\n abortController: AbortController;\n spawnChild: (options: SpawnChildOptions) => Promise<string>;\n /** Existing checkpoint results to preload into context.results. */\n checkpointResults?: Record<string, unknown>;\n}\n\n/**\n * Build the WorkflowContext that will be threaded through every step\n * handler. On resume, preload `context.results` from the checkpoint.\n */\nexport function buildContext(options: BuildContextOptions): WorkflowContext {\n const {\n runId,\n definition,\n input,\n metadata,\n events,\n logger,\n abortController,\n spawnChild,\n checkpointResults,\n } = options;\n\n return {\n runId,\n stepId: '', // set per-step by the step-runner before each handler call\n kind: definition.kind,\n input,\n results: checkpointResults ? { ...checkpointResults } : {},\n metadata,\n logger: createScopedLogger(logger, runId),\n signal: abortController.signal,\n spawnChild,\n emit: (eventType: string, payload?: unknown) => {\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType,\n timestamp: new Date(),\n payload,\n });\n },\n };\n}\n\n/**\n * Handle returned by setupWorkflowTimeout. The orchestrator must call\n * `clear()` on both success and failure paths to release the timer, and\n * may read `getTimeoutError()` in the catch path: if non-null, the abort\n * was triggered by our timeout (not user cancellation), and the caller\n * should surface that error instead of the generic abort-derived one.\n */\nexport interface WorkflowTimeoutHandle {\n clear: () => void;\n getTimeoutError: () => WorkflowTimeoutError | undefined;\n}\n\n/**\n * Arm a workflow-level timeout if the definition specifies one.\n *\n * On fire: constructs a WorkflowTimeoutError (recoverable via\n * `getTimeoutError`) and aborts the controller, which causes any\n * in-flight step handler racing the abort signal to reject.\n *\n * If the definition has no timeout, returns no-op handles.\n */\nexport function setupWorkflowTimeout(\n runId: string,\n definition: WorkflowDefinition,\n abortController: AbortController\n): WorkflowTimeoutHandle {\n if (!definition.timeout) {\n return {\n clear: () => {},\n getTimeoutError: () => undefined,\n };\n }\n\n let timeoutError: WorkflowTimeoutError | undefined;\n const timeoutId = setTimeout(() => {\n timeoutError = new WorkflowTimeoutError(runId, definition.timeout!);\n abortController.abort();\n }, definition.timeout);\n\n return {\n clear: () => clearTimeout(timeoutId),\n getTimeoutError: () => timeoutError,\n };\n}\n\n/**\n * Initial list of step keys to consider already complete — empty for a\n * fresh run, the checkpoint's set for a resume.\n */\nexport function initialCompletedSteps(\n checkpoint?: { completedStepKeys: Set<string> }\n): string[] {\n return checkpoint ? Array.from(checkpoint.completedStepKeys) : [];\n}\n","/**\n * Workflow Orchestrator\n *\n * This module is the heart of the workflow execution system.\n * It manages the execution of workflow steps, handles errors,\n * emits events, and persists state.\n */\n\nimport type {\n WorkflowDefinition,\n RunResult,\n Logger,\n SpawnChildOptions,\n} from './types';\nimport type { StorageAdapter } from '../storage/types';\nimport type { EventTransport } from '../events/types';\nimport { WorkflowEngineError, WorkflowCanceledError } from '../utils/errors';\nimport {\n markRunRunning,\n saveCheckpoint,\n markRunSucceeded,\n markRunFinal,\n safeEmitEvent,\n} from './orchestrator/persistence';\nimport { decideRunFinalState } from './orchestrator/state-transitions';\nimport { executeStep } from './orchestrator/step-runner';\nimport {\n buildContext,\n setupWorkflowTimeout,\n initialCompletedSteps,\n} from './orchestrator/plan-resolution';\n\n/**\n * Checkpoint data for resuming workflows.\n */\nexport interface WorkflowCheckpoint {\n /** Set of step keys that have been completed */\n completedStepKeys: Set<string>;\n /** Accumulated results from completed steps */\n results: Record<string, unknown>;\n}\n\n/**\n * Options for executing a workflow.\n */\nexport interface ExecuteOptions {\n /** The run ID */\n runId: string;\n /** The workflow definition */\n definition: WorkflowDefinition;\n /** Input parameters */\n input: Record<string, unknown>;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n /** Storage adapter */\n storage: StorageAdapter;\n /** Event transport */\n events: EventTransport;\n /** Logger instance */\n logger: Logger;\n /** Abort controller for cancellation */\n abortController: AbortController;\n /** Function to spawn child workflows */\n spawnChild: (options: SpawnChildOptions) => Promise<string>;\n /** Optional checkpoint for resuming from a previous execution */\n checkpoint?: WorkflowCheckpoint;\n}\n\n/**\n * Execute a workflow definition.\n * This is the main execution logic that runs all steps sequentially.\n */\nexport async function executeWorkflow(options: ExecuteOptions): Promise<RunResult> {\n const {\n runId,\n definition,\n input,\n metadata = {},\n storage,\n events,\n logger,\n abortController,\n spawnChild,\n checkpoint,\n } = options;\n\n const startTime = Date.now();\n const isResume = !!checkpoint;\n\n // Update run status to running (if not already)\n // On resume, don't overwrite the original startedAt\n await markRunRunning(storage, runId, isResume);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: isResume ? 'run.resumed' : 'run.started',\n timestamp: new Date(),\n payload: isResume ? { resumedFrom: Array.from(checkpoint.completedStepKeys) } : undefined,\n });\n\n const completedSteps = initialCompletedSteps(checkpoint);\n\n const context = buildContext({\n runId,\n definition,\n input,\n metadata,\n events,\n logger,\n abortController,\n spawnChild,\n checkpointResults: checkpoint?.results,\n });\n\n const timeoutHandle = setupWorkflowTimeout(runId, definition, abortController);\n const checkCancellation = () => {\n if (abortController.signal.aborted) throw new WorkflowCanceledError(runId);\n };\n let afterRunCalled = false;\n\n try {\n checkCancellation();\n // Execute beforeRun hook\n if (definition.hooks?.beforeRun) {\n await definition.hooks.beforeRun(context);\n }\n\n // Execute each step in sequence\n for (const step of definition.steps) {\n // Check for cancellation\n if (abortController.signal.aborted) {\n throw new WorkflowCanceledError(runId);\n }\n\n context.currentStep = step.key;\n\n // Skip already completed steps when resuming\n if (checkpoint?.completedStepKeys.has(step.key)) {\n logger.info(`Skipping step \"${step.key}\" (already completed in previous run)`);\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n payload: { reason: 'checkpoint' },\n });\n continue;\n }\n\n // Check skip condition\n if (step.skipIf) {\n const shouldSkip = await step.skipIf(context);\n if (shouldSkip) {\n logger.info(`Skipping step \"${step.key}\" (condition met)`);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'step.skipped',\n stepKey: step.key,\n timestamp: new Date(),\n });\n\n continue;\n }\n }\n\n // Execute the step\n const result = await executeStep(step, context, {\n definition,\n storage,\n events,\n logger,\n abortController,\n });\n\n // Store result in context\n context.results[step.key] = result;\n\n // Track completed step\n completedSteps.push(step.key);\n\n // Save checkpoint (accumulated results + completed steps)\n await saveCheckpoint(storage, runId, context.results, completedSteps);\n }\n\n checkCancellation();\n\n const duration = Date.now() - startTime;\n const runResult: RunResult = {\n status: 'succeeded',\n results: context.results,\n duration,\n };\n\n // Execute afterRun hook\n if (definition.hooks?.afterRun) {\n afterRunCalled = true;\n await definition.hooks.afterRun(context, runResult);\n }\n\n checkCancellation();\n // The run is complete from here on. Clear the timeout and do not check\n // cancellation after persisting success: an abort that arrives during the\n // final write (shutdown, timeout) must not relabel a succeeded run.\n timeoutHandle.clear();\n await markRunSucceeded(storage, runId, context.results);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType: 'run.completed',\n timestamp: new Date(),\n payload: { results: context.results, duration },\n });\n\n return runResult;\n\n } catch (error) {\n timeoutHandle.clear();\n\n const duration = Date.now() - startTime;\n\n const actualError = timeoutHandle.getTimeoutError() ?? error;\n const workflowError = WorkflowEngineError.fromError(actualError);\n\n // Determine final status + event type from the surfaced error.\n const { status, eventType } = decideRunFinalState(actualError);\n\n const runResult: RunResult = {\n status,\n results: context.results,\n error: workflowError,\n duration,\n };\n\n // Execute afterRun hook (even on failure)\n if (definition.hooks?.afterRun && !afterRunCalled) {\n try {\n await definition.hooks.afterRun(context, runResult);\n } catch (hookError) {\n logger.error('afterRun hook failed for run ' + runId + ':', hookError);\n }\n }\n\n // Update run status\n await markRunFinal(storage, runId, status, context.results, workflowError);\n\n safeEmitEvent(events, logger, {\n runId,\n kind: definition.kind,\n eventType,\n timestamp: new Date(),\n payload: { error: workflowError.message, duration },\n });\n\n return runResult;\n }\n}\n","/**\n * Concurrency control for the WorkflowEngine.\n *\n * Owns:\n * - the priority-ordered queue of pending runs (`runQueue`)\n * - the set of in-flight run abort controllers (`activeRuns`)\n * - the timer handles used to defer launches via setTimeout/setImmediate\n *\n * Responsibilities:\n * - `hasCapacity()` against the configured `maxConcurrency` ceiling\n * - priority-ordered enqueue (higher priority first, FIFO within a priority)\n * - dispatch loop that drains the queue while capacity exists, with a\n * try/catch around each dispatch so a single bad run cannot tear down\n * the loop and strand the rest of the queue (preserves the audit\n * 2026-04-27 C3 fix in `processQueue`).\n * - dispatch-failure telemetry: log + emit `run.failed` + best-effort\n * storage update with `QUEUE_DISPATCH_FAILED`.\n *\n * NOT responsible for:\n * - building the `executeWorkflow` invocation (that lives in WorkflowEngine\n * so the orchestrator/spawnChild wiring stays where it is)\n * - storage initialization / shutdown sequencing (see `lifecycle.ts`)\n */\n\nimport type { StorageAdapter } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport type { Logger, WorkflowDefinition } from '../types';\n\n/**\n * Queued run waiting to be executed when capacity is available.\n */\nexport interface QueuedRun {\n runId: string;\n definition: WorkflowDefinition;\n input: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n priority: number;\n queuedAt: Date;\n notBefore?: number;\n checkpoint?: { completedStepKeys: Set<string>; results: Record<string, unknown> };\n}\n\ntype TimerHandle = ReturnType<typeof setTimeout> | ReturnType<typeof setImmediate>;\n\nexport interface ConcurrencyManagerDeps {\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n /** Maximum concurrent runs; undefined or <=0 means unlimited. */\n maxConcurrency?: number;\n}\n\nexport class ConcurrencyManager {\n private readonly activeRuns = new Map<string, AbortController>();\n private readonly runQueue: QueuedRun[] = [];\n private readonly timerHandles = new Map<TimerHandle, () => void>();\n private readonly pendingOperations = new Set<Promise<unknown>>();\n private stopping = false;\n private readonly storage: StorageAdapter;\n private readonly events: EventTransport;\n private readonly logger: Logger;\n private readonly maxConcurrency: number | undefined;\n\n constructor(deps: ConcurrencyManagerDeps) {\n this.storage = deps.storage;\n this.events = deps.events;\n this.logger = deps.logger;\n this.maxConcurrency = deps.maxConcurrency;\n }\n\n hasCapacity(): boolean {\n if (this.stopping) return false;\n if (this.maxConcurrency === undefined || this.maxConcurrency <= 0) {\n return true;\n }\n return this.activeRuns.size < this.maxConcurrency;\n }\n\n getActiveCount(): number {\n return this.activeRuns.size;\n }\n\n getQueuedCount(): number {\n return this.runQueue.length;\n }\n\n isActive(runId: string): boolean {\n return this.activeRuns.has(runId);\n }\n\n isQueued(runId: string): boolean {\n return this.runQueue.some(run => run.runId === runId);\n }\n\n assertAccepting(): void {\n if (this.stopping) throw new Error('Workflow engine is shutting down');\n }\n\n /** Track execution and admission I/O so adapters stay open until it settles. */\n track<T>(operation: Promise<T>): Promise<T> {\n this.pendingOperations.add(operation);\n const cleanup = () => { this.pendingOperations.delete(operation); };\n operation.then(cleanup, cleanup);\n return operation;\n }\n\n beginShutdown(): void {\n this.stopping = true;\n this.clearTimers();\n this.runQueue.length = 0; // Persisted queued runs remain available for recovery.\n }\n\n /** Resolves true once tracked work settles, or false if `timeoutMs` elapses first. */\n async waitForIdle(timeoutMs?: number): Promise<boolean> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const deadline = timeoutMs === undefined ? undefined : new Promise<false>((resolve) => {\n timeoutId = setTimeout(() => resolve(false), timeoutMs);\n });\n const drain = (async () => {\n while (this.pendingOperations.size > 0) {\n await Promise.allSettled([...this.pendingOperations]);\n }\n return true as const;\n })();\n try {\n return await (deadline ? Promise.race([drain, deadline]) : drain);\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n }\n\n /** Insert a run in priority order (higher priority first, FIFO within same). */\n enqueue(run: QueuedRun): void {\n this.assertAccepting();\n let inserted = false;\n for (let i = 0; i < this.runQueue.length; i++) {\n if (run.priority > this.runQueue[i].priority) {\n this.runQueue.splice(i, 0, run);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n this.runQueue.push(run);\n }\n }\n\n /** Remove a run from the queue if present. Returns true if it was queued. */\n removeFromQueue(runId: string): boolean {\n const idx = this.runQueue.findIndex((q) => q.runId === runId);\n if (idx === -1) return false;\n this.runQueue.splice(idx, 1);\n return true;\n }\n\n registerActive(runId: string, controller: AbortController): void {\n this.assertAccepting();\n this.activeRuns.set(runId, controller);\n }\n\n unregisterActive(runId: string): void {\n this.activeRuns.delete(runId);\n }\n\n abortActive(runId: string): boolean {\n const controller = this.activeRuns.get(runId);\n if (!controller) return false;\n controller.abort();\n return true;\n }\n\n /**\n * Abort every in-flight run. `onAbort` is called for each run id before its\n * controller is signaled (so callers can log, emit, etc.).\n */\n abortAllActive(onAbort?: (runId: string) => void): void {\n for (const [runId, controller] of this.activeRuns) {\n if (onAbort) onAbort(runId);\n controller.abort();\n }\n }\n\n /** Forget all active-run bookkeeping without aborting (used during shutdown). */\n clearActive(): void {\n this.activeRuns.clear();\n }\n\n /**\n * Schedule a launch via setTimeout (when `delay` is truthy) or setImmediate\n * (otherwise). Tracks the handle so it can be cleared during shutdown.\n */\n scheduleLaunch(fn: () => void, delay?: number): void {\n this.assertAccepting();\n if (delay) {\n const handle = setTimeout(() => {\n this.timerHandles.delete(handle);\n fn();\n }, delay);\n this.timerHandles.set(handle, () => clearTimeout(handle));\n } else {\n const handle = setImmediate(() => {\n this.timerHandles.delete(handle);\n fn();\n });\n this.timerHandles.set(handle, () => clearImmediate(handle));\n }\n }\n\n clearTimers(): void {\n for (const cancel of this.timerHandles.values()) cancel();\n this.timerHandles.clear();\n }\n\n /**\n * Drain the queue while capacity is available, dispatching each item via\n * `dispatch(run)`. Each iteration is wrapped in try/catch so that a failure\n * dispatching one queued item (e.g., an event-transport that throws) cannot\n * tear down the loop and leave remaining items stuck in the queue. Failed\n * dispatches are logged, the run is marked as failed in storage as\n * best-effort telemetry, and the loop advances to the next item.\n *\n * Emits `run.dequeued` for each dispatched run (this is what the C3\n * resilience test exercises by having the emit throw).\n */\n processQueue(dispatch: (run: QueuedRun) => void): void {\n while (this.hasCapacity() && this.runQueue.length > 0) {\n const next = this.runQueue.shift()!;\n\n try {\n this.logger.debug(`Starting queued run ${next.runId}`);\n\n this.events.emit({\n runId: next.runId,\n kind: next.definition.kind,\n eventType: 'run.dequeued',\n timestamp: new Date(),\n });\n\n dispatch(next);\n } catch (err) {\n this.recordQueueDispatchFailure(next, err);\n }\n }\n }\n\n /**\n * Record a queue-dispatch failure: log it, emit a failure event, and\n * best-effort mark the run as failed in storage. All side-effects are\n * defensively wrapped so this method itself never throws.\n */\n private recordQueueDispatchFailure(queued: QueuedRun, err: unknown): void {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.error(`Failed to dispatch queued run ${queued.runId}`, err);\n\n try {\n this.events.emit({\n runId: queued.runId,\n kind: queued.definition.kind,\n eventType: 'run.failed',\n timestamp: new Date(),\n payload: { error: { code: 'QUEUE_DISPATCH_FAILED', message } },\n });\n } catch (emitErr) {\n this.logger.error(`Failed to emit dispatch-failure event for ${queued.runId}`, emitErr);\n }\n\n // Fire-and-forget; we don't want to block the queue loop on storage I/O.\n this.track(this.storage\n .updateRun(queued.runId, {\n status: 'failed',\n finishedAt: new Date(),\n error: { code: 'QUEUE_DISPATCH_FAILED', message },\n })\n .catch((updateErr) => {\n this.logger.error(`Failed to record dispatch failure for ${queued.runId}`, updateErr);\n }));\n }\n}\n","/**\n * Lifecycle and resume orchestration for the WorkflowEngine.\n *\n * Owns the cross-cutting \"engine itself\" lifecycle:\n * - `initialize()` — bring up storage adapters that need explicit init\n * (e.g., PostgresStorageAdapter)\n * - `shutdown()` — drain timers, abort in-flight runs, close transports\n * - `resumeRun()` / `getResumableRuns()` / `resumeAllInterrupted()` —\n * restart interrupted runs from their persisted checkpoints\n *\n * NOT responsible for:\n * - per-step execution (that lives in `orchestrator.ts`)\n * - queue/active/timer bookkeeping (that lives in `engine/concurrency.ts`;\n * this module delegates to a `ConcurrencyManager`)\n * - building the `executeWorkflow` invocation (the engine still owns that\n * so the orchestrator/spawnChild wiring stays in one place; this module\n * calls it via the injected `launchRun` callback)\n */\n\nimport type { StorageAdapter, WorkflowRunRecord } from '../../storage/types';\nimport type { EventTransport } from '../../events/types';\nimport type { Logger, WorkflowDefinition, WorkflowKind } from '../types';\nimport { RunNotFoundError, WorkflowNotFoundError } from '../../utils/errors';\nimport type { ConcurrencyManager } from './concurrency';\n\n/**\n * Callback the engine provides for actually launching a run. Lifecycle uses\n * it to start a resumed run with its checkpoint; the engine's implementation\n * registers the abort controller, schedules the launch via the concurrency\n * manager, and invokes the orchestrator.\n */\nexport type LaunchRunFn = (\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number,\n checkpoint?: { completedStepKeys: Set<string>; results: Record<string, unknown> }\n) => void;\n\nexport interface LifecycleManagerDeps {\n storage: StorageAdapter;\n events: EventTransport;\n logger: Logger;\n registry: Map<WorkflowKind, WorkflowDefinition>;\n concurrency: ConcurrencyManager;\n launchRun: LaunchRunFn;\n /** Maximum ms to wait for in-flight work during shutdown (default 30000). */\n shutdownTimeout?: number;\n}\n\nconst DEFAULT_SHUTDOWN_TIMEOUT_MS = 30_000;\n\nexport class LifecycleManager {\n private readonly storage: StorageAdapter;\n private readonly events: EventTransport;\n private readonly logger: Logger;\n private readonly registry: Map<WorkflowKind, WorkflowDefinition>;\n private readonly concurrency: ConcurrencyManager;\n private readonly launchRun: LaunchRunFn;\n private readonly shutdownTimeout: number;\n private shutdownPromise?: Promise<void>;\n\n constructor(deps: LifecycleManagerDeps) {\n this.storage = deps.storage;\n this.events = deps.events;\n this.logger = deps.logger;\n this.registry = deps.registry;\n this.concurrency = deps.concurrency;\n this.launchRun = deps.launchRun;\n this.shutdownTimeout = deps.shutdownTimeout ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;\n }\n\n /**\n * Initialize the engine's storage adapter if it requires it.\n * Safe to call when the adapter has no `initialize` hook.\n */\n async initialize(): Promise<void> {\n if (this.storage.initialize) {\n await this.storage.initialize();\n }\n }\n\n /**\n * Shutdown the engine gracefully:\n * 1. stop admission/dispatch and clear pending launch timers\n * 2. abort all in-flight runs\n * 3. await tracked execution and admission I/O\n * 4. close event and storage adapters, then drop active bookkeeping\n */\n shutdown(): Promise<void> {\n return this.shutdownPromise ??= this.performShutdown();\n }\n\n private async performShutdown(): Promise<void> {\n this.logger.info('Shutting down workflow engine...');\n\n this.concurrency.beginShutdown();\n\n this.concurrency.abortAllActive((runId) => {\n this.logger.debug(`Canceling active run: ${runId}`);\n });\n\n // Hooks and storage calls do not observe the abort signal, and a hook that\n // awaits shutdown() would otherwise deadlock, so bound the drain.\n const drained = await this.concurrency.waitForIdle(this.shutdownTimeout);\n if (!drained) {\n this.logger.warn(\n `Shutdown timed out after ${this.shutdownTimeout}ms waiting for in-flight work; closing adapters anyway`\n );\n }\n\n if (this.events.close) {\n this.events.close();\n }\n\n if (this.storage.close) {\n await this.storage.close();\n }\n\n this.concurrency.clearActive();\n this.logger.info('Workflow engine shutdown complete');\n }\n\n /**\n * Resume an interrupted workflow run from its checkpoint.\n * The run must be in 'queued' or 'running' status.\n */\n async resumeRun(runId: string): Promise<string> {\n this.concurrency.assertAccepting();\n const run = await this.storage.getRun(runId);\n this.concurrency.assertAccepting();\n if (!run) {\n throw new RunNotFoundError(runId);\n }\n\n if (!['queued', 'running'].includes(run.status)) {\n throw new Error(`Cannot resume run ${runId}: status is \"${run.status}\"`);\n }\n\n const definition = this.registry.get(run.kind);\n if (!definition) {\n throw new WorkflowNotFoundError(run.kind);\n }\n\n if (this.concurrency.isActive(runId) || this.concurrency.isQueued(runId)) {\n this.logger.warn(`Run ${runId} is already active or queued, skipping resume`);\n return runId;\n }\n\n this.logger.info(`Resuming run ${runId} from checkpoint`);\n\n const completedStepKeys = new Set(run.completedSteps ?? []);\n\n const checkpoint = {\n completedStepKeys,\n results: run.context,\n };\n if (this.concurrency.hasCapacity()) {\n this.launchRun(runId, definition, run.input, run.metadata, undefined, checkpoint);\n } else {\n this.concurrency.enqueue({\n runId, definition, input: run.input, metadata: run.metadata,\n priority: run.priority ?? 0, queuedAt: run.createdAt, checkpoint,\n });\n }\n\n return runId;\n }\n\n /**\n * Get all runs that were interrupted and can be resumed.\n * Returns runs with status 'queued' or 'running'.\n */\n async getResumableRuns(): Promise<WorkflowRunRecord[]> {\n const runs: WorkflowRunRecord[] = [];\n // Collect the snapshot before launching anything: advancing an offset while\n // resumed runs leave this filter would skip records.\n for (let offset = 0; ; ) {\n const result = await this.storage.listRuns({\n status: ['queued', 'running'], limit: 100, offset,\n });\n runs.push(...result.items);\n offset += result.items.length;\n if (result.items.length === 0 || offset >= result.total) return runs;\n }\n }\n\n /**\n * Resume every interrupted run whose workflow kind is currently registered.\n * Useful for recovering after a server restart.\n */\n async resumeAllInterrupted(): Promise<string[]> {\n const resumableRuns = await this.getResumableRuns();\n const resumedIds: string[] = [];\n\n for (const run of resumableRuns) {\n if (this.registry.has(run.kind)) {\n try {\n await this.resumeRun(run.id);\n resumedIds.push(run.id);\n } catch (error) {\n this.logger.error(`Failed to resume run ${run.id}:`, error);\n }\n } else {\n this.logger.warn(`Cannot resume run ${run.id}: workflow \"${run.kind}\" not registered`);\n }\n }\n\n return resumedIds;\n }\n}\n","/**\n * Main WorkflowEngine class.\n *\n * This is the primary entry point for the workflow engine.\n * It provides methods for registering workflows, starting runs,\n * and managing workflow execution.\n *\n * Internal concerns are decomposed into co-located submodules under\n * `./engine/` (see `engine/concurrency.ts`, `engine/lifecycle.ts`).\n * WorkflowEngine itself stays the thin public face.\n */\n\nimport type {\n WorkflowKind,\n WorkflowDefinition,\n WorkflowContext,\n Logger,\n SpawnChildOptions,\n} from './types';\nimport type { StorageAdapter, WorkflowRunRecord } from '../storage/types';\nimport type { EventTransport, EventCallback, Unsubscribe, WorkflowEvent } from '../events/types';\nimport { MemoryStorageAdapter } from '../storage/memory';\nimport { MemoryEventTransport } from '../events/memory';\nimport { executeWorkflow } from './orchestrator';\nimport {\n WorkflowNotFoundError,\n WorkflowAlreadyRegisteredError,\n RunNotFoundError,\n WaitForRunTimeoutError,\n} from '../utils/errors';\nimport { ConsoleLogger } from '../utils/logger';\nimport { ConcurrencyManager, type QueuedRun } from './engine/concurrency';\nimport { LifecycleManager } from './engine/lifecycle';\nimport { safeEmitEvent } from './orchestrator/persistence';\n\n// ============================================================================\n// Configuration Types\n// ============================================================================\n\n/**\n * Configuration for the workflow engine.\n */\nexport interface WorkflowEngineConfig {\n /** Storage adapter for persistence (default: MemoryStorageAdapter) */\n storage?: StorageAdapter;\n\n /** Event transport for real-time updates (default: MemoryEventTransport) */\n events?: EventTransport;\n\n /** Logger instance (default: ConsoleLogger) */\n logger?: Logger;\n\n /** Global settings */\n settings?: {\n /** Default timeout for workflows in ms */\n defaultTimeout?: number;\n\n /** Maximum concurrent workflows */\n maxConcurrency?: number;\n\n /**\n * Maximum time in ms that shutdown waits for in-flight runs, hooks and\n * admission I/O before closing adapters anyway (default: 30000).\n */\n shutdownTimeout?: number;\n };\n}\n\n/**\n * Options for starting a workflow run.\n */\nexport interface StartRunOptions<TInput = Record<string, unknown>> {\n /** Workflow type to run */\n kind: WorkflowKind;\n\n /** Input parameters */\n input?: TInput;\n\n /** Optional metadata (e.g., userId, topicId) */\n metadata?: Record<string, unknown>;\n\n /** Parent run ID (for child workflows) */\n parentRunId?: string;\n\n /** Delay before starting (ms) */\n delay?: number;\n\n /** Priority for queue ordering (higher = runs first, default: 0) */\n priority?: number;\n}\n\n// ============================================================================\n// WorkflowEngine Class\n// ============================================================================\n\n/**\n * Main workflow engine class.\n *\n * @example\n * ```typescript\n * const engine = new WorkflowEngine({\n * storage: new MemoryStorageAdapter(),\n * });\n *\n * engine.registerWorkflow({\n * kind: 'my.workflow',\n * name: 'My Workflow',\n * steps: [\n * {\n * key: 'step1',\n * name: 'First Step',\n * handler: async (ctx) => {\n * return { message: 'Hello!' };\n * },\n * },\n * ],\n * });\n *\n * const runId = await engine.startRun({ kind: 'my.workflow' });\n * ```\n */\nexport class WorkflowEngine {\n private registry = new Map<WorkflowKind, WorkflowDefinition>();\n private storage: StorageAdapter;\n private events: EventTransport;\n private logger: Logger;\n private settings: NonNullable<WorkflowEngineConfig['settings']>;\n private concurrency: ConcurrencyManager;\n private lifecycle: LifecycleManager;\n\n constructor(config: WorkflowEngineConfig = {}) {\n this.storage = config.storage ?? new MemoryStorageAdapter();\n this.events = config.events ?? new MemoryEventTransport();\n this.logger = config.logger ?? new ConsoleLogger();\n this.settings = config.settings ?? {};\n this.concurrency = new ConcurrencyManager({\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n maxConcurrency: this.settings.maxConcurrency,\n });\n this.lifecycle = new LifecycleManager({\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n registry: this.registry,\n concurrency: this.concurrency,\n shutdownTimeout: this.settings.shutdownTimeout,\n launchRun: (runId, def, input, metadata, delay, checkpoint) =>\n this.launchRun(runId, def, input, metadata, delay, checkpoint),\n });\n }\n\n /**\n * Initialize the engine and its storage/event adapters.\n * Call this before starting runs if your storage adapter requires initialization\n * (e.g., PostgresStorageAdapter).\n */\n async initialize(): Promise<void> {\n return this.lifecycle.initialize();\n }\n\n /**\n * Get the current number of active runs.\n */\n getActiveRunCount(): number {\n return this.concurrency.getActiveCount();\n }\n\n /**\n * Get the number of queued runs waiting for capacity.\n */\n getQueuedRunCount(): number {\n return this.concurrency.getQueuedCount();\n }\n\n // ============================================================================\n // Workflow Registration\n // ============================================================================\n\n /**\n * Register a workflow definition.\n * Must be called before runs of this type can be started.\n *\n * @param definition - The workflow definition\n * @throws WorkflowAlreadyRegisteredError if already registered\n */\n registerWorkflow<TInput = Record<string, unknown>>(\n definition: WorkflowDefinition<TInput>\n ): void {\n if (this.registry.has(definition.kind)) {\n throw new WorkflowAlreadyRegisteredError(definition.kind);\n }\n this.registry.set(definition.kind, definition as WorkflowDefinition);\n this.logger.debug(`Registered workflow: ${definition.kind}`);\n }\n\n /**\n * Unregister a workflow definition.\n *\n * @param kind - The workflow kind to unregister\n * @returns true if the workflow was unregistered, false if not found\n */\n unregisterWorkflow(kind: WorkflowKind): boolean {\n const deleted = this.registry.delete(kind);\n if (deleted) {\n this.logger.debug(`Unregistered workflow: ${kind}`);\n }\n return deleted;\n }\n\n /**\n * Get a registered workflow definition.\n *\n * @param kind - The workflow kind\n * @returns The workflow definition or undefined\n */\n getWorkflow(kind: WorkflowKind): WorkflowDefinition | undefined {\n return this.registry.get(kind);\n }\n\n /**\n * Get all registered workflow kinds.\n */\n getRegisteredWorkflows(): WorkflowKind[] {\n return Array.from(this.registry.keys());\n }\n\n // ============================================================================\n // Run Management\n // ============================================================================\n\n /**\n * Start a new workflow run (non-blocking).\n * The run executes asynchronously and this method returns immediately.\n * If maxConcurrency is set and reached, the run is queued.\n *\n * @param options - Run options including kind and input\n * @returns The generated run ID\n * @throws WorkflowNotFoundError if the workflow kind is not registered\n */\n async startRun<TInput = Record<string, unknown>>(\n options: StartRunOptions<TInput>\n ): Promise<string> {\n this.concurrency.assertAccepting();\n return this.concurrency.track(this.createAndStartRun(options));\n }\n\n private async createAndStartRun<TInput>(options: StartRunOptions<TInput>): Promise<string> {\n const notBefore = Date.now() + (options.delay ?? 0);\n const definition = this.registry.get(options.kind);\n if (!definition) {\n throw new WorkflowNotFoundError(options.kind);\n }\n\n // Create run record (status: queued)\n const run = await this.storage.createRun({\n kind: options.kind,\n status: 'queued',\n parentRunId: options.parentRunId,\n input: (options.input ?? {}) as Record<string, unknown>,\n metadata: options.metadata ?? {},\n context: {},\n });\n\n const runId = run.id;\n this.concurrency.assertAccepting();\n\n // Emit run created event\n safeEmitEvent(this.events, this.logger, {\n runId,\n kind: options.kind,\n eventType: 'run.created',\n timestamp: new Date(),\n payload: { input: options.input, metadata: options.metadata, priority: options.priority ?? 0 },\n });\n\n // Check if we have capacity to start immediately\n if (this.concurrency.hasCapacity()) {\n // Start execution immediately\n this.executeRun(\n runId,\n definition,\n (options.input ?? {}) as Record<string, unknown>,\n options.metadata,\n Math.max(0, notBefore - Date.now())\n );\n } else {\n // Queue the run for later execution\n this.concurrency.enqueue({\n runId,\n definition,\n input: (options.input ?? {}) as Record<string, unknown>,\n metadata: options.metadata,\n priority: options.priority ?? 0,\n queuedAt: new Date(),\n notBefore,\n });\n\n this.logger.debug(`Run ${runId} queued (${this.concurrency.getQueuedCount()} in queue)`);\n\n // Emit queued event\n safeEmitEvent(this.events, this.logger, {\n runId,\n kind: options.kind,\n eventType: 'run.queued',\n timestamp: new Date(),\n payload: { queuePosition: this.concurrency.getQueuedCount() },\n });\n }\n\n return runId;\n }\n\n /**\n * Execute a run (internal method).\n */\n private executeRun(\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number\n ): void {\n this.launchRun(runId, definition, input, metadata, delay);\n }\n\n /**\n * Launch a workflow run asynchronously.\n * Shared by both executeRun (new runs) and resumeRun (checkpoint recovery).\n */\n private launchRun(\n runId: string,\n definition: WorkflowDefinition,\n input: Record<string, unknown>,\n metadata?: Record<string, unknown>,\n delay?: number,\n checkpoint?: { completedStepKeys: Set<string>; results: Record<string, unknown> }\n ): void {\n const abortController = new AbortController();\n this.concurrency.registerActive(runId, abortController);\n\n const execute = async () => {\n try {\n await executeWorkflow({\n runId,\n definition: { ...definition, timeout: definition.timeout ?? this.settings.defaultTimeout },\n input,\n metadata,\n storage: this.storage,\n events: this.events,\n logger: this.logger,\n abortController,\n spawnChild: (childOptions: SpawnChildOptions) => this.spawnChild(runId, childOptions),\n checkpoint,\n });\n } finally {\n this.concurrency.unregisterActive(runId);\n this.processQueue();\n }\n };\n\n // executeWorkflow has its own try/catch that converts errors into a failed\n // run record, but the surrounding `finally` (unregisterActive + processQueue)\n // could still throw, and `setTimeout`/`setImmediate` discards the returned\n // promise — leaving any rejection unhandled and capable of crashing Node.\n // Wrap the launch so those rejections are logged instead.\n const guarded = () => {\n this.concurrency.track(execute().catch((err) => {\n this.concurrency.unregisterActive(runId);\n this.logger.error(`Unhandled error launching run ${runId}`, err);\n }));\n };\n\n this.concurrency.scheduleLaunch(guarded, delay);\n }\n\n /**\n * Drain the queue, dispatching each ready run via `executeRun`. Resilience\n * against per-item dispatch failures lives in `ConcurrencyManager.processQueue`.\n */\n private processQueue(): void {\n this.concurrency.processQueue((next) => {\n this.launchRun(next.runId, next.definition, next.input, next.metadata,\n Math.max(0, (next.notBefore ?? 0) - Date.now()), next.checkpoint);\n });\n }\n\n /**\n * Start a child workflow from within a parent workflow.\n * Called internally by the context.spawnChild helper.\n */\n private async spawnChild(parentRunId: string, options: SpawnChildOptions): Promise<string> {\n return this.startRun({\n kind: options.kind,\n input: options.input,\n metadata: options.metadata,\n parentRunId,\n });\n }\n\n /**\n * Cancel a running workflow.\n * Signals the workflow to stop at the next cancellation point.\n *\n * @param runId - The run ID to cancel\n * @throws {RunNotFoundError} If no run with the given ID exists\n */\n async cancelRun(runId: string): Promise<void> {\n this.concurrency.assertAccepting();\n return this.concurrency.track(this.cancelTrackedRun(runId));\n }\n\n private async cancelTrackedRun(runId: string): Promise<void> {\n const run = await this.storage.getRun(runId);\n if (!run) {\n throw new RunNotFoundError(runId);\n }\n\n // Don't overwrite terminal statuses\n if (['succeeded', 'failed', 'canceled', 'timeout'].includes(run.status)) {\n return;\n }\n\n // Remove from queue if queued, then signal abort if active\n this.concurrency.removeFromQueue(runId);\n this.concurrency.abortActive(runId);\n\n // Update status in storage (the orchestrator will also update on completion)\n await this.storage.updateRun(runId, {\n status: 'canceled',\n finishedAt: new Date(),\n });\n\n safeEmitEvent(this.events, this.logger, {\n runId,\n kind: run.kind,\n eventType: 'run.canceled',\n timestamp: new Date(),\n });\n }\n\n /**\n * Get the current status of a run.\n *\n * @param runId - The run ID to look up\n * @returns The run record or null if not found\n */\n async getRunStatus(runId: string): Promise<WorkflowRunRecord | null> {\n return this.storage.getRun(runId);\n }\n\n private static readonly TERMINAL_STATUSES = ['succeeded', 'failed', 'canceled', 'timeout'];\n private static readonly TERMINAL_EVENT_TYPES = ['run.completed', 'run.failed', 'run.canceled', 'run.timeout'];\n\n /**\n * Wait for a run to complete.\n * Subscribes to run events and resolves when a terminal event fires.\n * Falls back to an initial storage read to avoid race conditions.\n *\n * @param runId - The run ID to wait for\n * @param options - Wait options\n * @returns The final run record\n */\n async waitForRun(\n runId: string,\n options: { timeout?: number } = {}\n ): Promise<WorkflowRunRecord> {\n const timeout = options.timeout ?? 60000;\n\n return new Promise<WorkflowRunRecord>(async (resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let unsubscribe: (() => void) | undefined;\n let settled = false;\n\n const cleanup = () => {\n if (timeoutId) clearTimeout(timeoutId);\n if (unsubscribe) unsubscribe();\n };\n\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n cleanup();\n fn();\n };\n\n // Set up timeout\n timeoutId = setTimeout(() => {\n settle(() => reject(new WaitForRunTimeoutError(runId, timeout)));\n }, timeout);\n\n // Subscribe to run events FIRST to avoid missing terminal events\n unsubscribe = this.events.subscribe(runId, async (event) => {\n if (WorkflowEngine.TERMINAL_EVENT_TYPES.includes(event.eventType)) {\n try {\n const run = await this.storage.getRun(runId);\n settle(() => {\n if (!run) {\n reject(new RunNotFoundError(runId));\n } else {\n resolve(run);\n }\n });\n } catch (err) {\n settle(() => reject(err));\n }\n }\n });\n\n // THEN check storage for already-terminal runs\n try {\n const existingRun = await this.storage.getRun(runId);\n if (!existingRun) {\n settle(() => reject(new RunNotFoundError(runId)));\n return;\n }\n if (WorkflowEngine.TERMINAL_STATUSES.includes(existingRun.status)) {\n settle(() => resolve(existingRun));\n return;\n }\n } catch (err) {\n settle(() => reject(err));\n }\n });\n }\n\n // ============================================================================\n // Resume Support\n // ============================================================================\n\n /**\n * Resume an interrupted workflow run from its checkpoint.\n * The run must be in 'queued' or 'running' status.\n *\n * @param runId - The run ID to resume\n * @returns The run ID (same as input)\n * @throws {RunNotFoundError} If no run with the given ID exists\n * @throws {Error} If the run status is not 'queued' or 'running'\n * @throws {WorkflowNotFoundError} If the workflow kind is not registered\n */\n async resumeRun(runId: string): Promise<string> {\n return this.concurrency.track(this.lifecycle.resumeRun(runId));\n }\n\n /**\n * Get all runs that were interrupted and can be resumed.\n * Returns runs with status 'queued' or 'running'.\n */\n async getResumableRuns(): Promise<WorkflowRunRecord[]> {\n this.concurrency.assertAccepting();\n return this.concurrency.track(this.lifecycle.getResumableRuns());\n }\n\n /**\n * Resume all interrupted runs.\n * Useful for recovering after a server restart.\n *\n * @returns Array of resumed run IDs\n */\n async resumeAllInterrupted(): Promise<string[]> {\n this.concurrency.assertAccepting();\n return this.concurrency.track(this.lifecycle.resumeAllInterrupted());\n }\n\n // ============================================================================\n // Event Subscription\n // ============================================================================\n\n /**\n * Subscribe to events for a specific run.\n *\n * @param runId - The run ID to subscribe to\n * @param callback - Event handler\n * @returns Unsubscribe function\n */\n subscribeToRun(runId: string, callback: EventCallback): Unsubscribe {\n return this.events.subscribe(runId, callback);\n }\n\n /**\n * Subscribe to all workflow events.\n *\n * @param callback - Event handler\n * @returns Unsubscribe function\n */\n subscribeToAll(callback: EventCallback): Unsubscribe {\n return this.events.subscribeAll(callback);\n }\n\n // ============================================================================\n // Storage Access\n // ============================================================================\n\n /**\n * Get the storage adapter.\n * Useful for querying runs and steps directly.\n */\n getStorage(): StorageAdapter {\n return this.storage;\n }\n\n /**\n * Get the event transport.\n * Useful for custom event handling.\n */\n getEvents(): EventTransport {\n return this.events;\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n /**\n * Shutdown the engine gracefully.\n * Cancels all active runs and closes resources.\n */\n async shutdown(): Promise<void> {\n return this.lifecycle.shutdown();\n }\n}\n","/**\n * Shared condition evaluation helpers used by the planner and registry.\n *\n * Extracted to a single module so the planner's recipe scoring and the\n * registry's `query({ matchConditions })` filter cannot drift apart.\n */\n\nimport RE2 from 're2';\nimport type { ConditionOperator } from './types';\n\n/**\n * Maximum length (in characters) accepted for a `matches` regex pattern.\n *\n * Recipe conditions can come from user-supplied configuration; even with RE2's\n * linear-time guarantee, very large patterns waste CPU/memory at compile time\n * and inflate the per-evaluation cost. Cap the source length so a pathological\n * recipe cannot hand the planner a megabyte of regex.\n */\nexport const MAX_REGEX_PATTERN_LENGTH = 512;\n\n/**\n * Get a nested value from an object using dot notation.\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n path: string\n): unknown {\n return path.split('.').reduce<unknown>((current, key) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\n/**\n * Evaluate a single condition against a value.\n *\n * The `matches` operator uses RE2 (not the JS RegExp engine) to avoid\n * catastrophic-backtracking DoS from untrusted recipe inputs.\n */\nexport function evaluateCondition(\n operator: ConditionOperator,\n fieldValue: unknown,\n conditionValue: unknown\n): boolean {\n switch (operator) {\n case 'eq':\n return fieldValue === conditionValue;\n\n case 'neq':\n return fieldValue !== conditionValue;\n\n case 'gt':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue > conditionValue\n : false;\n\n case 'gte':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue >= conditionValue\n : false;\n\n case 'lt':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue < conditionValue\n : false;\n\n case 'lte':\n return typeof fieldValue === 'number' && typeof conditionValue === 'number'\n ? fieldValue <= conditionValue\n : false;\n\n case 'contains':\n if (typeof fieldValue === 'string' && typeof conditionValue === 'string') {\n return fieldValue.includes(conditionValue);\n }\n if (Array.isArray(fieldValue)) {\n return fieldValue.includes(conditionValue);\n }\n return false;\n\n case 'matches':\n if (typeof fieldValue === 'string' && typeof conditionValue === 'string') {\n if (conditionValue.length > MAX_REGEX_PATTERN_LENGTH) {\n return false;\n }\n try {\n return new RE2(conditionValue).test(fieldValue);\n } catch {\n return false;\n }\n }\n return false;\n\n case 'exists':\n return fieldValue !== undefined && fieldValue !== null && fieldValue !== '';\n\n case 'notExists':\n return fieldValue === undefined || fieldValue === null || fieldValue === '';\n\n default:\n return false;\n }\n}\n","/**\n * Recipe and Step Handler registries.\n * Provides storage and retrieval of recipes and handlers.\n */\n\nimport type { WorkflowStep } from '../core/types';\nimport { evaluateCondition, getNestedValue } from './evaluate-condition';\nimport type {\n Recipe,\n RecipeRegistry,\n RecipeQueryOptions,\n RegisteredStepHandler,\n StepHandlerRegistry,\n WorkflowKind,\n} from './types';\n\n// ============================================================================\n// Step Handler Registry Implementation\n// ============================================================================\n\n/**\n * In-memory implementation of the step handler registry.\n */\nexport class MemoryStepHandlerRegistry implements StepHandlerRegistry {\n private handlers = new Map<string, RegisteredStepHandler>();\n private tagIndex = new Map<string, Set<string>>();\n\n /** Register a step handler. Throws if a handler with the same ID is already registered. */\n register<TInput = Record<string, unknown>>(\n handler: RegisteredStepHandler<TInput>\n ): void {\n if (this.handlers.has(handler.id)) {\n throw new Error(`Step handler '${handler.id}' is already registered`);\n }\n\n this.handlers.set(handler.id, handler as RegisteredStepHandler);\n\n // Index by tags\n if (handler.tags) {\n for (const tag of handler.tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(handler.id);\n }\n }\n }\n\n /** Get a handler by its unique ID, or undefined if not registered. */\n get(id: string): RegisteredStepHandler | undefined {\n return this.handlers.get(id);\n }\n\n /** Check whether a handler with the given ID is registered. */\n has(id: string): boolean {\n return this.handlers.has(id);\n }\n\n /** List all registered step handlers. */\n list(): RegisteredStepHandler[] {\n return Array.from(this.handlers.values());\n }\n\n /** List all handlers tagged with the given tag. */\n listByTag(tag: string): RegisteredStepHandler[] {\n const ids = this.tagIndex.get(tag);\n if (!ids) return [];\n\n return Array.from(ids)\n .map(id => this.handlers.get(id))\n .filter((h): h is RegisteredStepHandler => h !== undefined);\n }\n\n /**\n * Resolve a handler reference to a WorkflowStep handler function.\n * Returns undefined if the handler is not found.\n */\n resolve(handlerRef: string): WorkflowStep['handler'] | undefined {\n const registered = this.handlers.get(handlerRef);\n return registered?.handler;\n }\n\n /**\n * Clear all registered handlers (useful for testing).\n */\n clear(): void {\n this.handlers.clear();\n this.tagIndex.clear();\n }\n}\n\n// ============================================================================\n// Recipe Registry Implementation\n// ============================================================================\n\n/**\n * In-memory implementation of the recipe registry.\n */\nexport class MemoryRecipeRegistry implements RecipeRegistry {\n private recipes = new Map<string, Recipe>();\n private kindIndex = new Map<WorkflowKind, Set<string>>();\n private variantIndex = new Map<string, string>(); // \"kind:variant\" -> recipeId\n private tagIndex = new Map<string, Set<string>>();\n\n /** Register a single recipe. Throws if a recipe with the same ID or kind:variant pair is already registered. */\n register(recipe: Recipe): void {\n if (this.recipes.has(recipe.id)) {\n throw new Error(`Recipe '${recipe.id}' is already registered`);\n }\n\n this.recipes.set(recipe.id, recipe);\n\n // Index by workflow kind\n if (!this.kindIndex.has(recipe.workflowKind)) {\n this.kindIndex.set(recipe.workflowKind, new Set());\n }\n this.kindIndex.get(recipe.workflowKind)!.add(recipe.id);\n\n // Index by kind:variant\n const variantKey = `${recipe.workflowKind}:${recipe.variant}`;\n if (this.variantIndex.has(variantKey)) {\n throw new Error(\n `Recipe variant '${recipe.variant}' for '${recipe.workflowKind}' is already registered`\n );\n }\n this.variantIndex.set(variantKey, recipe.id);\n\n // Index by tags\n if (recipe.tags) {\n for (const tag of recipe.tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(recipe.id);\n }\n }\n }\n\n /** Register multiple recipes at once. */\n registerAll(recipes: Recipe[]): void {\n for (const recipe of recipes) {\n this.register(recipe);\n }\n }\n\n /** Get a recipe by its unique ID, or undefined if not registered. */\n get(recipeId: string): Recipe | undefined {\n return this.recipes.get(recipeId);\n }\n\n /** Check whether a recipe with the given ID is registered. */\n has(recipeId: string): boolean {\n return this.recipes.has(recipeId);\n }\n\n /** Get all recipes registered for a given workflow kind. */\n getByKind(workflowKind: WorkflowKind): Recipe[] {\n const ids = this.kindIndex.get(workflowKind);\n if (!ids) return [];\n\n return Array.from(ids)\n .map(id => this.recipes.get(id))\n .filter((r): r is Recipe => r !== undefined);\n }\n\n /** Get the recipe for a specific workflow kind and variant combination. */\n getVariant(workflowKind: WorkflowKind, variant: string): Recipe | undefined {\n const variantKey = `${workflowKind}:${variant}`;\n const recipeId = this.variantIndex.get(variantKey);\n if (!recipeId) return undefined;\n return this.recipes.get(recipeId);\n }\n\n /**\n * Get the default recipe for a workflow kind.\n * Returns the 'default' variant if one exists, otherwise falls back to the\n * recipe with the lowest numeric priority value (lower number = higher precedence).\n */\n getDefault(workflowKind: WorkflowKind): Recipe | undefined {\n // First try to find a 'default' variant\n const defaultRecipe = this.getVariant(workflowKind, 'default');\n if (defaultRecipe) return defaultRecipe;\n\n // Fall back to the recipe with the lowest numeric priority (highest precedence).\n // Note: this ascending order is the inverse of RuleBasedPlanner.selectRecipe,\n // which uses descending priority as a tiebreaker in condition-based scoring.\n const recipes = this.getByKind(workflowKind);\n if (recipes.length === 0) return undefined;\n\n return recipes.reduce((lowest, current) => {\n const currentPriority = current.priority ?? 0;\n const lowestPriority = lowest.priority ?? 0;\n return currentPriority < lowestPriority ? current : lowest;\n });\n }\n\n /** List all variant names registered for a workflow kind. */\n listVariants(workflowKind: WorkflowKind): string[] {\n const recipes = this.getByKind(workflowKind);\n return recipes.map(r => r.variant);\n }\n\n /** Query recipes with optional filters for kind, variant, tags, and input conditions. */\n query(options: RecipeQueryOptions): Recipe[] {\n let results = this.list();\n\n if (options.workflowKind) {\n results = results.filter(r => r.workflowKind === options.workflowKind);\n }\n\n if (options.variant) {\n results = results.filter(r => r.variant === options.variant);\n }\n\n if (options.tags && options.tags.length > 0) {\n results = results.filter(r =>\n options.tags!.some(tag => r.tags?.includes(tag))\n );\n }\n\n if (options.matchConditions) {\n results = results.filter(r => {\n if (!r.conditions || r.conditions.length === 0) return true;\n return this.evaluateConditions(r.conditions, options.matchConditions!);\n });\n }\n\n return results;\n }\n\n /** List all registered recipes. */\n list(): Recipe[] {\n return Array.from(this.recipes.values());\n }\n\n /**\n * Clear all registered recipes (useful for testing).\n */\n clear(): void {\n this.recipes.clear();\n this.kindIndex.clear();\n this.variantIndex.clear();\n this.tagIndex.clear();\n }\n\n /**\n * Evaluate recipe conditions against an input.\n * Returns true if all conditions match.\n */\n private evaluateConditions(\n conditions: Recipe['conditions'],\n input: Record<string, unknown>\n ): boolean {\n if (!conditions || conditions.length === 0) return true;\n\n return conditions.every(condition => {\n const fieldValue = getNestedValue(input, condition.field);\n return evaluateCondition(condition.operator, fieldValue, condition.value);\n });\n }\n}\n\n// ============================================================================\n// Default Instances\n// ============================================================================\n\n/**\n * Create a combined registry that holds both recipes and step handlers.\n */\nexport interface CombinedRegistry {\n recipes: MemoryRecipeRegistry;\n handlers: MemoryStepHandlerRegistry;\n}\n\n/**\n * Create a new combined registry instance.\n */\nexport function createRegistry(): CombinedRegistry {\n return {\n recipes: new MemoryRecipeRegistry(),\n handlers: new MemoryStepHandlerRegistry(),\n };\n}\n","/**\n * Rule-based planner implementation.\n * Selects recipes and generates plans based on conditions and input analysis.\n */\n\nimport { generateId } from '../utils/id';\nimport { evaluateCondition, getNestedValue } from './evaluate-condition';\nimport type {\n Plan,\n PlannedStep,\n Planner,\n PlanModification,\n PlanningContext,\n PlanValidationResult,\n Recipe,\n RecipeCondition,\n RecipeRegistry,\n RecipeSelectionResult,\n ResourceEstimate,\n StepHandlerRegistry,\n WorkflowKind,\n} from './types';\n\n/**\n * Score a recipe's conditions against input.\n * Returns a score from 0-100 based on how well conditions match.\n */\nfunction scoreConditions(\n conditions: RecipeCondition[] | undefined,\n input: Record<string, unknown>\n): number {\n // No conditions = default match with low score\n if (!conditions || conditions.length === 0) {\n return 10;\n }\n\n let matched = 0;\n for (const condition of conditions) {\n const fieldValue = getNestedValue(input, condition.field);\n if (evaluateCondition(condition.operator, fieldValue, condition.value)) {\n matched++;\n }\n }\n\n // All conditions must match for any positive score\n if (matched < conditions.length) {\n return 0;\n }\n\n // Base score 50 ensures condition-matched recipes beat unconditional defaults (score 10).\n // Each additional condition adds 10 points, capped at 100 so forced recipes (100) still win.\n return Math.min(100, 50 + conditions.length * 10);\n}\n\n// ============================================================================\n// Rule-Based Planner Implementation\n// ============================================================================\n\n/**\n * Configuration for the RuleBasedPlanner.\n */\nexport interface RuleBasedPlannerConfig {\n /** Recipe registry to use */\n recipeRegistry: RecipeRegistry;\n\n /** Step handler registry for validation */\n handlerRegistry?: StepHandlerRegistry;\n\n /** Whether to validate handler references during planning */\n validateHandlers?: boolean;\n\n /** Resource estimation defaults (used by estimateResources) */\n resourceEstimates?: {\n /** Estimated API calls per step (default: 1) */\n apiCallsPerStep?: number;\n /** Estimated tokens per step (default: 500) */\n tokensPerStep?: number;\n /** Estimated duration per step in ms (default: 2000) */\n durationPerStep?: number;\n /** Estimated API calls per child workflow (default: 5) */\n apiCallsPerChild?: number;\n };\n}\n\n/**\n * Rule-based planner that selects recipes based on condition matching.\n */\nexport class RuleBasedPlanner implements Planner {\n private recipeRegistry: RecipeRegistry;\n private handlerRegistry?: StepHandlerRegistry;\n private validateHandlers: boolean;\n private resourceEstimates: Required<NonNullable<RuleBasedPlannerConfig['resourceEstimates']>>;\n\n constructor(config: RuleBasedPlannerConfig) {\n this.recipeRegistry = config.recipeRegistry;\n this.handlerRegistry = config.handlerRegistry;\n this.validateHandlers = config.validateHandlers ?? false;\n this.resourceEstimates = {\n apiCallsPerStep: config.resourceEstimates?.apiCallsPerStep ?? 1,\n tokensPerStep: config.resourceEstimates?.tokensPerStep ?? 500,\n durationPerStep: config.resourceEstimates?.durationPerStep ?? 2000,\n apiCallsPerChild: config.resourceEstimates?.apiCallsPerChild ?? 5,\n };\n }\n\n /**\n * Select the best recipe for a workflow kind and input.\n */\n async selectRecipe(\n workflowKind: WorkflowKind,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<RecipeSelectionResult> {\n // Check for forced recipe in hints\n if (context?.hints?.forceRecipeId) {\n const forced = this.recipeRegistry.get(context.hints.forceRecipeId);\n if (forced) {\n return {\n recipe: forced,\n score: 100,\n reason: `Forced recipe: ${context.hints.forceRecipeId}`,\n };\n }\n }\n\n // Check for preferred variant in hints\n if (context?.hints?.preferredVariant) {\n const preferred = this.recipeRegistry.getVariant(\n workflowKind,\n context.hints.preferredVariant\n );\n if (preferred) {\n return {\n recipe: preferred,\n score: 90,\n reason: `Preferred variant: ${context.hints.preferredVariant}`,\n };\n }\n }\n\n // Get all recipes for this workflow kind\n const recipes = this.recipeRegistry.getByKind(workflowKind);\n\n if (recipes.length === 0) {\n throw new Error(`No recipes found for workflow kind: ${workflowKind}`);\n }\n\n // Score each recipe\n const scored = recipes.map(recipe => ({\n recipe,\n conditionScore: scoreConditions(recipe.conditions, input),\n priorityScore: recipe.priority ?? 0,\n }));\n\n // Sort by condition score (desc), then priority (desc)\n scored.sort((a, b) => {\n if (b.conditionScore !== a.conditionScore) {\n return b.conditionScore - a.conditionScore;\n }\n return b.priorityScore - a.priorityScore;\n });\n\n // Find best matching recipe\n const best = scored.find(s => s.conditionScore > 0);\n\n if (best) {\n const reason = this.buildSelectionReason(best.recipe, input);\n return {\n recipe: best.recipe,\n score: best.conditionScore,\n reason,\n };\n }\n\n // Fall back to default recipe\n const defaultRecipe = this.recipeRegistry.getDefault(workflowKind);\n if (defaultRecipe) {\n return {\n recipe: defaultRecipe,\n score: 10,\n reason: `Fallback to default recipe: ${defaultRecipe.id}`,\n };\n }\n\n // Last resort: use first recipe\n return {\n recipe: recipes[0],\n score: 5,\n reason: `No matching recipe, using first available: ${recipes[0].id}`,\n };\n }\n\n /**\n * Generate a plan from a recipe and input.\n */\n async generatePlan(\n recipe: Recipe,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<Plan> {\n const modifications: PlanModification[] = [];\n\n // Start with recipe steps\n let steps = recipe.steps.map(step => this.recipeStepToPlannedStep(step));\n\n // Apply hint-based modifications\n if (context?.hints) {\n const { skipSteps, includeSteps, additionalConfig } = context.hints;\n\n // Mark steps to skip\n if (skipSteps && skipSteps.length > 0) {\n for (const stepKey of skipSteps) {\n const stepIndex = steps.findIndex(s => s.key === stepKey);\n if (stepIndex >= 0) {\n steps = steps.filter(s => s.key !== stepKey);\n modifications.push({\n type: 'remove_step',\n stepKey,\n value: null,\n reason: `Skipped via planning hints`,\n });\n }\n }\n }\n\n // Apply additional config to all steps\n if (additionalConfig) {\n for (const step of steps) {\n step.config = { ...step.config, ...additionalConfig };\n }\n modifications.push({\n type: 'modify_step',\n value: additionalConfig,\n reason: 'Applied additional config from planning hints',\n });\n }\n }\n\n // Apply constraint-based modifications\n if (context?.constraints) {\n const constraintMods = this.applyConstraints(steps, context.constraints);\n modifications.push(...constraintMods.modifications);\n steps = constraintMods.steps;\n }\n\n // Build the plan\n const plan: Plan = {\n id: generateId(),\n recipeId: recipe.id,\n variant: recipe.variant,\n modifications,\n steps,\n defaults: recipe.defaults ?? {},\n reasoning: this.buildPlanReasoning(recipe, modifications, context),\n createdAt: new Date(),\n };\n\n // Estimate resources\n plan.resourceEstimate = this.estimateResources(plan);\n\n return plan;\n }\n\n /**\n * Combined operation: select recipe and generate plan.\n */\n async plan(\n workflowKind: WorkflowKind,\n input: Record<string, unknown>,\n context?: PlanningContext\n ): Promise<Plan> {\n const selection = await this.selectRecipe(workflowKind, input, context);\n const plan = await this.generatePlan(selection.recipe, input, context);\n\n // Add selection reasoning to plan\n plan.reasoning = `${selection.reason}. ${plan.reasoning ?? ''}`.trim();\n\n return plan;\n }\n\n /**\n * Validate a plan before execution.\n */\n validatePlan(plan: Plan): PlanValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check plan has steps\n if (!plan.steps || plan.steps.length === 0) {\n errors.push('Plan has no steps');\n }\n\n // Check for duplicate step keys\n const stepKeys = new Set<string>();\n for (const step of plan.steps) {\n if (stepKeys.has(step.key)) {\n errors.push(`Duplicate step key: ${step.key}`);\n }\n stepKeys.add(step.key);\n }\n\n // Validate each step\n for (const step of plan.steps) {\n if (!step.key) {\n errors.push('Step missing key');\n }\n if (!step.name) {\n warnings.push(`Step '${step.key}' missing name`);\n }\n if (!step.handlerRef) {\n errors.push(`Step '${step.key}' missing handlerRef`);\n }\n\n // Validate handler exists (if registry available)\n if (this.validateHandlers && this.handlerRegistry) {\n if (!this.handlerRegistry.has(step.handlerRef)) {\n errors.push(`Step '${step.key}' references unknown handler: ${step.handlerRef}`);\n }\n }\n }\n\n // Check child workflows\n if (plan.childWorkflows) {\n for (const child of plan.childWorkflows) {\n if (!child.kind) {\n errors.push('Child workflow missing kind');\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n }\n\n /**\n * Estimate resources required for a plan.\n */\n estimateResources(plan: Plan): ResourceEstimate {\n const { apiCallsPerStep, tokensPerStep, durationPerStep, apiCallsPerChild } = this.resourceEstimates;\n\n const stepCount = plan.steps.length;\n const childCount = plan.childWorkflows?.length ?? 0;\n\n return {\n apiCalls: stepCount * apiCallsPerStep + childCount * apiCallsPerChild,\n tokens: stepCount * tokensPerStep,\n duration: stepCount * durationPerStep,\n };\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n /**\n * Convert a recipe step to a planned step.\n */\n private recipeStepToPlannedStep(step: Recipe['steps'][0]): PlannedStep {\n return {\n key: step.key,\n name: step.name,\n handlerRef: step.handlerRef,\n config: step.config ?? {},\n onError: step.onError,\n maxRetries: step.maxRetries,\n retryDelay: step.retryDelay,\n retryBackoff: step.retryBackoff,\n timeout: step.timeout,\n skipCondition: step.skipCondition,\n };\n }\n\n /**\n * Apply constraints to steps and generate modifications.\n */\n private applyConstraints(\n steps: PlannedStep[],\n constraints: NonNullable<PlanningContext['constraints']>\n ): { steps: PlannedStep[]; modifications: PlanModification[] } {\n const modifications: PlanModification[] = [];\n const perStepTimeout = constraints.maxDuration\n ? Math.floor(constraints.maxDuration / steps.length)\n : undefined;\n\n // Apply all constraint mutations in a single pass\n const modifiedSteps = steps.map(step => {\n const modified = { ...step };\n\n if (constraints.priority === 'speed') {\n modified.timeout = modified.timeout ? Math.min(modified.timeout, 30000) : 30000;\n modified.maxRetries = Math.min(modified.maxRetries ?? 3, 1);\n }\n\n if (constraints.priority === 'cost') {\n modified.maxRetries = 0;\n }\n\n if (perStepTimeout !== undefined) {\n modified.timeout = modified.timeout\n ? Math.min(modified.timeout, perStepTimeout)\n : perStepTimeout;\n }\n\n return modified;\n });\n\n // Record what was applied\n if (constraints.priority === 'speed') {\n modifications.push({\n type: 'set_default',\n value: { priority: 'speed' },\n reason: 'Optimized for speed: reduced timeouts and retries',\n });\n }\n if (constraints.priority === 'cost') {\n modifications.push({\n type: 'set_default',\n value: { priority: 'cost' },\n reason: 'Optimized for cost: disabled retries',\n });\n }\n if (constraints.maxDuration) {\n modifications.push({\n type: 'set_default',\n value: { maxDuration: constraints.maxDuration },\n reason: `Applied duration constraint: ${constraints.maxDuration}ms total`,\n });\n }\n\n return { steps: modifiedSteps, modifications };\n }\n\n /**\n * Build a human-readable selection reason.\n */\n private buildSelectionReason(\n recipe: Recipe,\n input: Record<string, unknown>\n ): string {\n const parts: string[] = [`Selected recipe: ${recipe.id}`];\n\n if (recipe.conditions && recipe.conditions.length > 0) {\n const conditionDescriptions = recipe.conditions.map(c => {\n const value = getNestedValue(input, c.field);\n return `${c.field} ${c.operator} ${JSON.stringify(c.value)} (actual: ${JSON.stringify(value)})`;\n });\n parts.push(`Matched conditions: ${conditionDescriptions.join(', ')}`);\n }\n\n if (recipe.priority !== undefined && recipe.priority > 0) {\n parts.push(`Priority: ${recipe.priority}`);\n }\n\n return parts.join('. ');\n }\n\n /**\n * Build reasoning text for a plan.\n */\n private buildPlanReasoning(\n recipe: Recipe,\n modifications: PlanModification[],\n context?: PlanningContext\n ): string {\n const parts: string[] = [];\n\n parts.push(`Using recipe '${recipe.name}' (${recipe.variant} variant)`);\n\n if (modifications.length > 0) {\n parts.push(`Applied ${modifications.length} modification(s)`);\n }\n\n if (context?.constraints) {\n const constraintList: string[] = [];\n if (context.constraints.priority) {\n constraintList.push(`priority=${context.constraints.priority}`);\n }\n if (context.constraints.maxDuration) {\n constraintList.push(`maxDuration=${context.constraints.maxDuration}ms`);\n }\n if (context.constraints.maxApiCalls) {\n constraintList.push(`maxApiCalls=${context.constraints.maxApiCalls}`);\n }\n if (constraintList.length > 0) {\n parts.push(`Constraints: ${constraintList.join(', ')}`);\n }\n }\n\n return parts.join('. ') + '.';\n }\n}\n"],"mappings":"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","names":[]}
|