UNPKG

@langchain/langgraph

Version:
1 lines 23.4 kB
{"version":3,"file":"mux.cjs","names":["StreamChannel","#transformers","#channels","#streamMap","#latestValues","#interrupts","#finalValues","#closed","#error","isStreamChannel","#nextEmitSeq","#currentNamespace","#interrupted","isInterrupted","INTERRUPT","convertToProtocolEvent"],"sources":["../../src/stream/mux.ts"],"sourcesContent":["/**\n * StreamMux — central dispatcher with transformer pipeline.\n *\n * Routes raw stream chunks through registered StreamTransformers, then appends\n * the resulting ProtocolEvents to the main local channel. Also tracks\n * namespace discovery for SubgraphRunStream creation.\n *\n * lifecycle:\n * graph.streamEvents(input, { version: \"v3\" })\n * ├─ StreamMux starts pumping from graph.stream(…, { subgraphs: true })\n * ├─ For each ProtocolEvent:\n * │ ├─ transformer_1.process(event)\n * │ ├─ transformer_2.process(event)\n * │ └─ event appended to _events (unless suppressed)\n * └─ On close: transformer_n.finalize() called in registration order\n */\n\nimport type { StreamChunk } from \"../pregel/stream.js\";\nimport { INTERRUPT, isInterrupted, type Interrupt } from \"../constants.js\";\nimport { convertToProtocolEvent, STREAM_EVENTS_V3_MODES } from \"./convert.js\";\nimport { StreamChannel, isStreamChannel } from \"./stream-channel.js\";\nimport type {\n InterruptPayload,\n Namespace,\n ProtocolEvent,\n StreamEmitter,\n StreamTransformer,\n} from \"./types.js\";\n\nexport { STREAM_EVENTS_V3_MODES };\n\n/** Wire prefix for user-defined {@link StreamChannel} auto-forwards. */\nconst EXTENSION_CHANNEL_PREFIX = \"custom:\";\n\n/**\n * Protocol method for a user-defined (extension) {@link StreamChannel}.\n * Matches Python's `StreamMux._bind_and_wire` (`f\"custom:{value.name}\"`).\n */\nfunction extensionChannelMethod(channelName: string): ProtocolEvent[\"method\"] {\n return `${EXTENSION_CHANNEL_PREFIX}${channelName}`;\n}\n\n/**\n * Structural `PromiseLike<T>` predicate — true for thenables including\n * native promises, user-constructed `{ then }` objects, and helper\n * wrappers. Used by {@link StreamMux.wireChannels} to detect final-value\n * projections distinctly from streaming `StreamChannel` values.\n */\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n value != null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * Symbol key used by {@link StreamMux} to resolve the values promise on a\n * stream handle. Using a symbol keeps this off the public autocomplete surface.\n */\nexport const RESOLVE_VALUES: unique symbol = Symbol(\"resolveValues\");\n\n/**\n * Symbol key used by {@link StreamMux} to reject the values promise on a\n * stream handle. Using a symbol keeps this off the public autocomplete surface.\n */\nexport const REJECT_VALUES: unique symbol = Symbol(\"rejectValues\");\n\n/**\n * Minimal interface that {@link StreamMux} requires from stream handles\n * for lifecycle resolution. This avoids a direct dependency on\n * `GraphRunStream` / `SubgraphRunStream`.\n */\nexport interface StreamHandle {\n [RESOLVE_VALUES](values: unknown): void;\n [REJECT_VALUES](err: unknown): void;\n}\n\n/**\n * Factory function that creates a subgraph stream handle for a newly\n * discovered namespace.\n *\n * Historically consumed by {@link StreamMux} at construction time;\n * today factories are consumed by\n * `createSubgraphDiscoveryTransformer` (via its `createStream`\n * option). This shape is retained for consumers that still thread a\n * mux reference through the factory — the narrower transformer\n * option omits `mux` because it captures the mux in a closure.\n */\nexport type SubgraphStreamFactory = (\n path: Namespace,\n mux: StreamMux,\n discoveryStart: number,\n eventStart: number\n) => StreamHandle;\n\n/**\n * A discovered subgraph namespace paired with its run stream handle.\n */\nexport type SubgraphDiscovery = {\n ns: Namespace;\n stream: StreamHandle;\n};\n\n/**\n * Central event dispatcher that routes {@link ProtocolEvent}s through a\n * pipeline of {@link StreamTransformer}s, manages namespace discovery for\n * subgraph streams, and exposes async iteration over filtered event\n * sequences.\n *\n * One `StreamMux` instance exists per top-level\n * `streamEvents(..., { version: \"v3\" })` invocation.\n */\nexport class StreamMux {\n /** @internal All protocol events in arrival order (after reducer pipeline). */\n readonly _events = StreamChannel.local<ProtocolEvent>();\n\n /** @internal New-namespace discovery notifications. */\n readonly _discoveries = StreamChannel.local<SubgraphDiscovery>();\n\n /** Monotonic counter for auto-forwarded channel events. */\n #nextEmitSeq = 0;\n\n /** Whether the mux has been closed or failed. */\n #closed = false;\n\n /** The error passed to {@link fail}, if any. */\n #error: unknown;\n\n /** Whether the run was interrupted. */\n #interrupted = false;\n\n /**\n * Namespace of the event currently being processed by\n * {@link push}. Read by {@link StreamChannel} wiring callbacks so\n * auto-forwarded events inherit the triggering event's namespace.\n */\n #currentNamespace: Namespace = [];\n\n readonly #transformers: StreamTransformer<unknown>[] = [];\n readonly #channels: StreamChannel<unknown>[] = [];\n readonly #streamMap = new Map<string, StreamHandle>();\n readonly #latestValues = new Map<string, Record<string, unknown>>();\n readonly #interrupts: InterruptPayload[] = [];\n\n /**\n * Final-value projection keys tracked for remote surfacing. Populated\n * by {@link wireChannels} when a transformer's projection contains a\n * `PromiseLike` value. Each entry is flushed as a `custom:<name>`\n * protocol event during {@link close} so that remote clients can\n * observe final-value transformers via `thread.extensions.<name>`.\n */\n readonly #finalValues: Array<{ name: string; promise: Promise<unknown> }> =\n [];\n\n /**\n * Associates a pre-existing stream handle with a namespace so that\n * {@link close} can resolve its values promise later.\n *\n * @param path - The namespace path to register.\n * @param stream - The run stream handle for that namespace.\n */\n register(path: Namespace, stream: StreamHandle): void {\n this.#streamMap.set(nsKey(path), stream);\n }\n\n /**\n * Registers a transformer and replays all buffered events through it so\n * it catches up with events already processed by the mux. When the event\n * log is empty (typical at construction time) the replay is a no-op.\n *\n * The transformer must already have been initialised (i.e. `init()` called\n * and any projection wired). The sequence is:\n *\n * 1. Snapshot the current event log length.\n * 2. Append the transformer so future {@link push} calls reach it.\n * 3. Replay events `[0, snapshot)` through `process()`.\n * 4. If the mux is already closed, call `finalize()` (or `fail()`)\n * immediately so the transformer's log/channel terminates cleanly.\n *\n * @param transformer - An already-initialised transformer to register.\n */\n addTransformer(transformer: StreamTransformer<unknown>): void {\n const snapshot = this._events.size;\n this.#transformers.push(transformer);\n\n // Hand the transformer a narrow emitter handle *before* replay so\n // synthetic-emission transformers (e.g. deepagents\n // `SubagentTransformer`) can inject events into the mux during\n // their own `process()` calls — including the initial replay\n // triggered just below.\n if (transformer.onRegister) {\n const emitter: StreamEmitter = {\n // Transformer-originated events use a placeholder `seq` of\n // `0`. `push()` is the single authority for sequence numbers\n // and will re-stamp this event with the next monotonically\n // increasing value.\n push: (ns, event) => this.push(ns, event),\n };\n transformer.onRegister(emitter);\n }\n\n for (let i = 0; i < snapshot; i += 1) {\n transformer.process(this._events.get(i));\n }\n\n if (this.#closed) {\n if (this.#error !== undefined) {\n transformer.fail?.(this.#error);\n } else {\n transformer.finalize?.();\n }\n }\n }\n\n /**\n * Scans a transformer projection for streaming and final-value primitives.\n * Remote stream channels are wired to auto-forward to the protocol event\n * stream; local stream channels are tracked for lifecycle only.\n *\n * Two projection shapes are recognised:\n *\n * - {@link StreamChannel} values — named channels forward each `push()`\n * immediately as a `custom:<channelName>` protocol event. Unnamed\n * channels remain in-process-only.\n *\n * - `PromiseLike<unknown>` values — tracked as final-value\n * projections and flushed on {@link close} as a single\n * `custom:<key>` event, where `<key>` is the projection key.\n * This mirrors the in-process `await run.extensions.<key>`\n * ergonomics on remote clients via\n * `await thread.extensions.<key>`.\n *\n * Plain values that are neither are ignored — they remain in-process-only,\n * matching prior behaviour.\n *\n * @param projection - The object returned by `transformer.init()`.\n */\n wireChannels(projection: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(projection)) {\n if (isStreamChannel(value)) {\n this.#channels.push(value);\n if (typeof value.channelName !== \"string\") {\n continue;\n }\n const method = extensionChannelMethod(value.channelName);\n value._wire((item: unknown) => {\n this._events.push({\n type: \"event\",\n seq: this.#nextEmitSeq++,\n method,\n params: {\n namespace: this.#currentNamespace,\n timestamp: Date.now(),\n data: item,\n },\n });\n });\n continue;\n }\n if (isPromiseLike(value)) {\n this.#finalValues.push({\n name: key,\n promise: Promise.resolve(value),\n });\n }\n }\n }\n\n /**\n * Distributes an event through the transformer pipeline, then appends it to\n * the main event log.\n *\n * Subgraph discovery (materializing a {@link StreamHandle} for each\n * newly observed top-level namespace) is handled by the\n * {@link createSubgraphDiscoveryTransformer} when installed, not here.\n *\n * @param ns - The namespace path that produced the event.\n * @param event - The protocol event to process and store.\n */\n push(ns: Namespace, event: ProtocolEvent): void {\n if (event.method === \"values\") {\n this.#latestValues.set(\n nsKey(ns),\n event.params.data as Record<string, unknown>\n );\n }\n\n // Save the outer namespace so re-entrant `push()` calls (e.g. from\n // `StreamTransformer.onRegister` emitters synthesizing events\n // inside a transformer's `process()`) can set their own namespace\n // without clobbering the outer scope's `StreamChannel` routing\n // when control returns to the outer transformer loop.\n const outerNamespace = this.#currentNamespace;\n this.#currentNamespace = ns;\n\n let keep = true;\n for (const transformer of this.#transformers) {\n if (!transformer.process(event)) {\n keep = false;\n }\n }\n\n this.#currentNamespace = outerNamespace;\n\n if (keep) {\n // The mux is the single authority for sequence numbers. Callers\n // (the `pump`, transformer emitters, channel forwarders) pass a\n // placeholder `seq`; we re-stamp every event here so the log is\n // strictly monotonic across all origination paths. Stamping\n // happens *after* `process()` so that any channel-forwarded\n // events pushed during processing get earlier sequence numbers\n // than the triggering event, matching their in-order appearance\n // in `_events`.\n this._events.push({ ...event, seq: this.#nextEmitSeq++ });\n }\n }\n\n /**\n * Gracefully ends the stream: resolves values promises on all known\n * streams, finalizes every transformer, auto-closes streaming\n * channels, flushes any final-value projections as `custom:<name>`\n * events, and closes both event logs.\n *\n * When final-value projections are present, `_events.close()` is\n * deferred until every tracked projection promise has settled so\n * remote consumers observe the flushed values before their event\n * stream ends. Callers do not need to await — `close()` returns\n * synchronously and any downstream consumer iterating\n * {@link _events} naturally waits for the final events.\n */\n close(): void {\n this.#closed = true;\n for (const [key, values] of this.#latestValues.entries()) {\n const ns = key ? key.split(\"\\x00\") : [];\n const stream = this.#streamMap.get(nsKey(ns));\n stream?.[RESOLVE_VALUES](values);\n }\n\n const finalizePromises: PromiseLike<void>[] = [];\n for (const transformer of this.#transformers) {\n const result = transformer.finalize?.();\n if (\n result != null &&\n typeof (result as PromiseLike<void>).then === \"function\"\n ) {\n finalizePromises.push(result as PromiseLike<void>);\n }\n }\n\n for (const channel of this.#channels) {\n channel._close();\n }\n\n const finalValues = this.#finalValues;\n if (finalValues.length === 0 && finalizePromises.length === 0) {\n this._events.close();\n this._discoveries.close();\n } else {\n void Promise.allSettled([\n ...finalizePromises,\n ...finalValues.map(async ({ name, promise }) => {\n try {\n const resolved = await promise;\n if (!this._events.done) {\n this._events.push({\n type: \"event\",\n seq: this.#nextEmitSeq++,\n method: \"custom\",\n params: {\n namespace: [],\n timestamp: Date.now(),\n data: { name, payload: resolved },\n },\n });\n }\n } catch {\n // Rejected final-value projections are intentionally dropped\n // so a single failing extension can't poison the protocol\n // stream. The corresponding in-process Promise still\n // surfaces the rejection to its direct awaiters via the\n // transformer's own `fail()` hook.\n }\n }),\n ]).then(() => {\n this._events.close();\n this._discoveries.close();\n });\n }\n\n for (const stream of this.#streamMap.values()) {\n stream[RESOLVE_VALUES](undefined);\n }\n }\n\n /**\n * Propagates a failure to all transformers, channels, event logs, and\n * stream handles.\n *\n * @param err - The error that caused the run to fail.\n */\n fail(err: unknown): void {\n this.#closed = true;\n this.#error = err;\n for (const transformer of this.#transformers) {\n transformer.fail?.(err);\n }\n for (const channel of this.#channels) {\n channel._fail(err);\n }\n this._events.fail(err);\n this._discoveries.fail(err);\n for (const stream of this.#streamMap.values()) {\n stream[REJECT_VALUES](err);\n }\n }\n\n /**\n * Records that the run was interrupted, appending the supplied payloads\n * for later retrieval.\n *\n * @param interrupts - The interrupt payloads to store.\n */\n markInterrupted(interrupts: InterruptPayload[]): void {\n this.#interrupted = true;\n this.#interrupts.push(...interrupts);\n }\n\n /**\n * Whether the run ended due to an interrupt.\n *\n * @returns `true` if {@link markInterrupted} was called.\n */\n get interrupted(): boolean {\n return this.#interrupted;\n }\n\n /**\n * All interrupt payloads collected during the run.\n *\n * @returns A readonly view of the accumulated interrupt payloads.\n */\n get interrupts(): readonly InterruptPayload[] {\n return this.#interrupts;\n }\n\n /**\n * Returns an async iterator that yields only events whose namespace\n * starts with {@link path}.\n *\n * @param path - Namespace prefix to filter on.\n * @param startAt - Zero-based index into the event log to begin from.\n * @returns An async iterator over matching {@link ProtocolEvent}s.\n */\n subscribeEvents(path: Namespace, startAt = 0): AsyncIterator<ProtocolEvent> {\n const base = this._events.iterate(startAt);\n return {\n async next(): Promise<IteratorResult<ProtocolEvent>> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const result = await base.next();\n if (result.done) return result;\n if (hasPrefix(result.value.params.namespace, path)) {\n return result;\n }\n }\n },\n };\n }\n}\n\n/**\n * Background consumer that drains a raw `graph.stream()` source into a\n * {@link StreamMux}. Converts each chunk to a {@link ProtocolEvent} and\n * pushes it; calls {@link StreamMux.close} on normal completion or\n * {@link StreamMux.fail} on error.\n *\n * @param source - The async iterable of raw stream chunks from the engine.\n * @param mux - The mux instance to feed.\n * @returns A promise that resolves when the source is fully consumed.\n */\nexport async function pump(\n source: AsyncIterable<StreamChunk>,\n mux: StreamMux\n): Promise<void> {\n let seq = 0;\n try {\n for await (const chunk of source) {\n const [ns, mode, payload] = chunk;\n\n // Detect interrupt payloads attached to values-mode chunks.\n if (mode === \"values\" && isInterrupted(payload)) {\n const interrupts = (payload as { [INTERRUPT]: Interrupt[] })[INTERRUPT];\n mux.markInterrupted(\n interrupts.map((i) => ({\n interruptId: i.id ?? \"\",\n payload: i.value,\n }))\n );\n }\n\n const events = convertToProtocolEvent({\n namespace: ns,\n mode,\n payload,\n seq,\n });\n seq += events.length;\n for (const event of events) {\n mux.push(ns, event);\n }\n }\n } catch (err) {\n mux.fail(err);\n return;\n }\n mux.close();\n}\n\n/**\n * Serialises a {@link Namespace} array into a single string key using the\n * null byte (`\\x00`) as separator, suitable for `Map`/`Set` lookups.\n *\n * @param ns - The namespace segments to join.\n * @returns A null-byte-joined string key.\n */\nexport function nsKey(ns: Namespace): string {\n return ns.join(\"\\x00\");\n}\n\n/**\n * Tests whether {@link ns} starts with every segment in {@link prefix}.\n *\n * @param ns - The full namespace to check.\n * @param prefix - The prefix to match against.\n * @returns `true` if `ns` begins with `prefix` segment-by-segment.\n */\nexport function hasPrefix(ns: Namespace, prefix: Namespace): boolean {\n if (prefix.length > ns.length) return false;\n for (let i = 0; i < prefix.length; i += 1) {\n if (ns[i] !== prefix[i]) return false;\n }\n return true;\n}\n"],"mappings":"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"}