@noetaris/harness 0.3.2 → 0.5.0

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 CHANGED
@@ -124,17 +124,20 @@ h.provide('model', runtime()) // per-run — supplied at agent.run
124
124
 
125
125
  ### Session Store
126
126
 
127
- `h.store()` adds persistence. The reserved `session` key is used by the framework to save and restore state across runs; all other keys are surfaced as `ctx.store.<name>`.
127
+ `h.store()` adds persistence. The reserved `session` key is used by the framework to save and restore state across runs.
128
128
 
129
129
  ```ts
130
130
  import { InMemorySessionStore } from '@noetaris/harness-store'
131
131
 
132
132
  h.store({
133
- session: new InMemorySessionStore(), // framework-managed lifecycle
134
- knowledge: new MyKnowledgeGraph(), // available as ctx.store.knowledge
133
+ session: new InMemorySessionStore(), // framework-managed lifecycle
135
134
  })
136
135
  ```
137
136
 
137
+ > **Note:** Only the `session` key is processed today. Surfacing additional
138
+ > store keys to steps as `ctx.store.<name>` is planned but not yet wired up —
139
+ > non-session keys passed to `h.store()` are currently ignored.
140
+
138
141
  The framework injects `ctx.sessionId` automatically on every run — no declaration in `Ctx` needed.
139
142
 
140
143
  ### Interrupts
@@ -187,6 +190,8 @@ const resumed = agent.resume(response, sessionId, interruptId)
187
190
  - ESM only (`"type": "module"`)
188
191
  - Zero runtime dependencies
189
192
 
193
+ See [LIMITATIONS.md](LIMITATIONS.md) for known limitations.
194
+
190
195
  ## Related Packages
191
196
 
