Classes

Conditional

Class: Conditional

Defined in: src/core-flow/Conditional.ts:94

Every primitive (LLMCall, Agent), every composition (Sequence, Parallel, Conditional, Loop), and every pattern factory result implements Runner. That makes them freely nestable: any runner can be a child of any composition.

Extends

Constructors

Constructor

new Conditional(opts, branches, fallbackId): Conditional

Defined in: src/core-flow/Conditional.ts:107

Parameters

opts

ConditionalOptions

branches

readonly BranchEntry[]

fallbackId

string

Returns

Conditional

Overrides

RunnerBase.constructor

Properties

enable

readonly enable: EnableNamespace

Defined in: src/core/RunnerBase.ts:729

Enable-namespace for high-level observability features. Each method attaches a pre-built CombinedRecorder and returns an unsubscribe function. Consumers write ONE line to enable rich observability, instead of N .on() subscriptions.

Inherited from

RunnerBase.enable


id

readonly id: string

Defined in: src/core-flow/Conditional.ts:96


name

readonly name: string

Defined in: src/core-flow/Conditional.ts:95

Methods

attach()

attach(recorder): Unsubscribe

Defined in: src/core/RunnerBase.ts:554

Attach a footprintjs CombinedRecorder to observe every subsequent run.

LIFECYCLE CONTRACT (who owns cleanup):

  • Attached recorders live for the RUNNER's lifetime, not a run's. NOTHING auto-expires per-run — a recorder attached once observes every later run() until you call the returned Unsubscribe.
  • The CALLER owns cleanup. Keep the Unsubscribe and call it when the observer's life ends (request scope, UI unmount, test teardown).
  • Event listeners (on() / once()) follow the same rule, with two extra outs: pass { signal } for AbortSignal auto-cleanup, or call removeAllListeners() to bulk-drop listeners (listeners ONLY — recorders are not affected).
  • once() listeners are the only self-expiring subscription.

attach() is NOT idempotent: every call pushes another entry. (At run time footprintjs's executor dedupes recorders by ID, so same-ID duplicates won't double-fire — but the runner-side array still grows.) Attaching in a per-run loop without detaching is the classic server leak; attach once, or detach per-run.

WHEN it starts observing: the NEXT run. Recorders are handed to the executor when the executor is built, at run start, so one attached WHILE a run is in flight sees nothing of that run and everything of the one after — it is not dropped, it is early. Between runs (or before the first) is the ordinary case and works exactly as it reads. Event listeners are the opposite: on() takes effect immediately, but only for events emitted after it, so a listener added mid-run sees the rest of that run and none of its beginning.

Parameters

recorder

CombinedRecorder

Returns

Unsubscribe

Inherited from

RunnerBase.attach


closeToolSessions()

closeToolSessions(options?): Promise<number>

Defined in: src/core/RunnerBase.ts:722

End the tool sessions held for one hosting session.

The mechanism is the library's; the TIMING is yours. Nothing in this package can know when a request/reply session is over — a HostRequest carries a sessionId and no end, SessionLifecycle is hydrate/persist by design (a TTL, a scan or a delete is the STORE's own API, not a demand this port makes of every store that will ever implement it), and AWS itself does not tell you: an idle timeout is the reality. Guessing a boundary here would tear down a live sandbox mid-conversation.

So the composition root, which already owns the shape of the process, says when — the same doctrine that stops shutdownOn from grabbing signals by default. On the conversation door that is one line:

conversation.onClose(() => void agent.closeToolSessions({ sessionId }));

A request/reply deployment that knows its own boundary — a logout, a job finishing, a cart abandoned — calls the same method.

Never calling it is survivable, not silent: sessions idle out on the tier's lazy sweep, a bounded live count evicts the coldest, and shutdown() takes whatever is left.

Parameters

options?
reason?

TeardownReason

sessionId?

string

Returns

Promise<number>

how many cleanups ran. 0 when this runner holds none — a composition, or an agent whose tools never opened anything.

Example

host.onSessionEnd(async (sessionId) => {
    const closed = await agent.closeToolSessions({ sessionId });
    log.info({ sessionId, closed }, 'tool sessions released');
  });

Inherited from

RunnerBase.closeToolSessions


create()

static create(opts?): ConditionalBuilder

Defined in: src/core-flow/Conditional.ts:121

Parameters

opts?

ConditionalOptions = {}

Returns

ConditionalBuilder


emit()

emit(name, payload): void

Defined in: src/core/RunnerBase.ts:777

Emit a consumer-defined custom event.

If name matches a registered event type, this routes exactly like a library-emitted event (via the typed EventMap). Otherwise it flows through to wildcard listeners ('*') as an opaque CustomEvent with minimal meta. Library events remain reserved under agentfootprint.*.

Parameters

name

string

payload

Record<string, unknown>

Returns

void

Inherited from

RunnerBase.emit


getCommitCount()

getCommitCount(): number

Defined in: src/core/RunnerBase.ts:159

How many commits the run has written so far — footprintjs's executor.getCommitCount(), forwarded.

