Channel Types
Type definitions for channels, external channels, and channel handles in Noetic.
Channel
A typed communication channel for inter-step message passing.
interface Channel<T> {
readonly name: string;
readonly schema: ZodType<T>;
readonly mode: 'value' | 'queue' | 'topic';
readonly capacity?: number;
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique channel name |
schema | ZodType<T> | yes | Zod schema for message validation |
mode | 'value' | 'queue' | 'topic' | yes | Channel semantics |
capacity | number | no | Maximum buffered messages (for queue/topic modes) |
Channel Modes
| Mode | Behavior |
|---|---|
'value' | Holds a single value. New sends overwrite the previous value. |
'queue' | FIFO buffer. Sends enqueue, receives dequeue. |
'topic' | Pub/sub broadcast. All receivers get every message. |
Channel state is keyed by name and lives for the harness lifetime. With a CheckpointStore, value and queue state is checkpointed and restored with each execution that used the channel (CheckpointSnapshot.channels, exported with ChannelSnapshotSchema).
ExternalChannel
An external channel extends Channel with an external flag, enabling cross-process communication.
interface ExternalChannel<T> extends Channel<T> {
readonly external: true;
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique channel name |
schema | ZodType<T> | yes | Zod schema for message validation |
mode | 'value' | 'queue' | 'topic' | yes | Channel semantics |
capacity | number | no | Maximum buffered messages |
external | true | yes | Marks channel as externally accessible |
ChannelHandle
A handle for sending messages into a channel from outside the agent execution context.
interface ChannelHandle<T> {
send(value: T): void;
readonly closed: boolean;
readonly channel: Channel<T>;
}| Field | Type | Description |
|---|---|---|
send | (value: T) => void | Send a value into the channel. Synchronous — external senders are never back-pressured; at capacity the oldest queued item is dropped and a channel.warning span event (overflow_drop) is recorded |
closed | boolean | Whether the handle is closed (execution completed) |
channel | Channel<T> | Reference to the underlying channel |
getChannelStream
The read-side counterpart to getChannelHandle: subscribe from outside the execution to values the agent sends on an external channel.
harness.getChannelStream<T>(channel: ExternalChannel<T>, executionId: string): AsyncIterable<T>Delivery is channel-scoped (state is keyed by channel name per harness); executionId bounds only the subscription's lifetime. An id no execution runs under never closes — a harness-lifetime stream ended with iterator.return().
| Mode | External subscriber behavior |
|---|---|
queue | Competing consumer — FIFO-fair with internal recv waiters; consuming frees parked senders. Subscribe once per harness |
topic | Non-lossy tap — per-subscriber buffer (1000, drop-oldest), no pre-subscribe replay |
value | Current value, then conflated updates; non-consuming |
The iterable ends normally when the root execution completes (queue values present at close drain first; later sends stay in the channel) — it never rejects with channel_timeout or cancelled. A re-run or restored root context reopens its id. iterator.return() unsubscribes; the iterable owns a single iterator, so subscribe again for a second consumer.
Context Channel Methods
The Context object provides three methods for channel interaction:
interface Context {
send<T>(channel: Channel<T>, value: NoInfer<T>): Promise<void>;
recv<T>(channel: Channel<T>, opts?: { timeout?: number }): Promise<T>;
tryRecv<T>(channel: Channel<T>): T | null;
}NoInfer<T> makes the channel alone fix T: sending a plain string to a Channel<'running' | 'done'> is a compile error rather than widening T to string.
| Method | Description |
|---|---|
send(channel, value) | Send a value to the channel. Resolves immediately unless a queue channel is at capacity, in which case the send parks until a consumer frees a slot (back-pressure): default 30s timeout rejects with channel_timeout; aborting the context rejects with cancelled. |
recv(channel, opts?) | Receive a value. Blocks until available or timeout (channel_timeout, default 30s). timeout: 0 disables the timeout in every mode and records an unbounded_wait channel warning; a negative timeout rejects with NoeticConfigError code INVALID_CHANNEL_TIMEOUT. Rejects with cancelled when the context is aborted while waiting. |
tryRecv(channel) | Non-blocking receive. Returns null if no value available. |