192
197
  - [`@noetaris/harness-store`](https://github.com/noetaris-lab/harness-store) — session store implementations (`InMemorySessionStore`, `LocalFileSessionStore`, etc.)
package/dist/index.d.ts CHANGED
@@ -100,6 +100,189 @@ declare function isRequiredMarker(value: unknown): value is RequiredMarker;
100
100
  */
101
101
  declare function isRuntimeMarker(value: unknown): value is RuntimeMarker;
102
102
 
103
+ /**
104
+ * Identifies the agent and session for run-level observer callbacks.
105
+ */
106
+ interface RunContext {
107
+ readonly agentId: string;
108
+ readonly sessionId: string;
109
+ /**
110
+ * The UUID for this specific run invocation. Always present in RunContext
111
+ * passed to observer methods.
112
+ */
113
+ readonly runId: string;
114
+ /**
115
+ * Optional parent run UUID for cross-process trace correlation. Present
116
+ * when parentRunId was passed to agent.run() resources. Absent for top-level
117
+ * runs or when not provided by the caller.
118
+ */
119
+ readonly parentRunId?: string;
120
+ /**
121
+ * The physical instance ID of the agent process, if configured via
122
+ * `createAgent()` options. Absent when `instanceId` was not provided.
123
+ */
124
+ readonly instanceId?: string;
125
+ /**
126
+ * Branch-name path (outermost to innermost), present only when this context describes a
127
+ * fork branch's own nested run rather than the top-level run. A branch is implemented as
128
+ * its own recursive runLoop call, so it fires onRunStart/onRunEnd on the same observer as
129
+ * the top-level run, under the same runId — this field is what makes those distinguishable
130
+ * from the real top-level pair. Absent for the top-level run.
131
+ */
132
+ readonly branchPath?: readonly string[];
133
+ }
134
+ /**
135
+ * Identifies the agent, session, and current step for step-level observer callbacks.
136
+ */
137
+ interface StepContext {
138
+ readonly agentId: string;
139
+ readonly sessionId: string;
140
+ readonly stepName: string;
141
+ /**
142
+ * Branch-name path (outermost to innermost), present only when this step runs inside a
143
+ * fork branch. Absent for a step at the top level of the loop (including the fork node
144
+ * itself, which is one atomic step from the outer run's point of view).
145
+ */
146
+ readonly branchPath?: readonly string[];
147
+ }
148
+ /**
149
+ * Observability hook interface. All methods are optional — implement only
150
+ * the hooks you need.
151
+ *
152
+ * Pass an `Observer` implementation in `agent.run()` resources under the key
153
+ * `'observer'`, or bind it to an {@link ObserverAware} slot before running.
154
+ *
155
+ * LLM adapters emit `'llm.response'` events via `onEvent` carrying an
156
+ * `LLMUsageEvent` payload for token tracking.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * const obs: Observer = {
161
+ * onRunStart: (ctx) => console.log('run started', ctx.sessionId),
162
+ * onEvent: (ctx, type, payload) => metrics.record(type, payload),
163
+ * }
164
+ * agent.run({}, { llm, observer: obs })
165
+ * ```
166
+ */
167
+ interface Observer {
168
+ /** Called once when a run begins, before the first step executes. */
169
+ onRunStart?: (ctx: RunContext) => void;
170
+ /** Called once when a run settles (completed or stopped). */
171
+ onRunEnd?: (ctx: RunContext, event: {
172
+ signal: string;
173
+ durationMs: number;
174
+ }) => void;
175
+ /** Called immediately before each step's `run` function is invoked. */
176
+ onStepStart?: (ctx: StepContext) => void;
177
+ /** Called after a step completes successfully. */
178
+ onStepEnd?: (ctx: StepContext, event: {
179
+ durationMs: number;
180
+ }) => void;
181
+ /** Called when a step's `run` function throws. */
182
+ onStepError?: (ctx: StepContext, event: {
183
+ error: unknown;
184
+ durationMs: number;
185
+ }) => void;
186
+ /** Called when a step issues a `ctx.interrupt()`. */
187
+ onInterrupt?: (ctx: StepContext, event: {
188
+ prompt: unknown;
189
+ interruptId: string;
190
+ }) => void;
191
+ /**
192
+ * Called for arbitrary named events emitted by step code via `ctx.emit()` or
193
+ * by LLM adapters (e.g. `'llm.response'`).
194
+ */
195
+ onEvent?: (ctx: StepContext, type: string, payload: unknown) => void;
196
+ }
197
+ /**
198
+ * The telemetry a resource needs to attribute an `invoke()` call to the correct
199
+ * run and step: the run's {@link Observer} and the current {@link StepContext}.
200
+ *
201
+ * The harness passes this per call rather than storing it on the resource instance,
202
+ * so concurrently-running fork branches that share one instance never race on it —
203
+ * each call carries its own context by value.
204
+ */
205
+ interface TelemetryContext {
206
+ readonly observer: Observer;
207
+ readonly stepContext: StepContext;
208
+ }
209
+ /**
210
+ * Implemented by resources (e.g. LLM adapters) that emit per-step telemetry.
211
+ *
212
+ * The harness calls {@link ObserverAware.withTelemetry} at the start of each step for every
213
+ * slot that exposes it, and installs the returned value as that slot on the step's `ctx`.
214
+ * Step code then calls the returned view (e.g. `ctx.llm.invoke(...)`) with no telemetry
215
+ * arguments, and the view forwards the {@link TelemetryContext} into the call it wraps — so
216
+ * telemetry travels *with the call* rather than living in mutable instance state.
217
+ *
218
+ * The return is typed `unknown` because core exports no LLM-domain type; a concrete adapter
219
+ * narrows it (e.g. to its `LLM` view). The harness treats the returned value as an opaque
220
+ * slot, exactly as it treats every provided slot.
221
+ */
222
+ interface ObserverAware {
223
+ /**
224
+ * Return a view of this resource scoped to the given telemetry. The harness installs
225
+ * the returned value as the resource's slot on the step's `ctx` before calling `step.run`.
226
+ * Called once per step (and once per step per branch), so each concurrent branch gets its
227
+ * own scoped view and there is no shared field to race on.
228
+ */
229
+ withTelemetry(ctx: TelemetryContext): unknown;
230
+ }
231
+ /**
232
+ * Combine multiple {@link Observer} instances into one. Each hook on the
233
+ * composite forwards to all constituent observers in order.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const observer = composeObservers([otelObserver, metricsObserver])
238
+ * ```
239
+ */
240
+ /**
241
+ * Identifies which observer hook threw. Passed to an {@link ObserverErrorSink}.
242
+ */
243
+ interface ObserverErrorContext {
244
+ /** The observer hook that threw, e.g. `'onStepStart'`, `'onRunEnd'`, `'onEvent'`. */
245
+ readonly hookName: string;
246
+ }
247
+ /**
248
+ * Opt-in sink for errors thrown by observer callbacks. Supplied under the
249
+ * `'onObserverError'` key in `agent.run()` / `agent.resume()` resources.
250
+ *
251
+ * Telemetry is a side-channel: an observer that throws must never crash a run.
252
+ * The harness routes every such throw here and continues. The sink is called at
253
+ * most once per failed hook invocation and MUST NOT rethrow into the run — if it
254
+ * does, the harness contains that too (see {@link safeInvoke}).
255
+ */
256
+ type ObserverErrorSink = (error: unknown, ctx: ObserverErrorContext) => void;
257
+ declare function composeObservers(observers: Observer[], onObserverError?: ObserverErrorSink): Observer;
258
+
259
+ type Cursor = string | ForkCursor;
260
+ /**
261
+ * Persisted/returned shape of a paused fork. Always lists every branch of the fork, in
262
+ * declaration order (never completion order — see decision #8). A branch never appears
263
+ * with an 'errored' status: an uncaught branch error always escalates to whole-fork
264
+ * failure (decision #9) rather than sitting here as a persisted per-branch state.
265
+ */
266
+ interface ForkCursor {
267
+ readonly kind: 'fork';
268
+ readonly fork: string;
269
+ readonly branches: readonly BranchCursor[];
270
+ }
271
+ type BranchCursor = {
272
+ readonly name: string;
273
+ readonly status: 'done';
274
+ readonly state: Record<string, unknown>;
275
+ readonly touchedKeys: readonly string[];
276
+ } | {
277
+ readonly name: string;
278
+ readonly status: 'paused';
279
+ readonly state: Record<string, unknown>;
280
+ readonly cursor: Cursor;
281
+ readonly touchedKeys: readonly string[];
282
+ };
283
+ /** Structural type guard distinguishing a ForkCursor from a plain step-name cursor. */
284
+ declare function isForkCursor(cursor: Cursor): cursor is ForkCursor;
285
+
103
286
  /**
104
287
  * Options passed to {@link SessionStore.claim}.
105
288
  *
@@ -236,7 +419,11 @@ interface SessionStore {
236
419
  * every run settles (either `'paused'` on an interrupt or `'completed'`).
237
420
  *
238
421
  * - `phase: 'paused'` — the run paused on an interrupt; `step` is the step that
239
- * issued the interrupt and `signal` is `'$interrupt'`.
422
+ * issued the interrupt and `signal` is `'$interrupt'`. `step` is a plain step name,
423
+ * or (when the run paused inside a fork) a composite `ForkCursor` carrying every
424
+ * branch's own state/cursor — see `Cursor` in `loop-executor.ts` and
425
+ * HANDOVER-fork-join.md §4/Phase 5. A plain-string `step` from before fork/join
426
+ * existed is still a valid `Cursor`, so old rows load and resume unchanged.
240
427
  * - `phase: 'completed'` — the loop exited normally; `signal` holds the exit
241
428
  * signal (or is absent when the loop ended without emitting a signal).
242
429
  */
@@ -251,7 +438,7 @@ interface StoredRun {
251
438
  readonly initialState: Record<string, unknown>;
252
439
  readonly finalState: Record<string, unknown>;
253
440
  readonly signal?: string;
254
- readonly step?: string;
441
+ readonly step?: Cursor;
255
442
  /**
256
443
  * Operational metadata written by the framework.
257
444
  *
@@ -268,7 +455,8 @@ interface StoredRun {
268
455
  * - `'in-flight'` — a run is currently executing (in-process guard only; not
269
456
  * detectable cross-process from the store alone).
270
457
  * - `'paused'` — the last run settled on an interrupt; `step` identifies the
271
- * step that issued the interrupt.
458
+ * step that issued the interrupt. When the run paused inside a fork, `step` is
459
+ * the fork's own name (not the richer per-branch detail — see `pendingInterrupts`).
272
460
  * - `'completed'` — the last run exited the loop; `signal` is the exit signal.
273
461
  */
274
462
  type SessionPhase = {
@@ -280,10 +468,28 @@ type SessionPhase = {
280
468
  readonly phase: 'paused';
281
469
  readonly signal?: string;
282
470
  readonly step: string;
471
+ /**
472
+ * Every interrupt currently awaiting a response, one per paused branch when the run
473
+ * paused inside a fork (a single-element array for a plain, non-forked pause). Lets a
474
+ * caller discover and resolve each one — via `Agent.resume(response, sessionId, id)` —
475
+ * independently; the session stays `'paused'` until every entry is resolved.
476
+ */
477
+ readonly pendingInterrupts: readonly PendingInterrupt[];
283
478
  } | {
284
479
  readonly phase: 'completed';
285
480
  readonly signal?: string;
286
481
  };
482
+ /** One outstanding `ctx.interrupt()` call awaiting a response. See {@link SessionPhase}. */
483
+ interface PendingInterrupt {
484
+ readonly interruptId: string;
485
+ readonly prompt: unknown;
486
+ /**
487
+ * The step that raised this interrupt. For a forked pause this is a `/`-joined
488
+ * breadcrumb (`"<fork>/<branch>/<step>"`, recursing further for nested forks) —
489
+ * same style as the validator's own fork/branch violation paths.
490
+ */
491
+ readonly step: string;
492
+ }
287
493
 
288
494
  /**
289
495
  * Options for background renewal mode.
@@ -408,20 +614,47 @@ interface StepDef {
408
614
  readonly next: string | undefined;
409
615
  readonly errorAware: boolean;
410
616
  }
617
+ /**
618
+ * A single `.branch(name, fn)` declaration inside a fork.
619
+ * definition is the branch's own, independently-captured LoopDefinition — built by running
620
+ * the branch's builder lambda against a fresh createLoopBuilder() instance. Inside a branch,
621
+ * `.end()` means "this branch is done," not "the run is done" (see LoopBuilder.branch).
622
+ */
623
+ interface BranchDef {
624
+ readonly name: string;
625
+ readonly definition: LoopDefinition;
626
+ }
627
+ /**
628
+ * Compiled fork node stored in LoopDefinition.steps alongside StepDef nodes.
629
+ * A fork has no run/route of its own — it never emits a signal, so .on() is not supported on it.
630
+ * next: explicit .next(name) target for the step that runs once every branch has settled
631
+ * (the "join"), or undefined to fall through to the next declared top-level node.
632
+ * Discriminated from StepDef structurally (see isForkDef) rather than via a tag field, so
633
+ * existing StepDef-only code and hand-built StepDef literals are unaffected.
634
+ */
635
+ interface ForkDef {
636
+ readonly name: string;
637
+ readonly branches: readonly BranchDef[];
638
+ readonly next: string | undefined;
639
+ }
640
+ /** A top-level node in a LoopDefinition: either an ordinary step or a fork. */
641
+ type LoopNode = StepDef | ForkDef;
642
+ /** Structural type guard distinguishing ForkDef from StepDef within a LoopNode. */
643
+ declare function isForkDef(node: LoopNode): node is ForkDef;
411
644
  /**
412
645
  * Complete loop topology captured from the builder lambda.
413
646
  * Immutable snapshot — produced once, consumed by LoopValidator and (later) F6.
414
647
  *
415
648
  * startCalled: true if l.start() was invoked at least once.
416
- * entryStep: name of the first .step() declared after .start() was called; undefined if .start()
417
- * was never called or no step was declared after it.
418
- * steps: all declared steps in declaration order.
649
+ * entryStep: name of the first .step()/.fork() declared after .start() was called; undefined if
650
+ * .start() was never called or no node was declared after it.
651
+ * steps: all declared top-level nodes (steps and forks) in declaration order.
419
652
  * onError: the fallback step name from l.onError(), or undefined if not set.
420
653
  */
421
654
  interface LoopDefinition {
422
655
  readonly startCalled: boolean;
423
656
  readonly entryStep: string | undefined;
424
- readonly steps: readonly StepDef[];
657
+ readonly steps: readonly LoopNode[];
425
658
  readonly onError: string | undefined;
426
659
  }
427
660
  /**
@@ -439,13 +672,40 @@ interface OnChain<S, Ctx> {
439
672
  * All methods mutate internal state and return `this` for chaining.
440
673
  */
441
674
  interface LoopBuilder<S, Ctx> {
442
- /** Mark the loop as having a declared entry. The first .step() called after .start() is the entry. */
675
+ /** Mark the loop as having a declared entry. The first .step()/.fork() called after .start() is the entry. */
443
676
  start(): LoopBuilder<S, Ctx>;
444
677
  /** Declare a step. At least one of run or route must be set (validated later by LoopValidator). */
445
678
  step(name: string, options: StepOptions<S, Ctx>): LoopBuilder<S, Ctx>;
679
+ /**
680
+ * Declare a fork: a named node that splits execution into 2+ concurrent branches, declared
681
+ * with .branch() immediately after. The step immediately following the fork automatically
682
+ * waits for every branch to settle (the "join") — no separate join primitive exists.
683
+ *
684
+ * Per-step telemetry is attributed correctly across concurrent branches: the harness scopes
685
+ * each branch's slots per step via {@link ObserverAware.withTelemetry}, so telemetry travels
686
+ * with the call rather than through shared instance state. See `ObserverAware`'s doc comment
687
+ * (`agent/observer.ts`).
688
+ */
689
+ fork(name: string): LoopBuilder<S, Ctx>;
690
+ /**
691
+ * Declare one branch of the fork most recently opened with .fork(). Must be called immediately
692
+ * after .fork() or another .branch() on the same fork — throws otherwise.
693
+ * builderFn receives a fresh LoopBuilder scoped to this branch, using the same .step()/.on()/
694
+ * .next() vocabulary as the top level; inside it, .end() means "this branch is done," not
695
+ * "the run is done."
696
+ */
697
+ branch(name: string, builderFn: (b: LoopBuilder<S, Ctx>) => void): LoopBuilder<S, Ctx>;
698
+ /**
699
+ * Declare the step that runs once every branch of the preceding fork has settled.
700
+ * Pure alias of .step(name, options) — not enforced by the validator, just a naming
701
+ * convenience so the DSL reads as fork/branch/join.
702
+ */
703
+ join(name: string, options: StepOptions<S, Ctx>): LoopBuilder<S, Ctx>;
446
704
  /**
447
705
  * Begin a signal transition declaration. Must be called immediately after .step() or after
448
706
  * a previous .on().to() or .on().end() chain (attaches to the most recently declared step).
707
+ * Throws if the most recently declared node is a fork — a fork has no run/route to emit
708
+ * a signal from.
449
709
  */
450
710
  on(signal: string): OnChain<S, Ctx>;
451
711
  /**
@@ -723,120 +983,4 @@ declare class LeaseExpiredError extends Error {
723
983
  constructor(sessionId: string);
724
984
  }
725
985
 
726
- /**
727
- * Identifies the agent and session for run-level observer callbacks.
728
- */
729
- interface RunContext {
730
- readonly agentId: string;
731
- readonly sessionId: string;
732
- /**
733
- * The UUID for this specific run invocation. Always present in RunContext
734
- * passed to observer methods.
735
- */
736
- readonly runId: string;
737
- /**
738
- * Optional parent run UUID for cross-process trace correlation. Present
739
- * when parentRunId was passed to agent.run() resources. Absent for top-level
740
- * runs or when not provided by the caller.
741
- */
742
- readonly parentRunId?: string;
743
- /**
744
- * The physical instance ID of the agent process, if configured via
745
- * `createAgent()` options. Absent when `instanceId` was not provided.
746
- */
747
- readonly instanceId?: string;
748
- }
749
- /**
750
- * Identifies the agent, session, and current step for step-level observer callbacks.
751
- */
752
- interface StepContext {
753
- readonly agentId: string;
754
- readonly sessionId: string;
755
- readonly stepName: string;
756
- }
757
- /**
758
- * Observability hook interface. All methods are optional — implement only
759
- * the hooks you need.
760
- *
761
- * Pass an `Observer` implementation in `agent.run()` resources under the key
762
- * `'observer'`, or bind it to an {@link ObserverAware} slot before running.
763
- *
764
- * LLM adapters emit `'llm.response'` events via `onEvent` carrying an
765
- * `LLMUsageEvent` payload for token tracking.
766
- *
767
- * @example
768
- * ```ts
769
- * const obs: Observer = {
770
- * onRunStart: (ctx) => console.log('run started', ctx.sessionId),
771
- * onEvent: (ctx, type, payload) => metrics.record(type, payload),
772
- * }
773
- * agent.run({}, { llm, observer: obs })
774
- * ```
775
- */
776
- interface Observer {
777
- /** Called once when a run begins, before the first step executes. */
778
- onRunStart?: (ctx: RunContext) => void;
779
- /** Called once when a run settles (completed or stopped). */
780
- onRunEnd?: (ctx: RunContext, event: {
781
- signal: string;
782
- durationMs: number;
783
- }) => void;
784
- /** Called immediately before each step's `run` function is invoked. */
785
- onStepStart?: (ctx: StepContext) => void;
786
- /** Called after a step completes successfully. */
787
- onStepEnd?: (ctx: StepContext, event: {
788
- durationMs: number;
789
- }) => void;
790
- /** Called when a step's `run` function throws. */
791
- onStepError?: (ctx: StepContext, event: {
792
- error: unknown;
793
- durationMs: number;
794
- }) => void;
795
- /** Called when a step issues a `ctx.interrupt()`. */
796
- onInterrupt?: (ctx: StepContext, event: {
797
- prompt: unknown;
798
- interruptId: string;
799
- }) => void;
800
- /**
801
- * Called for arbitrary named events emitted by step code via `ctx.emit()` or
802
- * by LLM adapters (e.g. `'llm.response'`).
803
- */
804
- onEvent?: (ctx: StepContext, type: string, payload: unknown) => void;
805
- }
806
- /**
807
- * Implemented by resources (e.g. LLM adapters) that accept an {@link Observer}
808
- * at run time. The harness calls `bindObserver` on every slot value that
809
- * implements this interface before the first step runs.
810
- *
811
- * Optionally, the harness calls `setStepContext` at the start of each step for
812
- * every slot that exposes it. Adapters use this to attribute per-step telemetry
813
- * (e.g. `observer.onEvent`) to the correct step without manual calls from step code.
814
- */
815
- interface ObserverAware {
816
- /**
817
- * Receive the run's observer. The harness calls this once per `agent.run()`
818
- * invocation before execution begins.
819
- */
820
- bindObserver(observer: Observer): void;
821
- /**
822
- * Receive the current step context. The harness calls this at the start of
823
- * each step for every slot that exposes this method, before calling `step.run`.
824
- *
825
- * Adapters that emit `observer.onEvent` in their `invoke()` method store the
826
- * provided `StepContext` and use it as the first argument to `onEvent`, so
827
- * events are attributed to the correct step automatically.
828
- */
829
- setStepContext?(ctx: StepContext): void;
830
- }
831
- /**
832
- * Combine multiple {@link Observer} instances into one. Each hook on the
833
- * composite forwards to all constituent observers in order.
834
- *
835
- * @example
836
- * ```ts
837
- * const observer = composeObservers(otelObserver, metricsObserver)
838
- * ```
839
- */
840
- declare function composeObservers(...observers: Observer[]): Observer;
841
-
842
- export { type Agent, type ClaimOptions, type DeepWithMarkers, type FieldDefinition, type FrameworkState, type Harness, type Lease, LeaseExpiredError, type LoopDefinition, LoopNotDefinedError, NoInterruptError, type Observer, type ObserverAware, REQUIRED_TAG, RUNTIME_TAG, type RequiredMarker, type RouteFn, type RunContext, type RunFn, type RuntimeMarker, SessionBusyError, SessionInFlightError, SessionPendingInterruptError, type SessionStore, type SignalTransition, type StateFromSchema, type StepContext, type StepDef, type StepState, StoreLoadError, type StoredRun, type StoredRunMetadata, type TransitionTarget, composeObservers, createAgent, createHarness, field, isRequiredMarker, isRuntimeMarker, required, runtime };
986
+ export { type Agent, type BranchCursor, type BranchDef, type ClaimOptions, type Cursor, type DeepWithMarkers, type FieldDefinition, type ForkCursor, type ForkDef, type FrameworkState, type Harness, type Lease, LeaseExpiredError, type LoopDefinition, type LoopNode, LoopNotDefinedError, NoInterruptError, type Observer, type ObserverAware, type ObserverErrorContext, type ObserverErrorSink, REQUIRED_TAG, RUNTIME_TAG, type RequiredMarker, type RouteFn, type RunContext, type RunFn, type RuntimeMarker, SessionBusyError, SessionInFlightError, SessionPendingInterruptError, type SessionStore, type SignalTransition, type StateFromSchema, type StepContext, type StepDef, type StepState, StoreLoadError, type StoredRun, type StoredRunMetadata, type TelemetryContext, type TransitionTarget, composeObservers, createAgent, createHarness, field, isForkCursor, isForkDef, isRequiredMarker, isRuntimeMarker, required, runtime };