This is the run's TIME AXIS. One commit lands per executed stage, in order, so the count sampled at some moment is that moment's position in the run. Observers stamp it to say WHEN they fired: it is what boundaryRecorder({ getCommitCount }) records on every boundary, and the only reason a step strip can be rebuilt from a stored recording later. Sample it live, at the moment of the event — a number read once and captured is a number about the wrong instant.

0 before the first run, and during a run it climbs; between runs it is the last run's total. Cumulative across resume() on the same executor, and it counts the whole run — a subflow's own commits are kept out of the run-level log by footprintjs, so this is the parent timeline, not a sum of every nested one.

Returns

number

Inherited from

RunnerBase.getCommitCount


getLastSnapshot()

getLastSnapshot(): RuntimeSnapshot | undefined

Defined in: src/core/RunnerBase.ts:122

Returns the footprintjs snapshot from the most recent run. The snapshot is the CANONICAL STRUCTURE: nodes, edges, executionTree, runtimeStageId, commitLog.

Domain consumers (Lens, Trace, dashboards) read this for shape and join their own per-stage payload by runtimeStageId. They MUST NOT re-derive structure from typed events — that's the design footprintjs's CLAUDE.md Convention 1 explicitly forbids.

undefined before the first run() has STARTED. After that it is the most recent run's snapshot, including across multi-turn reuse of the same runner instance.

Live during a run. The executor is assigned at run start, so a caller reading this from inside a run — an event listener, a tool, a recorder — gets the IN-FLIGHT snapshot, partially filled, not the last completed one. RunnerBase.getSnapshot is the same value under the name that says so. Anything that must describe a FINISHED run has to capture at the terminal flush instead of polling this.

Returns

RuntimeSnapshot | undefined

Inherited from

RunnerBase.getLastSnapshot


getSnapshot()

getSnapshot(): RuntimeSnapshot | undefined

Defined in: src/core/RunnerBase.ts:137

Alias for getLastSnapshot() that mirrors FlowChartExecutor.getSnapshot() so consumers (lens, playground, ExplainableShell) can read the live or just-completed snapshot through the same method name they'd use on a footprintjs executor — without having to know whether they're holding an agentfootprint Runner or a raw executor.

During an active run, returns the live snapshot (commit log + execution tree built incrementally as stages execute). Between runs, returns the last completed run's snapshot. Undefined before any run has started.

Returns

RuntimeSnapshot | undefined

Inherited from

RunnerBase.getSnapshot


getSpec()

getSpec(): FlowChart

Defined in: src/core/RunnerBase.ts:182

Return the footprintjs FlowChart for this runner — the canonical design-time blueprint. STABLE REFERENCE across calls (getSpec() === getSpec()). Set once at construction via initChart().

Pairs with the run-time getters (getLastSnapshot, getCommitCount) and matches ExplainableShell.spec + specToReactFlow(spec, ...) consumer conventions. Its buildTimeStructure field is what a viewer draws — save it with the snapshot when storing a run, since no snapshot carries it.

DO NOT OVERRIDE in subclasses — the reference-identity contract (Lens / OpenAPI / MCP caches memo on this returning the same object) depends on the inherited body returning this.chart directly. To customise build behaviour, override buildChart() instead; this getter must remain a thin cache-read.

Returns

FlowChart

Inherited from

RunnerBase.getSpec


getUIGroup()

getUIGroup<T>(): T | undefined

Defined in: src/core/RunnerBase.ts:218

Return the consumer-shaped UI group for this composition — produced by invoking the consumer's groupTranslator (if attached) with this runner's GroupMetadata. Returns undefined when no translator was attached.

STABLE REFERENCE across calls. Computed on first access and cached; subsequent calls return the same value. Pairs with getSpec() — library shape on one side, consumer-shaped UI on the other.

Subclasses MUST override buildUIGroupMetadata() (the next hook) to supply the GroupMetadata for their composition kind. This method (the public surface) is final-by-convention — do not override.

Type Parameters

T

T = unknown

Returns

T | undefined

Inherited from

RunnerBase.getUIGroup


getUIGroupWith()

getUIGroupWith<T>(override): T | undefined

Defined in: src/core/RunnerBase.ts:262

Translate this runner's group metadata with a CALLER-SUPPLIED translator that overrides the runner's own default. Used by parent compositions to apply per-method translator overrides. See the Runner.getUIGroupWith JSDoc for the contract.

Type Parameters

T

T = unknown

Parameters

override

GroupTranslator<unknown>

Returns

T | undefined

Inherited from

RunnerBase.getUIGroupWith


listenerCount()

listenerCount(type?): number

Defined in: src/core/RunnerBase.ts:518

Diagnostic — how many event listeners this runner currently retains. No argument = total across all buckets (the leak-detection number); with a subscription key = that bucket only. Delegates to EventDispatcher.listenerCount().

Parameters

type?

keyof AgentfootprintEventMap | WildcardSubscription

Returns

number

Inherited from

RunnerBase.listenerCount


off()

