eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
158 lines • 7.72 kB
TypeScript
/**
* QuickJS WebAssembly (WASM) VM integration with the Workflow DevKit.
*
* This module provides the entry point for running workflows in the
* QuickJS VM engine instead of the `node:vm` engine. Both engines
* implement the same event-replay execution model, where every invocation:
*
* 1. Loads the full event log for the run
* 2. Runs the workflow function from the top in a fresh QuickJS VM,
* replaying the event log to resolve awaited primitives
* 3. On suspension: creates events + queues steps for new pending ops
* 4. On completion: creates run_completed
* 5. On failure: creates run_failed
*/
import type { Span } from '#compiled/@opentelemetry/api/index.js';
import { type Event, type RunInput, type WorkflowRun } from '#compiled/@workflow/world/index.js';
/**
* Returns true when the supplied preloaded events indicate this is the
* first workflow handler invocation for the run, i.e. the log contains
* nothing beyond `run_created` / `run_started`. In that case the
* preloaded events ARE the complete event log and the `events.list`
* round-trips can be skipped entirely.
*
* Crucially, if the world backfilled a missing `run_created` via the
* resilient start path, `preloadedEvents` contains it even when a fresh
* `events.list` might not (eventual consistency), so preferring the
* preloaded events on first invocation is also the more correct choice.
*
* Returns false when `preloadedEvents` is missing/empty so the caller
* falls back to the normal fetch path.
*
* Exported for unit testing.
*/
export declare function isFirstInvocation(preloadedEvents: readonly Event[] | undefined): boolean;
/**
* Run a workflow using the QuickJS WASM VM engine.
*
* This replaces the `node:vm` replay path (runWorkflow + EventsConsumer)
* with a QuickJS VM invocation that performs the same full event replay.
*
* Log position on writes. This engine follows the same rule as the node:vm
* replay loop for which writes tell the World where the writer stood (see the
* "Who names a position" table above `slotSnapshotParams` in `helpers.ts`):
*
* - Writes made from this invocation's view of the log (`step_created`,
* `wait_created`, `hook_created`, `hook_disposed`, `attr_set`, the abort
* `hook_received`, `wait_completed`, and the `step_created` + `step_failed`
* pair for an unserializable input) carry `eventCount`, and the page a
* World hands back is queued for the live VM through {@link QuickJSLogView}.
* - A single inline step's terminal write asks for the inline delta
* (`sinceCursor`) through `executeStep`, and so does a lone `hook_created`
* (see `dispatchPendingOps.deltaCursor`); the delta is queued the same
* way. The step executor's other writes carry nothing: it holds no log.
* - Run-terminal writes (`run_completed`, `run_failed`) and the terminal drain
* of pending ops carry nothing: nothing reads the log afterwards.
*
* What differs from the node engine is what "merge into the log" means. The
* node engine merges a returned page into the array it replays from. This
* engine holds a live VM that consumes events exactly once, in position
* order, so a returned page is queued and delivered ahead of the next
* `events.list`, which then only runs when the queue cannot account for the
* next position. Both engines fall back to a list for anything a page did
* not carry.
*/
export declare function runWorkflowWithQuickJS(params: {
workflowCode: string;
workflowName: string;
workflowRun: WorkflowRun;
/**
* Events returned inline by `events.create('run_started', ...)` or by
* the lazy hook fast path's `hook_received` preload. When they indicate
* a first invocation, or when `preloadedEventsComplete` attests they
* are the complete log, they are used as the event log instead of
* fetching via `events.list`, matching the node:vm engine's fast path.
*/
preloadedEvents?: Event[];
/**
* True when the caller has validated that `preloadedEvents` is the run's
* COMPLETE event log (e.g. the lazy hook fast path's hasMore-false
* replay preload). The first-invocation heuristic below only recognizes
* run_created/run_started-only preloads, so without this attestation a
* hook-resume preload would be discarded and refetched.
*/
preloadedEventsComplete?: boolean;
/**
* The `events.list` cursor positioned after the last of `preloadedEvents`,
* when the caller has one. Lets this invocation read incrementally from
* where the preload ended and ask for an inline delta against it. Without
* it the first read after the preload starts from the top of the log.
*/
preloadedCursor?: string | null;
/**
* Run input carried through the queue message on first delivery. Used
* as a last-resort fallback for `run_created.eventData.input` when
* the event log is incomplete.
*/
runInput?: RunInput;
/**
* The parent OTel span (the outer `WORKFLOW {workflowName}` span from
* `runtime.ts`). When supplied, VM lifecycle attributes are attached
* to it for end-to-end visibility.
*/
parentSpan?: Span;
/**
* Server-supplied per-run event ceiling from the run_started response
* (undefined ⇒ no enforcement). Mirrors the node:vm engine's guard:
* a runaway run is failed once its log reaches the ceiling. The throw
* propagates to the replay loop's catch in runtime.ts (the QuickJS
* dispatch runs inside that loop's try), which classifies it and
* records run_failed with MAX_EVENTS_EXCEEDED.
*/
maxEventsLimit?: number;
/**
* Queue delivery attempt of the message driving this invocation (from
* the queue handler's metadata; 1 = first delivery). Surfaced in
* diagnostics; crash recovery itself is driven by the ownership-lease
* decision table in the loop, not by the attempt count.
*/
deliveryAttempt?: number;
/**
* Queue message ID of the delivery driving this invocation, stamped as
* `ownerMessageId` on inline lazy step claims so wake replays defer to
* the in-flight body instead of requeueing the step.
*/
ownerMessageId?: string;
/** Request ID of the queue invocation, when the queue provides one. */
requestId?: string;
/**
* Queue namespace resolved at route registration (runtime.ts). Must be
* threaded into every message publish: the builders bake the namespace
* into generated routes, so consumers listen on `__<ns>_wkf_workflow_*`.
* A publish without it lands on `__wkf_workflow_*` and is never
* picked up.
*/
namespace?: string;
/**
* Run-origin trace carrier accessor from runtime.ts
* (getNextTraceCarrier). In the default `linked` trace mode every
* invocation must link back to the run's origin (workflow.start) in a
* star; capturing the current invocation context instead would chain
* invocations to each other and fragment the run view on async queues.
*/
nextTraceCarrier?: () => Promise<Record<string, string>>;
/**
* The wait this invocation is the delayed continuation for, if it is one
* (`WorkflowInvokePayload.waitContinuation`). Read only to decide the next
* continuation's idempotency key: a continuation that finds its own wait
* still pending has spent its key, so the re-arm has to advance the attempt
* or the world's dedupe window drops it and the wait loses its only timer.
*/
waitContinuation?: {
correlationId: string;
attempt: number;
};
}): Promise<{
timeoutSeconds?: number;
} | void>;
//# sourceMappingURL=quickjs-entrypoint.d.ts.map