eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
72 lines • 3.81 kB
TypeScript
import { AsyncLocalStorage } from 'node:async_hooks';
import type { CryptoKey } from '../encryption.js';
import type { FlushableStreamState } from '../flushable-stream.js';
import type { WorkflowMetadata } from '../workflow/get-workflow-metadata.js';
import type { StepMetadata } from './get-step-metadata.js';
/**
* Per-step cache entry for a `(runId, namespace)` writable stream.
*
* Holds the user-facing `WritableStream` and the shared `FlushableStreamState`
* driving the background pipe to the workflow server. Re-used so repeat calls
* to `getWritable()` within the same step return the same handle instead of
* spawning racing pipes — see https://github.com/vercel/workflow/issues/2058.
*/
export interface CachedWritable {
writable: WritableStream<any>;
state: FlushableStreamState;
}
export type StepContext = {
stepMetadata: StepMetadata;
workflowMetadata: WorkflowMetadata;
/** Deployment that owns the current workflow run, used for forwarded streams. */
workflowDeploymentId?: string;
/**
* Root run id of the current run's lineage (`$rootRunId`), so a nested
* `start()` inherits it without reloading the parent. Set by the runtime from
* the run it already has loaded.
*/
rootRunId?: string;
ops: Promise<void>[];
/**
* Operations that MUST be durably committed before the step's
* `step_completed`/`step_failed` event is written, because the workflow
* continuation triggered by that event depends on them.
*
* The canonical case is a step-initiated `AbortController.abort()`: the
* durable `hook_received` event records the cancellation in the workflow's
* event log. If it is flushed in the background (like `ops`), the workflow
* continuation enqueued by `step_completed` can run — and advance past the
* abort, dispatching a later step with a stale, non-aborted `signal` — before
* the `hook_received` event exists. Awaiting these inline before completion
* guarantees the abort is ordered ahead of any continuation that observes the
* step's result. Unlike these, `ops` holds best-effort real-time stream
* writes that should fire ASAP and are intentionally left in the background.
*
* Contract: producers MUST NOT push a promise that can reject — these are
* awaited only to enforce ordering, never to surface an outcome. A rejection
* here would propagate as an infra error (queue re-delivery), not the
* user-code failure path, so each producer swallows its own errors (see
* `reviveAbortController` in serialization.ts). The await sites also
* defensively `.catch()` so ordering is all this bucket can ever enforce.
*
* Required (not optional) so a new step-context construction site that
* forgets to wire it fails at compile time, rather than silently regressing
* the ordering guarantee back to background-flush behavior.
*/
preCompletionOps: Promise<void>[];
closureVars?: Record<string, any>;
encryptionKey?: CryptoKey;
writables?: Map<string, CachedWritable>;
/**
* Turbo mode only: a promise that resolves once the backgrounded
* `run_started` has landed (the run exists). Set when the step body runs
* optimistically — before `run_started`/`step_started` are confirmed — so a
* direct step-body world write (e.g. `setAttributes`, which
* resolves to a host-side `attr_set` create) can gate on it and never race
* ahead of the run's creation. `undefined` outside turbo and on the await
* path, where `run_started` was already durable before the body ran.
*/
runReadyBarrier?: Promise<unknown>;
};
export declare const contextStorage: AsyncLocalStorage<StepContext>;
//# sourceMappingURL=context-storage.d.ts.map