Call Signature

off<K>(type, listener): void

Defined in: src/core/RunnerBase.ts:461

Unsubscribe a previously-registered listener.

Type Parameters
K

K extends keyof AgentfootprintEventMap

Parameters
type

K

listener

EventListener<K>

Returns

void

Inherited from

RunnerBase.off

Call Signature

off(type, listener): void

Defined in: src/core/RunnerBase.ts:462

Parameters
type

WildcardSubscription

listener

WildcardListener

Returns

void

Inherited from

RunnerBase.off


on()

Call Signature

on<K>(type, listener, options?): Unsubscribe

Defined in: src/core/RunnerBase.ts:438

Subscribe a typed listener. Returns unsubscribe.

Lifecycle: the subscription lives until you call the returned Unsubscribe, the { signal } you passed aborts, or removeAllListeners() runs. Nothing auto-expires per-run — pass a per-run AbortSignal for request-scoped listeners on long-lived runners (servers).

Type Parameters
K

K extends keyof AgentfootprintEventMap

Parameters
type

K

listener

EventListener<K>

options?

ListenOptions

Returns

Unsubscribe

Inherited from

RunnerBase.on

Call Signature

on(type, listener, options?): Unsubscribe

Defined in: src/core/RunnerBase.ts:443

Subscribe to a domain wildcard (e.g. 'agentfootprint.context.') or ''.

Parameters
type

WildcardSubscription

listener

WildcardListener

options?

ListenOptions

Returns

Unsubscribe

Inherited from

RunnerBase.on


once()

Call Signature

once<K>(type, listener, options?): Unsubscribe

Defined in: src/core/RunnerBase.ts:472

Subscribe a one-shot listener (fires once then auto-removes). Accepts { signal }.

Type Parameters
K

K extends keyof AgentfootprintEventMap

Parameters
type

K

listener

EventListener<K>

options?

Omit<ListenOptions, "once">

Returns

Unsubscribe

Inherited from

RunnerBase.once

Call Signature

once(type, listener, options?): Unsubscribe

Defined in: src/core/RunnerBase.ts:477

Parameters
type

WildcardSubscription

listener

WildcardListener

options?

Omit<ListenOptions, "once">

Returns

Unsubscribe

Inherited from

RunnerBase.once


removeAllListeners()

removeAllListeners(): void

Defined in: src/core/RunnerBase.ts:508

Lifecycle escape hatch — drop EVERY event listener on this runner in one call (typed, domain-wildcard, and '*'). Delegates to EventDispatcher.removeAllListeners().

For long-lived runners on servers: when you can't thread an AbortSignal or keep every Unsubscribe handle, call this between requests to guarantee zero residual subscriptions. Note it also removes listeners wired by enable.* strategies — re-enable after calling if you still want them. Does NOT touch attached recorders (see attach() — recorders have their own Unsubscribe).

Returns

void

Inherited from

RunnerBase.removeAllListeners


resume()

resume(checkpoint, input?, options?): Promise<string | RunnerPauseOutcome>

Defined in: src/core-flow/Conditional.ts:168

Resume a paused run from its checkpoint. Default behavior: rebuild the chart, wire the same core recorders + consumer recorders, call executor.resume(checkpoint, input), and emit pause.resume before returning. Subclass overrides only if it needs specialized behavior.

Parameters

checkpoint

FlowchartCheckpoint

input?

unknown

options?

RunOptions

Returns

Promise<string | RunnerPauseOutcome>

Overrides

RunnerBase.resume


run()

run(input, options?): Promise<string | RunnerPauseOutcome>

Defined in: src/core-flow/Conditional.ts:154

Execute the runner. Subclass may override for specialized input mapping, but default invokes getSpec() + FlowChartExecutor.

Parameters

input

string | ConditionalInput

options?

RunOptions

Returns

Promise<string | RunnerPauseOutcome>

Overrides

RunnerBase.run


shutdown()

shutdown(options?): Promise<void>

Defined in: src/core/RunnerBase.ts:639

Drain and release what was enabled on this runner.

The agent itself remains usable afterwards; shutdown() drains and releases what was enabled on it. Nothing about the runner is destroyed: run() still works, listeners still fire, and enabling telemetry again gives you a fresh, live handle.

The order is the part worth having in one place:

  1. every handle FLUSHES first — including the events still queued on a detach driver, which have not reached the strategy yet;
  2. only then does anything stop, so a strategy shared by two handles is fully drained before either releases it;
  3. a strategy is stopped only once nothing is still subscribed to it, and at most once ever (see strategies/lifecycle.ts).

Parameters

options?
stop?

boolean

Default true. Pass false to drain WITHOUT releasing — what a host does when it is shutting down but does not own the agent it was handed (standingAgent's default shutdown: 'flush').

Returns

Promise<void>

Example

Graceful exit for a script
  const telemetry = agent.enable.observability({ strategy: cloudwatch });
  const answer = await agent.run({ message: 'hi' });
  await agent.shutdown();

Inherited from

RunnerBase.shutdown

On this page