@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
1 lines • 117 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":["ensureMessageInstances","#transportAdapter","#pending","#subscriptions","#seenEventIds","#headlessInterruptsAwaitingTerminal","#pendingSubResolves","#onEventListeners","#onErrorListeners","#extensionsCache","#extensionsEvents","#extensionsEventListeners","#extensionsEndListeners","#mediaHandles","#audioBuffer","MultiCursorBuffer","#imagesBuffer","#videoBuffer","#filesBuffer","#fetchOption","#nextCommandId","#prepareForNextRun","#withRunStartGate","#ensureLifecycleTracking","#send","#resubscribeWebSocketSubscriptions","#consumeEvents","#ensureOpen","#opened","#openPromise","#lifecycleStartPromise","#lifecycleSubId","#subscribeRaw","#lifecycleChannels","#runStartReady","#terminalPauseTimer","#terminalPauseSeq","#messagesIterable","StreamingMessageAssembler","#startProjection","toStreamingMessageHandle","#valuesProjection","#outputPromise","#toolCallsIterable","ToolCallAssembler","toClientAssembledToolCall","#subgraphsIterable","SubgraphDiscoveryHandle","#subagentsIterable","SubagentDiscoveryHandle","#ensureMediaDispatcher","#extensionsProxy","#createExtension","#extensionsDispatcherStarted","#extensionsEnded","#mediaDispatcherStarted","MediaAssembler","#mediaAssembler","#ensureExtensionsDispatcher","#startLifecycleWatcher","#lifecycleWatcherStartPromise","#startLifecycleWatcherSse","#startLifecycleWatcherWebSocket","#closed","#lifecycleWatcherHandle","#handleLifecycleWatcherMessage","#applyThreadLevelEffects","#fireOnEvent","isHeadlessToolInterrupt","#sharedStream","#sharedStreamFilter","#subscribeViaSharedStream","#subscribeViaCommand","#scheduleReconcile","#rotationState","#reconcileStream","#computeUnionFilter","#rejectUncoveredPending","#resolvePending","#pumpStream","#handleIncoming","#failThreadWithError","#fireOnError","ProtocolError","matchesSubscription","#scheduleTerminalPause"],"sources":["../../../src/client/stream/index.ts"],"sourcesContent":["import type {\n Channel,\n Command,\n CommandResponse,\n Event,\n InputRespondParams,\n LifecycleEvent,\n ListCheckpointsResult,\n Message,\n MessagesEvent,\n Namespace,\n RunResult,\n StateForkResult,\n StateGetResult,\n SubscribeParams,\n SubscribeResult,\n ToolsEvent,\n ValuesEvent,\n} from \"@langchain/protocol\";\nimport { matchesSubscription } from \"./subscription.js\";\nimport { MultiCursorBuffer } from \"./multi-cursor-buffer.js\";\nimport { ensureMessageInstances } from \"../../ui/messages.js\";\nimport {\n ToolCallAssembler,\n toClientAssembledToolCall,\n SubgraphDiscoveryHandle,\n SubgraphHandle,\n SubagentDiscoveryHandle,\n SubagentHandle,\n} from \"./handles/index.js\";\nimport type { ClientAssembledToolCall } from \"./handles/tools.js\";\nimport {\n StreamingMessageAssembler,\n toStreamingMessageHandle,\n} from \"./messages.js\";\nimport type { StreamingMessageHandle } from \"./messages.js\";\nimport { MediaAssembler } from \"./media.js\";\nimport type {\n AnyMediaHandle,\n AudioMedia,\n FileMedia,\n ImageMedia,\n VideoMedia,\n} from \"./media.js\";\nimport type {\n EventSubscription,\n EventForChannel,\n EventForChannels,\n InterruptPayload,\n ThreadExtension,\n ThreadExtensions,\n ThreadModules,\n ThreadStreamOptions,\n SessionOrderingState,\n SubscribeOptions,\n YieldForChannel,\n YieldForChannels,\n} from \"./types.js\";\nimport type { EventStreamHandle, TransportAdapter } from \"./transport.js\";\nimport { ProtocolError } from \"./error.js\";\nimport { NAMESPACE_SEPARATOR } from \"../../stream/constants.js\";\nimport { isHeadlessToolInterrupt } from \"../../headless-tools.js\";\n\ntype PendingCommand = {\n resolve: (response: CommandResponse) => void;\n reject: (error: Error) => void;\n};\n\ntype CommandResultMap = {\n \"run.start\": RunResult;\n \"subscription.subscribe\": SubscribeResult;\n \"subscription.unsubscribe\": Record<string, unknown>;\n \"agent.getTree\": Record<string, unknown>;\n \"input.respond\": Record<string, unknown>;\n \"input.inject\": Record<string, unknown>;\n \"state.get\": StateGetResult;\n \"state.listCheckpoints\": ListCheckpointsResult;\n \"state.fork\": StateForkResult;\n};\n\ntype CommandParamsMap = {\n \"run.start\": Record<string, unknown>;\n \"subscription.subscribe\": SubscribeParams;\n \"subscription.unsubscribe\": { subscription_id: string };\n \"agent.getTree\": { run_id?: string };\n \"input.respond\": InputRespondParams;\n \"input.inject\": Record<string, unknown>;\n \"state.get\": Record<string, unknown>;\n \"state.listCheckpoints\": Record<string, unknown>;\n \"state.fork\": Record<string, unknown>;\n};\n\ntype InternalEventSubscription = EventSubscription<unknown> & {\n filter: SubscribeParams;\n push(event: Event): void;\n close(): void;\n pause(): void;\n resume(): void;\n /**\n * Highest sequence observed by the thread before this subscription was\n * registered. Replayed terminal events at or before this point belong to a\n * run that already ended before the subscription existed, so they must not\n * pause the subscription before it can drain server replay.\n */\n registeredAfterSeq: number | undefined;\n /**\n * Per-subscription dedup window. Guards against redelivery during\n * shared-stream rotation overlap and from WebSocket server-side\n * fan-out, while still letting newly-registered subs receive the\n * replayed events that existing subs already consumed. Event IDs\n * are session-local but stable across sessions for the same run\n * (the session's monotonic `_next_seq` processes events in order),\n * so a set-per-sub is sufficient.\n */\n seenEventIds: Set<string>;\n};\n\ntype PendingSubResolve = {\n filter: SubscribeParams;\n resolve: () => void;\n reject: (err: unknown) => void;\n};\n\nconst MESSAGE_LIKE_TYPES = new Set([\n \"human\",\n \"user\",\n \"ai\",\n \"assistant\",\n \"tool\",\n \"system\",\n \"function\",\n \"remove\",\n]);\n\n/**\n * When the state payload has a `messages` array containing plain\n * serialized messages (objects with a recognized `type` field), coerce\n * them into `@langchain/core/messages` class instances so remote runs\n * expose the same shape as in-process runs.\n *\n * Returns the input unchanged when the payload is not an object, does\n * not include a `messages` key, or contains entries that are already\n * class instances / not message-like.\n */\nfunction coerceStateMessages(value: unknown): unknown {\n if (value == null || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n const state = value as Record<string, unknown>;\n const messages = state.messages;\n if (!Array.isArray(messages) || messages.length === 0) return value;\n\n const needsCoercion = messages.some((msg) => {\n if (msg == null || typeof msg !== \"object\") return false;\n if (typeof (msg as { getType?: () => string }).getType === \"function\") {\n return false;\n }\n const type = (msg as { type?: unknown }).type;\n return typeof type === \"string\" && MESSAGE_LIKE_TYPES.has(type);\n });\n if (!needsCoercion) return value;\n\n return {\n ...state,\n messages: ensureMessageInstances(\n messages as Parameters<typeof ensureMessageInstances>[0]\n ),\n };\n}\n\nfunction namespaceKey(ns: Namespace): string {\n return ns.join(NAMESPACE_SEPARATOR);\n}\n\nfunction maxSeq(\n current: number | undefined,\n next: number | undefined\n): number | undefined {\n if (next == null) return current;\n if (current == null) return next;\n return Math.max(current, next);\n}\n\nconst ROOT_TERMINAL_LIFECYCLE_EVENTS = new Set([\n \"completed\",\n \"failed\",\n \"interrupted\",\n]);\n\n/**\n * Detect a root-namespace terminal lifecycle event. Used by\n * `#startProjection`'s `endOnRootTerminal` guard to settle per-run\n * dispatchers regardless of whether the shared-stream pause logic\n * applies to their underlying subscription.\n */\nfunction isRootTerminalLifecycle(event: Event): boolean {\n if (event.method !== \"lifecycle\") return false;\n if (event.params.namespace.length !== 0) return false;\n const data = event.params.data as { event?: string } | undefined;\n return data?.event != null && ROOT_TERMINAL_LIFECYCLE_EVENTS.has(data.event);\n}\n\nfunction namespaceListsEqual(\n a: readonly Namespace[] | undefined,\n b: readonly Namespace[] | undefined\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n if (a.length !== b.length) return false;\n const aKeys = new Set<string>();\n for (const ns of a) aKeys.add(namespaceKey(ns));\n for (const ns of b) {\n if (!aKeys.has(namespaceKey(ns))) return false;\n }\n return true;\n}\n\n/**\n * Structural equality on filters. Two filters are equal iff they\n * request the same channel set, the same namespace prefix set\n * (with `undefined` meaning wildcard), and the same depth\n * (with `undefined` meaning unbounded).\n */\nfunction filterEqual(\n a: SubscribeParams | null,\n b: SubscribeParams | null\n): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (a.channels.length !== b.channels.length) return false;\n const aChannels = new Set(a.channels as Channel[]);\n for (const ch of b.channels as Channel[]) {\n if (!aChannels.has(ch)) return false;\n }\n if (!namespaceListsEqual(a.namespaces, b.namespaces)) return false;\n const aDepth = a.depth ?? null;\n const bDepth = b.depth ?? null;\n if (aDepth !== bDepth) return false;\n return true;\n}\n\nfunction isPrefix(prefix: Namespace, candidate: Namespace): boolean {\n if (prefix.length > candidate.length) return false;\n for (let i = 0; i < prefix.length; i += 1) {\n if (prefix[i] !== candidate[i]) return false;\n }\n return true;\n}\n\n/**\n * Whether the `coverer` filter delivers every event a subscription\n * opened with `target` could want.\n *\n * Rules:\n * - Channels: target.channels must be a subset of coverer.channels.\n * - Namespaces:\n * - coverer wildcard (`undefined`) → coverer covers all prefixes.\n * - coverer explicit + target wildcard → not covered.\n * - both explicit → every target prefix must have some coverer\n * prefix that is its ancestor (coverer's prefix delivers events\n * for all descendants, modulo depth).\n * - Depth:\n * - coverer unbounded (`undefined`) → depth is covered.\n * - otherwise, for each target prefix `tp` covered by coverer\n * prefix `cp`, the maximum event depth target wants\n * (`tp.length + (target.depth ?? ∞) - cp.length`) must be\n * `<= coverer.depth`. For a wildcard target with bounded depth,\n * target's max absolute depth is `target.depth` (prefix is `[]`).\n */\nfunction filterCovers(\n coverer: SubscribeParams,\n target: SubscribeParams\n): boolean {\n const covererChannels = new Set(coverer.channels as Channel[]);\n for (const ch of target.channels as Channel[]) {\n if (!covererChannels.has(ch)) return false;\n }\n\n const covererDepth = coverer.depth;\n const targetDepth = target.depth;\n\n if (coverer.namespaces == null) {\n if (covererDepth == null) return true;\n if (targetDepth == null) return false;\n return targetDepth <= covererDepth;\n }\n\n if (target.namespaces == null) return false;\n\n for (const tp of target.namespaces) {\n const covered = coverer.namespaces.some((cp) => {\n if (!isPrefix(cp, tp)) return false;\n if (covererDepth == null) return true;\n if (targetDepth == null) return false;\n return tp.length - cp.length + targetDepth <= covererDepth;\n });\n if (!covered) return false;\n }\n return true;\n}\n\nfunction normalizeSubscribeParams(\n paramsOrChannels: SubscribeParams | Channel | readonly Channel[],\n options: SubscribeOptions = {}\n): SubscribeParams {\n if (\n typeof paramsOrChannels === \"object\" &&\n !Array.isArray(paramsOrChannels) &&\n \"channels\" in paramsOrChannels\n ) {\n return paramsOrChannels;\n }\n\n const channels = Array.isArray(paramsOrChannels)\n ? ([...paramsOrChannels] as Channel[])\n : ([paramsOrChannels] as Channel[]);\n return {\n ...options,\n channels,\n };\n}\n\n/**\n * Fold the ergonomic top-level `forkFrom` checkpoint id into\n * `config.configurable.checkpoint_id` and strip `forkFrom` from the\n * outgoing params.\n *\n * `forkFrom` is purely an SDK-side convenience: callers say\n * `submit(input, { forkFrom })` instead of hand-building a nested\n * RunnableConfig. The agent server only ever accepts the fork target via\n * `config.configurable.checkpoint_id` (the same field the legacy run\n * endpoints use), so we translate here — before the `run.start` message\n * hits the wire — keeping a single, legacy-compliant way to provide it.\n *\n * `forkFrom` takes precedence over any `checkpoint_id` the caller already\n * placed in `config.configurable`, matching the prior server-side merge.\n */\nfunction foldForkFromIntoConfig<\n T extends { forkFrom?: string; config?: unknown },\n>(params: T): Omit<T, \"forkFrom\"> {\n const { forkFrom, ...rest } = params;\n if (typeof forkFrom !== \"string\" || forkFrom.length === 0) {\n return rest;\n }\n const config =\n rest.config != null && typeof rest.config === \"object\"\n ? (rest.config as Record<string, unknown>)\n : {};\n const configurable =\n config.configurable != null && typeof config.configurable === \"object\"\n ? (config.configurable as Record<string, unknown>)\n : {};\n return {\n ...rest,\n config: {\n ...config,\n configurable: {\n ...configurable,\n checkpoint_id: forkFrom,\n },\n },\n } as Omit<T, \"forkFrom\">;\n}\n\n/**\n * Async iterable handle for raw event subscriptions.\n *\n * An optional `transform` maps each incoming event before it is queued\n * or delivered to a waiting consumer. This is used by named custom\n * channel subscriptions (e.g. `\"custom:a2a\"`) to unwrap the payload\n * so callers receive the raw emitted data instead of the protocol\n * event envelope.\n */\nexport class SubscriptionHandle<TEvent extends Event = Event, TYield = TEvent>\n implements AsyncIterable<TYield>, EventSubscription<TYield>\n{\n // Mutated by `#subscribeViaCommand` on WS once the server-assigned\n // subscription id arrives — see the placeholder→resolved transition\n // there. SSE paths set this once at construction and never change it.\n subscriptionId: string;\n readonly params: SubscribeParams;\n private readonly queue: TYield[] = [];\n private readonly waiters: Array<(value: IteratorResult<TYield>) => void> = [];\n private closed = false;\n private paused = false;\n private resumeResolve?: () => void;\n private readonly onUnsubscribe: (id: string) => Promise<void>;\n private readonly transform: (event: TEvent) => TYield;\n\n constructor(\n subscriptionId: string,\n params: SubscribeParams,\n onUnsubscribe: (id: string) => Promise<void>,\n transform?: (event: TEvent) => TYield\n ) {\n this.subscriptionId = subscriptionId;\n this.params = params;\n this.onUnsubscribe = onUnsubscribe;\n this.transform = transform ?? ((event) => event as unknown as TYield);\n }\n\n push(event: TEvent): void {\n if (this.closed) {\n return;\n }\n const value = this.transform(event);\n const waiter = this.waiters.shift();\n if (waiter) {\n waiter({ done: false, value });\n return;\n }\n this.queue.push(value);\n }\n\n /**\n * Pause the subscription: resolve all waiting iterators with `done: true`\n * so `for await` loops exit, but keep the subscription alive. New events\n * arriving while paused are still buffered. Call `resume()` to allow\n * iterators to consume again.\n */\n pause(): void {\n if (this.closed) return;\n this.paused = true;\n while (this.waiters.length > 0) {\n this.waiters.shift()?.({ done: true, value: undefined });\n }\n }\n\n /**\n * Resume a paused subscription so new `for await` loops can consume\n * buffered and future events.\n */\n resume(): void {\n this.paused = false;\n this.resumeResolve?.();\n this.resumeResolve = undefined;\n }\n\n /**\n * Returns a promise that resolves when `resume()` is called. Resolves\n * immediately if not currently paused.\n */\n waitForResume(): Promise<void> {\n if (!this.paused) return Promise.resolve();\n return new Promise<void>((resolve) => {\n this.resumeResolve = resolve;\n });\n }\n\n get isPaused(): boolean {\n return this.paused;\n }\n\n close(): void {\n this.closed = true;\n this.paused = false;\n while (this.waiters.length > 0) {\n this.waiters.shift()?.({ done: true, value: undefined });\n }\n // A paused iterator may be parked on `waitForResume()` instead of\n // on a regular iterator waiter. Resolving here prevents closed\n // subscriptions from stranding pumps that observe `isPaused` and\n // block on `waitForResume()` (e.g. the root pump in\n // `StreamController`).\n this.resumeResolve?.();\n this.resumeResolve = undefined;\n }\n\n async unsubscribe(): Promise<void> {\n if (this.closed) {\n return;\n }\n this.close();\n await this.onUnsubscribe(this.subscriptionId);\n }\n\n [Symbol.asyncIterator](): AsyncIterator<TYield> {\n return {\n next: async () => {\n if (this.queue.length > 0) {\n const value = this.queue.shift()!;\n return { done: false, value };\n }\n if (this.closed || this.paused) {\n return { done: true, value: undefined };\n }\n return await new Promise<IteratorResult<TYield>>((resolve) => {\n this.waiters.push(resolve);\n });\n },\n return: async () => {\n this.close();\n return { done: true, value: undefined };\n },\n };\n }\n}\n\n/**\n * High-level wrapper around a protocol connection to a specific thread.\n *\n * In the thread-centric protocol, threads are durable (backed by\n * checkpoints) and connections are ephemeral. A `ThreadStream` is the\n * client-side handle for interacting with a thread: starting runs,\n * subscribing to events, consuming assembled projections (`messages`,\n * `values`, `toolCalls`, etc.), and responding to interrupts.\n *\n * Construct via `client.threads.stream(threadId?, { assistantId? })`.\n *\n * @typeParam TExtensions - Optional map of `{ name: payload }` pairs\n * describing the transformer projections the bound assistant exposes\n * on `custom:<name>` channels. Narrows `thread.extensions.<name>` to\n * `ThreadExtension<payload>`. Defaults to `Record<string, unknown>`.\n */\nexport class ThreadStream<\n TExtensions extends Record<string, unknown> = Record<string, unknown>,\n> {\n readonly threadId: string;\n readonly ordering: SessionOrderingState = {};\n readonly run: ThreadModules[\"run\"];\n readonly agent: ThreadModules[\"agent\"];\n readonly input: ThreadModules[\"input\"];\n readonly state: ThreadModules[\"state\"];\n\n /**\n * Whether the run was interrupted (a lifecycle \"interrupted\" event\n * was received). Mirrors the in-process `run.interrupted`.\n */\n interrupted = false;\n\n /**\n * Interrupt payloads collected during the run, if any.\n * Mirrors the in-process `run.interrupts`.\n */\n readonly interrupts: InterruptPayload[] = [];\n\n readonly assistantId: string;\n\n #nextCommandId: number;\n readonly #transportAdapter: TransportAdapter;\n readonly #pending = new Map<number, PendingCommand>();\n readonly #subscriptions = new Map<string, InternalEventSubscription>();\n // Tracks `event_id`s that have already been processed for thread-level\n // side effects (interrupt tracking, `input.requested` capture) AND to\n // drop duplicate fan-outs during the overlap window of SSE stream\n // rotation (see `#reconcileStream`): the old stream and the new stream\n // are both pumping briefly, and the server replays buffered events on\n // new streams, so the same `event_id` can arrive twice.\n //\n // The set grows at the rate of unique events per thread, but its\n // lifetime is bounded by `ThreadStream` (it's GC'd when the run\n // completes and the stream is disposed), and each entry is a short\n // numeric string. A bounded sliding-window alternative was considered\n // and rejected: any cap smaller than the server's replay buffer\n // (`maxBufferSize` in `protocol/session`) would risk evicting still-\n // live ids and re-processing real events, which trades a hypothetical\n // memory win for a real correctness failure mode and cross-repo\n // coupling. Revisit only if a concrete long-run memory profile\n // justifies the added complexity.\n readonly #seenEventIds = new Set<string>();\n /**\n * Headless tool interrupts can be auto-resumed by the React hook before\n * the shared SSE content pump has processed the root `interrupted`\n * lifecycle event. `respondInput()` clears `interrupts`, so keep a\n * short-lived marker here until that stale terminal passes through the\n * content pump and we can avoid pausing it.\n */\n readonly #headlessInterruptsAwaitingTerminal = new Set<string>();\n #closed = false;\n #opened = false;\n #openPromise?: Promise<void>;\n\n // ---------- Shared SSE stream state ----------\n // Under the SSE transport a single connection is shared across all\n // subscriptions. Its filter is the union of every active subscription's\n // filter (`#computeUnionFilter`); the client fans out incoming events\n // to matching subscriptions via `matchesSubscription` in\n // `#handleIncoming`. The stream rotates (open-before-close) whenever\n // `subscribe`/`unsubscribe` changes the channel union.\n #sharedStream: EventStreamHandle | null = null;\n #sharedStreamFilter: SubscribeParams | null = null;\n #rotationState: \"idle\" | \"scheduled\" | \"rotating\" = \"idle\";\n /** Pending `subscribe()` promises waiting for a covering rotation. */\n readonly #pendingSubResolves: PendingSubResolve[] = [];\n #terminalPauseTimer: ReturnType<typeof setTimeout> | undefined;\n #terminalPauseSeq: number | null | undefined;\n\n #lifecycleSubId: string | null = null;\n #lifecycleStartPromise?: Promise<void>;\n\n // Set to the in-flight `run.start` send while it is awaiting the\n // server response, then cleared. Sites that open server-side\n // resources against `/threads/{id}/stream/events` (the SSE content\n // pump, the SSE lifecycle watcher, and the WS `subscription.subscribe`\n // command) await this so they don't race the thread's server-side\n // creation and trip a `404: Thread not found`. Subscribers that\n // arrive after `run.start` resolves see `null` and proceed\n // immediately — `await null` is a microtask, not a real wait — so\n // late selector-hook mounts (`useToolCalls` after subagent discovery)\n // take no extra latency.\n #runStartReady: Promise<void> | null = null;\n\n // ---------- v2 lifecycle watcher ----------\n // Dedicated wildcard `{channels: [\"lifecycle\", \"input\"]}` stream\n // opened by `submitRun` / `respondInput` (v2 entry points). Carries\n // every interrupt and lifecycle event at any depth so consumers of\n // `onEvent` (discovery runners, nested HITL capture) don't depend\n // on the content pump's narrow filter.\n //\n // - SSE: opened via `openEventStream` as an independent stream\n // that sits outside `#computeUnionFilter`, so the shared SSE\n // content pump stays narrow. Tracked in `#lifecycleWatcherHandle`\n // so `close()` can tear it down.\n // - WebSocket: opened via `#subscribeRaw` on the shared command\n // connection. The resulting `SubscriptionHandle` is managed by\n // the normal `#subscriptions` lifecycle, so no separate handle\n // reference is needed — `close()` fans `SubscriptionHandle.close`\n // across all registered subs.\n #lifecycleWatcherHandle: EventStreamHandle | null = null;\n #lifecycleWatcherStartPromise?: Promise<void>;\n\n // ---------- v2 unified event fan-out ----------\n // Listeners invoked once per globally-unique event across BOTH the\n // content pump and the lifecycle watcher. Used by `StreamController`\n // to consume discovery and interrupt events without opening extra\n // server subscriptions.\n readonly #onEventListeners = new Set<(event: Event) => void>();\n readonly #onErrorListeners = new Set<(error: Error) => void>();\n\n #messagesIterable?: AsyncIterable<StreamingMessageHandle>;\n #valuesProjection?: AsyncIterable<unknown> & PromiseLike<unknown>;\n #toolCallsIterable?: AsyncIterable<ClientAssembledToolCall>;\n #subgraphsIterable?: AsyncIterable<SubgraphHandle>;\n #subagentsIterable?: AsyncIterable<SubagentHandle>;\n #outputPromise?: Promise<unknown>;\n #extensionsProxy?: ThreadExtensions<TExtensions>;\n readonly #extensionsCache = new Map<string, ThreadExtension<unknown>>();\n\n /**\n * Shared state for the single `\"custom\"` channel subscription that\n * backs every `thread.extensions.<name>` handle.\n *\n * One subscription is opened eagerly from {@link run.start} (mirroring\n * the {@link values} eager-start pattern) so that per-name handles\n * created before, during, or after the run can all resolve correctly.\n *\n * - `events` retains every custom event for backfill into\n * late-constructed handles.\n * - `eventListeners` fan new events out to live per-name handlers.\n * - `endListeners` fire when the dispatcher's run terminates, so each\n * handle can resolve its `PromiseLike` side with its last-seen\n * payload.\n */\n #extensionsDispatcherStarted = false;\n #extensionsEnded = false;\n readonly #extensionsEvents: Event[] = [];\n readonly #extensionsEventListeners: Array<(event: Event) => void> = [];\n readonly #extensionsEndListeners: Array<() => void> = [];\n\n /**\n * Shared state for the single `messages`-channel subscription that\n * backs every media handle iterable (`thread.audio`, `thread.images`,\n * `thread.video`, `thread.files`). One subscription serves all four\n * iterables; per-type buffers track the handles already emitted so\n * late attachers replay through {@link MultiCursorBuffer}.\n */\n #mediaDispatcherStarted = false;\n #mediaAssembler: MediaAssembler | undefined;\n /** Object URLs minted by media handles, tracked for {@link close} cleanup. */\n readonly #mediaHandles = new Set<AnyMediaHandle>();\n readonly #audioBuffer = new MultiCursorBuffer<AudioMedia>();\n readonly #imagesBuffer = new MultiCursorBuffer<ImageMedia>();\n readonly #videoBuffer = new MultiCursorBuffer<VideoMedia>();\n readonly #filesBuffer = new MultiCursorBuffer<FileMedia>();\n readonly #fetchOption: typeof fetch | undefined;\n\n constructor(\n transportAdapter: TransportAdapter,\n options: ThreadStreamOptions\n ) {\n if (!options?.assistantId) {\n throw new Error(\"ThreadStream requires an assistantId option.\");\n }\n this.#transportAdapter = transportAdapter;\n this.threadId = transportAdapter.threadId;\n this.assistantId = options.assistantId;\n this.#nextCommandId = options.startingCommandId ?? 1;\n this.#fetchOption = options.fetch;\n this.run = {\n start: async (params) => {\n this.#prepareForNextRun();\n // Kick off the lifecycle watcher and the values projection\n // SYNCHRONOUSLY so the React layer (and any other consumer that\n // races subagent discovery) sees them registered immediately.\n // Both open server-side subscriptions on\n // `/threads/{id}/stream/events`, which would 404 if they landed\n // before `run.start` committed the thread server-side — so we\n // stage them behind `#runStartReady`, a promise resolved when\n // the in-flight `run.start` send completes. Sites that open\n // SSE/WS resources await this gate; everything else (event\n // dispatch, projection bookkeeping) runs without delay.\n return await this.#withRunStartGate(() => {\n this.#ensureLifecycleTracking();\n // Eagerly start the values projection so `thread.output` /\n // `thread.values` resolve with the final state regardless of\n // whether they are accessed before or after the run completes.\n // Without this, late access would open a fresh subscription\n // that misses every `values` event from the run.\n void this.values;\n // NOTE: `thread.extensions.<name>` is NOT eagerly subscribed.\n // The shared custom dispatcher is opened lazily on first\n // extension access and relies on the server's event buffer to\n // replay any custom events that were emitted before the\n // subscription landed. This keeps the zero-extensions hot path\n // free of an unused `custom` subscription per run.\n return this.#send(\"run.start\", {\n ...foldForkFromIntoConfig(params),\n assistant_id: this.assistantId,\n });\n });\n },\n };\n this.agent = {\n getTree: async (params = {}) =>\n (await this.#send(\"agent.getTree\", params)) as {\n tree: unknown;\n } as never,\n };\n this.input = {\n respond: async (params) => {\n this.#prepareForNextRun();\n this.#ensureLifecycleTracking();\n // See note in `run.start` — keep `thread.output` working\n // across resumes regardless of access order.\n void this.values;\n await this.#send(\"input.respond\", params);\n },\n inject: async (params) => {\n await this.#send(\n \"input.inject\",\n params as unknown as CommandParamsMap[\"input.inject\"]\n );\n },\n };\n this.state = {\n get: async (params) =>\n await this.#send(\n \"state.get\",\n params as unknown as CommandParamsMap[\"state.get\"]\n ),\n listCheckpoints: async (params) =>\n await this.#send(\n \"state.listCheckpoints\",\n params as unknown as CommandParamsMap[\"state.listCheckpoints\"]\n ),\n fork: async (params) =>\n await this.#send(\n \"state.fork\",\n params as unknown as CommandParamsMap[\"state.fork\"]\n ),\n };\n // SSE transports deliver events via openEventStream — the events()\n // iterable is inert. Skip the consumer loop in that case.\n if (this.#transportAdapter.openEventStream == null) {\n const wsTransport = this.#transportAdapter as {\n setOnReconnected?: (handler: () => void | Promise<void>) => void;\n };\n wsTransport.setOnReconnected?.(() =>\n this.#resubscribeWebSocketSubscriptions()\n );\n void this.#consumeEvents();\n }\n }\n\n /**\n * Ensure the underlying transport is connected.\n *\n * For HTTP/SSE this is a no-op. For WebSocket this performs the\n * handshake. Called lazily on first command; safe to call multiple times.\n */\n async #ensureOpen(): Promise<void> {\n if (this.#opened) return;\n if (this.#openPromise == null) {\n this.#openPromise = this.#transportAdapter.open().then(() => {\n this.#opened = true;\n });\n }\n await this.#openPromise;\n }\n\n /**\n * Channels bundled into every lazy getter's SSE filter so that\n * interrupt tracking works without a separate lifecycle subscription.\n */\n #lifecycleChannels(): Channel[] {\n return [\"lifecycle\", \"input\"];\n }\n\n /**\n * Lazily start a dedicated lifecycle+input subscription so that\n * `thread.interrupted` / `thread.interrupts` work even when the\n * caller never accesses a lazy getter (e.g. they only call\n * `run.start` and `subscribe({ channels: [\"custom:...\"] })`).\n *\n * Idempotent and fire-and-forget — invoked from `run.start` and\n * `input.respond`.\n */\n #ensureLifecycleTracking(): void {\n if (this.#lifecycleStartPromise != null) return;\n this.#lifecycleStartPromise = (async () => {\n const sub = await this.#subscribeRaw({\n channels: this.#lifecycleChannels(),\n });\n this.#lifecycleSubId = sub.subscriptionId;\n })().catch(() => undefined);\n }\n\n /**\n * Run `operation` (a `run.start` send) while holding the run-start\n * gate. Sets `#runStartReady` before invoking `operation` so any\n * subscription kicked off synchronously inside it (e.g. the lifecycle\n * watcher and the values projection) sees the gate when it eventually\n * reaches `#startLifecycleWatcherSse` / `#reconcileStream` /\n * `#subscribeViaCommand` and awaits it. The gate resolves the moment\n * `operation` settles, so server-side subscribes land immediately\n * after the thread is committed.\n */\n async #withRunStartGate<T>(operation: () => Promise<T>): Promise<T> {\n let resolveGate!: () => void;\n let rejectGate!: (err: unknown) => void;\n const gate = new Promise<void>((resolve, reject) => {\n resolveGate = resolve;\n rejectGate = reject;\n });\n this.#runStartReady = gate;\n // Swallow unhandled rejection: gate-awaiters that surface the\n // rejection via their own error path don't need a second log line,\n // and consumers that never await it (the typical case once\n // `run.start` resolves successfully) shouldn't trigger\n // `unhandledrejection` either.\n gate.catch(() => undefined);\n try {\n const result = await operation();\n resolveGate();\n return result;\n } catch (err) {\n rejectGate(err);\n throw err;\n } finally {\n // Only clear the gate if it's still our gate. Concurrent\n // run.start calls (multitaskStrategy: enqueue) would otherwise\n // null out a later call's gate when this earlier call's finally\n // ran, leaving subscribers that raced in after our finally but\n // before the later run.start commits with no gate to wait on.\n if (this.#runStartReady === gate) {\n this.#runStartReady = null;\n }\n }\n }\n\n /**\n * Reset interrupt state and resume all paused user subscriptions.\n * Called before `run.start()` and `input.respond()` so that\n * iterators on the same handle pick up the next run's events.\n *\n * @param respondedInterruptId - When responding to one of several\n * pending interrupts, only that entry is removed. Clearing the\n * full list here would drop other headless-tool interrupts that\n * are still awaiting client execution.\n */\n #prepareForNextRun(respondedInterruptId?: string | readonly string[]): void {\n this.interrupted = false;\n if (respondedInterruptId != null) {\n const respondedIds = new Set(\n Array.isArray(respondedInterruptId)\n ? respondedInterruptId\n : [respondedInterruptId as string]\n );\n for (let index = this.interrupts.length - 1; index >= 0; index -= 1) {\n if (respondedIds.has(this.interrupts[index].interruptId)) {\n this.interrupts.splice(index, 1);\n }\n }\n } else {\n this.interrupts.length = 0;\n }\n if (this.#terminalPauseTimer != null) {\n clearTimeout(this.#terminalPauseTimer);\n this.#terminalPauseTimer = undefined;\n }\n this.#terminalPauseSeq = undefined;\n for (const [id, subscription] of this.#subscriptions) {\n if (id !== this.#lifecycleSubId) {\n subscription.resume();\n }\n }\n }\n\n // ---------- Lazy getters mirroring in-process GraphRunStream ----------\n\n /**\n * Streaming messages. Each `for await` loop gets an independent cursor\n * over the shared buffer; late consumers see all previously emitted\n * messages. Mirrors the in-process `run.messages`.\n */\n get messages(): AsyncIterable<StreamingMessageHandle> {\n if (this.#messagesIterable) return this.#messagesIterable;\n const buffer = new MultiCursorBuffer<StreamingMessageHandle>();\n this.#messagesIterable = buffer;\n const assembler = new StreamingMessageAssembler();\n void this.#startProjection(\n [\"messages\", ...this.#lifecycleChannels()],\n (event) => {\n if (isRootTerminalLifecycle(event)) {\n assembler.abandonActive();\n return;\n }\n if (event.method !== \"messages\") return;\n const msg = assembler.consume(event as MessagesEvent);\n if (msg) buffer.push(toStreamingMessageHandle(msg));\n },\n () => {\n assembler.abandonActive();\n buffer.close();\n }\n );\n return buffer;\n }\n\n /**\n * State values. Iterable for intermediate snapshots; also\n * `PromiseLike` — `await thread.values` resolves with the final\n * state. Mirrors the in-process `run.values`.\n */\n get values(): AsyncIterable<unknown> & PromiseLike<unknown> {\n if (this.#valuesProjection) return this.#valuesProjection;\n const buffer = new MultiCursorBuffer<unknown>();\n let lastValue: unknown;\n let resolveOutput!: (value: unknown) => void;\n const outputPromise = new Promise<unknown>((resolve) => {\n resolveOutput = resolve;\n });\n this.#outputPromise = outputPromise;\n const projection = Object.assign(buffer, {\n then: <TResult1 = unknown, TResult2 = never>(\n onfulfilled?:\n | ((value: unknown) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?:\n | ((reason: unknown) => TResult2 | PromiseLike<TResult2>)\n | null\n ): Promise<TResult1 | TResult2> =>\n outputPromise.then(onfulfilled, onrejected),\n }) as AsyncIterable<unknown> & PromiseLike<unknown>;\n this.#valuesProjection = projection;\n void this.#startProjection(\n [\"values\", ...this.#lifecycleChannels()],\n (event) => {\n if (event.method !== \"values\") return;\n const data = coerceStateMessages((event as ValuesEvent).params.data);\n lastValue = data;\n buffer.push(data);\n },\n () => {\n resolveOutput(lastValue);\n buffer.close();\n }\n );\n return projection;\n }\n\n /**\n * Tool calls with a promise-based {@link output} for script consumers.\n * Mirrors the in-process `run.toolCalls`.\n */\n get toolCalls(): AsyncIterable<ClientAssembledToolCall> {\n if (this.#toolCallsIterable) return this.#toolCallsIterable;\n const buffer = new MultiCursorBuffer<ClientAssembledToolCall>();\n this.#toolCallsIterable = buffer;\n const assembler = new ToolCallAssembler();\n void this.#startProjection(\n [\"tools\", ...this.#lifecycleChannels()],\n (event) => {\n if (event.method !== \"tools\") return;\n const tc = assembler.consume(event as ToolsEvent);\n if (tc) buffer.push(toClientAssembledToolCall(tc));\n },\n () => buffer.close()\n );\n return buffer;\n }\n\n /**\n * Discovered subgraphs. Mirrors the in-process `run.subgraphs`.\n */\n get subgraphs(): AsyncIterable<SubgraphHandle> {\n if (this.#subgraphsIterable) return this.#subgraphsIterable;\n const buffer = new MultiCursorBuffer<SubgraphHandle>();\n this.#subgraphsIterable = buffer;\n void (async () => {\n const rawHandle = await this.#subscribeRaw({\n channels: [\"tools\", ...this.#lifecycleChannels()],\n });\n const discovery = new SubgraphDiscoveryHandle(rawHandle, this, []);\n for await (const sub of discovery) {\n buffer.push(sub);\n }\n buffer.close();\n })();\n return buffer;\n }\n\n /**\n * Discovered subagents.\n */\n get subagents(): AsyncIterable<SubagentHandle> {\n if (this.#subagentsIterable) return this.#subagentsIterable;\n const buffer = new MultiCursorBuffer<SubagentHandle>();\n this.#subagentsIterable = buffer;\n void (async () => {\n const rawHandle = await this.#subscribeRaw({\n channels: [\"tools\", ...this.#lifecycleChannels()],\n });\n const discovery = new SubagentDiscoveryHandle(rawHandle, this);\n for await (const sub of discovery) {\n buffer.push(sub);\n }\n buffer.close();\n })();\n return buffer;\n }\n\n /**\n * Audio media handles, one per message containing at least one\n * `AudioBlock`. Each `for await` opens an independent cursor over\n * the shared buffer; late consumers replay every previously emitted\n * audio handle.\n *\n * Yields one item per message on the first matching\n * `content-block-start` — messages with no audio blocks are skipped.\n */\n get audio(): AsyncIterable<AudioMedia> {\n this.#ensureMediaDispatcher();\n return this.#audioBuffer;\n }\n\n /**\n * Image media handles, one per message containing at least one\n * `ImageBlock`. See {@link audio} for shared semantics.\n */\n get images(): AsyncIterable<ImageMedia> {\n this.#ensureMediaDispatcher();\n return this.#imagesBuffer;\n }\n\n /**\n * Video media handles, one per message containing at least one\n * `VideoBlock`. See {@link audio} for shared semantics.\n */\n get video(): AsyncIterable<VideoMedia> {\n this.#ensureMediaDispatcher();\n return this.#videoBuffer;\n }\n\n /**\n * File media handles, one per message containing at least one\n * `FileBlock`. See {@link audio} for shared semantics.\n */\n get files(): AsyncIterable<FileMedia> {\n this.#ensureMediaDispatcher();\n return this.#filesBuffer;\n }\n\n /**\n * Promise that resolves with the final state value when the run\n * completes. Shares the `values` getter's SSE connection.\n * Mirrors the in-process `run.output`.\n */\n get output(): Promise<unknown> {\n // Accessing `this.values` ensures the projection is started.\n void this.values;\n return this.#outputPromise!;\n }\n\n /**\n * Proxy over compile-time {@link StreamTransformer} projections\n * exposed by the bound assistant on `custom:<name>` channels.\n *\n * Each access (e.g. `thread.extensions.toolActivity`) lazily opens a\n * dedicated `custom:<name>` subscription, returns a cached\n * {@link ThreadExtension} handle that is both `AsyncIterable<T>`\n * (streaming items as they arrive) and `PromiseLike<T>` (resolves\n * with the final value when the run terminates), and reuses the same\n * handle on subsequent access.\n *\n * Mirrors the in-process `run.extensions.<name>` shape.\n */\n get extensions(): ThreadExtensions<TExtensions> {\n if (this.#extensionsProxy) return this.#extensionsProxy;\n const cache = this.#extensionsCache;\n const createExtension = (name: string) => this.#createExtension(name);\n this.#extensionsProxy = new Proxy(\n Object.create(null) as ThreadExtensions<TExtensions>,\n {\n get: (_target, prop) => {\n if (typeof prop !== \"string\") return undefined;\n const cached = cache.get(prop);\n if (cached) return cached;\n const extension = createExtension(prop);\n cache.set(prop, extension);\n return extension;\n },\n has: (_target, prop) => typeof prop === \"string\",\n }\n );\n return this.#extensionsProxy;\n }\n\n /**\n * Lazily open one shared subscription on the `custom` channel that\n * buffers every custom event for this run and fans it out to any\n * per-name extension handles.\n *\n * Deliberately **lazy**: the dispatcher only starts on first access\n * to `thread.extensions.<name>`. Runs that never touch extensions\n * pay no subscription cost. Runs that touch extensions after events\n * have already fired rely on the server's per-session event buffer,\n * which replays matching events to new subscriptions.\n *\n * Each handle retains a PromiseLike that resolves with the\n * transformer's last-observed payload, independent of when the\n * caller grabs the handle (before, during, or after the run), as\n * long as the server still has the events buffered.\n *\n * Idempotent. Invoked only from {@link #createExtension}.\n */\n #ensureExtensionsDispatcher(): void {\n if (this.#extensionsDispatcherStarted) return;\n this.#extensionsDispatcherStarted = true;\n void this.#startProjection(\n [\"custom\", ...this.#lifecycleChannels()],\n (event) => {\n if (event.method !== \"custom\") return;\n this.#extensionsEvents.push(event);\n for (const listener of this.#extensionsEventListeners) {\n listener(event);\n }\n },\n () => {\n this.#extensionsEnded = true;\n const listeners = this.#extensionsEndListeners.splice(0);\n for (const listener of listeners) listener();\n },\n // Late-bound dispatchers (created after the run already terminated)\n // are skipped by the shared-stream pause logic — their\n // `registeredAfterSeq` is already past the terminal seq, which is\n // intended to keep nested replays draining for raw `subscribe()`\n // callers. The dispatcher needs the OPPOSITE: once the run's\n // terminal lifecycle replays through, settle the per-name\n // `PromiseLike`s with their last-observed payload. Detect the\n // terminal explicitly here so a late `thread.extensions.<name>`\n // access still resolves.\n { endOnRootTerminal: true }\n );\n }\n\n /**\n * Open the single shared `messages`-channel subscription that backs\n * every media iterable (audio/images/video/files). Idempotent.\n *\n * The {@link MediaAssembler} fans out to four per-type\n * {@link MultiCursorBuffer}s; each buffer feeds its corresponding\n * lazy getter. One handle is yielded per `(messageId, blockType)` on\n * the first matching `content-block-start`, so messages without any\n * media blocks of a given type never appear on that iterable.\n */\n #ensureMediaDispatcher(): void {\n if (this.#mediaDispatcherStarted) return;\n this.#mediaDispatcherStarted = true;\n const assembler = new MediaAssembler({\n fetch: this.#fetchOption,\n onAudio: (m) => {\n this.#mediaHandles.add(m);\n this.#audioBuffer.push(m);\n },\n onImage: (m) => {\n this.#mediaHandles.add(m);\n this.#imagesBuffer.push(m);\n },\n onVideo: (m) => {\n this.#mediaHandles.add(m);\n this.#videoBuffer.push(m);\n },\n onFile: (m) => {\n this.#mediaHandles.add(m);\n this.#filesBuffer.push(m);\n },\n });\n this.#mediaAssembler = assembler;\n void this.#startProjection(\n [\"messages\", ...this.#lifecycleChannels()],\n (event) => {\n if (event.method !== \"messages\") return;\n assembler.consume(event as MessagesEvent);\n },\n () => {\n assembler.close();\n this.#audioBuffer.close();\n this.#imagesBuffer.close();\n this.#videoBuffer.close();\n this.#filesBuffer.close();\n }\n );\n }\n\n /**\n * Build a single {@link ThreadExtension} handle for a named\n * `custom:<name>` projection.\n *\n * The handle reads from the shared extensions dispatcher: past events\n * matching {@link name} are backfilled on construction, future events\n * arrive via a registered listener, and the handle's `PromiseLike`\n * side resolves with its last-seen payload once the run terminates\n * (which may already have happened, in which case it resolves on the\n * next microtask).\n */\n #createExtension(name: string): ThreadExtension<unknown> {\n this.#ensureExtensionsDispatcher();\n\n const buffer = new MultiCursorBuffer<unknown>();\n let lastValue: unknown;\n let resolveFinal!: (value: unknown) => void;\n const finalPromise = new Promise<unknown>((resolve) => {\n resolveFinal = resolve;\n });\n\n const handleEvent = (event: Event) => {\n const data = event.params.data as\n | {\n name?: string;\n payload?: unknown;\n }\n | undefined;\n if (data?.name !== name) return;\n lastValue = data.payload;\n buffer.push(data.payload);\n };\n\n // Backfill from events already seen by the dispatcher so handles\n // constructed mid-run or post-run still observe their payload.\n for (const event of this.#extensionsEvents) handleEvent(event);\n\n // Live events — routed through the shared dispatcher.\n this.#extensionsEventListeners.push(handleEvent);\n\n const settle = () => {\n resolveFinal(lastValue);\n buffer.close();\n };\n if (this.#extensionsEnded) {\n settle();\n } else {\n this.#extensionsEndListeners.push(settle);\n }\n\n return Object.assign(buffer, {\n then: <TResult1 = unknown, TResult2 = never>(\n onfulfilled?:\n | ((value: unknown) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?:\n | ((reason: unknown) => TResult2 | PromiseLike<TResult2>)\n | null\n ): Promise<TResult1 | TResult2> =>\n finalPromise.then(onfulfilled, onrejected),\n }) as ThreadExtension<unknown>;\n }\n\n /**\n * Generic projection starter: opens a raw subscription with the given\n * channels, feeds events through the consumer, and calls onDone when\n * the stream ends.\n *\n * When `endOnRootTerminal` is set, the projection unsubscribes its\n * own handle one macrotask after observing a root-namespace terminal\n * lifecycle event. This is needed by projections that may be opened\n * AFTER a run already terminated: the shared-stream pause logic\n * skips subscriptions whose `registeredAfterSeq` is past the\n * terminal so raw `subscribe()` callers can keep draining replayed\n * descendants — but a per-run dispatcher (e.g. the extensions\n * pipeline) needs the projection to settle so its `PromiseLike`\n * surface resolves. The macrotask deferral mirrors the deferred\n * pause in `#handleIncoming`, giving trailing same-tick custom\n * events (transformer `finalize()` flushes) a chance to drain.\n */\n async #startProjection(\n channels: Channel[],\n onEvent: (event: Event) => void,\n onDone: () => void,\n options: { endOnRootTerminal?: boolean } = {}\n ): Promise<void> {\n let endTimer: ReturnType<typeof setTimeout> | undefined;\n let rawHandle: SubscriptionHandle<Event> | undefined;\n try {\n rawHandle = await this.#subscribeRaw({ channels });\n const handle = rawHandle;\n for await (const event of handle) {\n onEvent(event);\n if (\n options.endOnRootTerminal &&\n endTimer == null &&\n isRootTerminalLifecycle(event)\n ) {\n endTimer = setTimeout(() => {\n endTimer = undefined;\n void handle.unsubscribe().catch(() => undefined);\n }, 0);\n }\n }\n } catch {\n // Projection streams are best-effort views over the shared thread\n // stream. Surface-level errors are reflected through the controller\n // state; this background task only needs to settle cleanly.\n } finally {\n if (endTimer != null) clearTimeout(endTimer);\n onDone();\n }\n }\n\n // ---------- v2 entry points ----------\n\n /**\n * Start a run without the v1 eager lazy-getter shims.\n *\n * `run.start` (the v1 entry point) eagerly opens a wildcard `values`\n * projection so `thread.output` / `thread.values` resolve regardless\n * of access order, and calls `#ensureLifecycleTracking` which opens\n * another wildcard `[\"lifecycle\", \"input\"]` subscription. Both\n * subscriptions widen `#computeUnionFilter` to wildcard, defeating\n * the progressive-expansion rotation strategy.\n *\n * `submitRun` skips those shims — callers that manage their own\n * content subscriptions (such as `StreamController`) get the narrow\n * union filter they asked for. Lifecycle / interrupt tracking is\n * instead served by the dedicated `#startLifecycleWatcher`, which\n * opens a wildcard `[\"lifecycle\", \"input\"]` stream alongside the\n * narrow content pump on both SSE and WebSocket transports.\n */\n async submitRun(params: {\n input?: unknown;\n config?: unknown;\n metadata?: Record<string, unknown>;\n /**\n * Fork the new run from an explicit checkpoint instead of the\n * thread's latest. This is an SDK-side convenience: it is folded into\n * `config.configurable.checkpoint_id` before the `run.start` message\n * is sent, so the agent server only ever sees the single\n * legacy-compliant fork field (`forkFrom` never hits the wire).\n */\n forkFrom?: string;\n /**\n * Controls how concurrent submissions on the same thread are\n * handled by the server (`reject` | `rollback` | `interrupt` |\n * `enqueue`).\n */\n multitaskStrategy?: \"reject\" | \"rollback\" | \"interrupt\" | \"enqueue\";\n }): Promise<RunResult> {\n this.#prepareForNextRun();\n // See `this.run.start` for the gating rationale — the lifecycle\n // watcher must register synchronously (so subagent discovery and\n // its downstream `useToolCalls` / `useMessages` subscriptions\n // don't race the run), but its server-side SSE/WS open is staged\n // behind `#runStartReady` to avoid a `404: Thread not found`.\n return await this.#withRunStartGate(() => {\n this.#startLifecycleWatcher();\n return this.#send(\"run.start\", {\n ...(foldForkFromIntoConfig(params) as Record<string, unknown>),\n assistant_id: this.assistantId,\n });\n });\n }\n\n /**\n * Respond to an interrupt without the v1 eager lazy-getter shims.\n * See {@link submitRun} for why this exists alongside\n * {@link input.respond}.\n */\n async respondInput(params: InputRespondParams): Promise<void> {\n // `InputRespondParams` is `InputRespondOne | InputRespondMany`. The\n // batch variant (`responses`) resolves several interrupts pending at\n // the same checkpoint in one command; the single variant carries a\n // top-level `interrupt_id`.\n const respondedIds =\n \"responses\" in params\n ? params.responses.map((entry) => entry.interrupt_id)\n : params.interrupt_id;\n this.#prepareForNextRun(respondedIds);\n this.#startLifecycleWatcher();\n await this.#send(\"input.respond\", params);\n }\n\n /**\n * Register a listener for every globally-unique event on the thread.\n *\n * Fires exactly once per `event_id` across both the content pump\n * (user `subscribe()` calls) and the lifecycle watcher. Events\n * without an `event_id` always fire through (dedup is best-effort).\n *\n * Returns an unsubscribe function. Primary consumer is\n * `StreamController`, which uses the listener to feed discovery\n * runners and pick up deeply-nested interrupts that the narrow\n * content pump wouldn't deliver.\n */\n onEvent(listener: (event: Event) => void): () => void {\n this.#onEventListeners.add(listener);\n return () => {\n this.#onEventListeners.delete(listener);\n };\n }\n\n /**\n * Register a listener for stream-level failures: an unsolicited server\n * error frame, or the transport giving up on reconnecting. Returns an\n * unsubscribe function.\n */\n onError(listener: (error: Error) => void): () => void {\n this.#onErrorListeners.add(listener);\n return () => {\n this.#onErrorListeners.delete(listener);\n };\n }\n\n /**\n * Lazily open the wildcard discovery watcher stream.\n *\n * Idempotent. Used by both transports, but through different\n * mechanisms:\n *\n * - **SSE**: opens a dedicated event stream via\n * {@link TransportAdapter.openEventStream}. The stream runs\n * outside `#computeUnionFilter`, so the shared SSE stream's\n * content pump can stay narrow (e.g. `depth: 1`) while we still\n * capture every lifecycle/input event at any depth.\n * - **WebSocket**: opens a wildcard watcher subscription\n * subscription via the normal command path. The WS server\n * delivers matching events on the shared command connection and\n * `#handleIncoming` dispatches them through `#fireOnEvent` and\n * the thread-level effects — same downstream semantics as the\n * SSE watcher, just reusing the transport that's already open.\n *\n * Why this matters: consumers of {@link onEvent} (notably\n * `StreamController`'s subgraph/subagent discovery runners and\n * nested interrupt capture) depend on observing namespaced\n * lifecycle events at any depth. Without this watcher, WS clients\n * would only ever receive events matching the content pump's\n * narrow filter (depth 1 from the root), breaking inference rules\n * that require deeper descendants (e.g. the \"has-descendants\"\n * signal used to promote a subgraph host).\n */\n #startLifecycleWatcher(): void {\n if (this.#lifecycleWatcherStartPromise != null) return;\n\n if (this.#transportAdapter.openEventStream != null) {\n this.#lifecycleWatcherStartPromise = this.#startLifecycleWatcherSse();\n return;\n }\n\n this.#lifecycleWatcherStartPromise = this.#startLifecycleWatcherWebSocket();\n }\n\n /**\n * Public, idempotent entry point to start the wildcard lifecycle\n * watcher.\n *\n * The watcher is normally started lazily by `submitRun` /\n * `respondInput` because for fresh (self-created) threads the SSE\n * stream would 404 if opened before the server has the thread row.\n * Callers that already know the thread exists server-side\n * (`StreamController.hydrate` of an existing thread) can use this\n * to start the watcher up front. The watcher subscribes to wildcard\n * lifecycle events across every namespace, so it sees arbitrarily-\n * nested subagent lifecycle messages that the narrow root content\n * pump (running at `depth: 1`) wouldn't reach — that's what makes\n * subagent discovery work for historical thread loads.\n *\n * Idempotent — repeat calls reuse the in-flight start promise.\n */\n startLifecycleWatcher(): void {\n this.#startLifecycleWatcher();\n }\n\n async #startLifecycleWatcherSse(): Promise<void> {\n // Wait for any in-flight `run.start` send to commit the thread\n // server-side. Without this the SSE GET on\n // `/threads/{id}/stream/events` 404s and the watcher tears down\n // before delivering any lifecycle event.\n if (this.#runStartReady != null) {\n try {\n await this.#runStartReady;\n } catch {\n return;\n }\n }\n const filter: SubscribeParams = {\n channels: [\"lifecycle\", \"input\"],\n };\n let handle: EventStreamHandle;\n try {\n handle = this.#transportAdapter.openEventStream!(filter);\n } catch {\n return;\n }\n try {\n await handle.ready;\n } catch {\n try {\n handle.close();\n } catch {\n // best-effort\n }\n return;\n }\n if (this.#closed) {\n try {\n handle.close();\n } catch {\n // best-effort\n }\n return;\n }\n this.#lifecycleWatcherHandle = handle;\n try {\n for await (const message of handle.events) {\n if (this.#closed) break;\n this.#handleLifecycleWatcherMessage(message);\n }\n } catch {\n // Best-effort; the content pump handles surface-level errors.\n }\n }\n\n async #startLifecycleWatcherWebSocket(): Promise<void> {\n // `#subscribeRaw` on WS registers the subscription with the\n // server and buffers incoming events on a `SubscriptionHandle`.\n // All the side effects we care about (global dedup,\n // `#fireOnEvent` fan-out to `onEvent` listeners, interrupt\n // capture) already run in `#handleIncoming` regardless of which\n // subscription matched, so we don't need to process events on\n // the handle itself — we just drain it so its buffer doesn't\n // accumulate.\n let handle: SubscriptionHandle<Event>;\n try {\n handle = await this.#subscribeRaw({\n channels: [\"lifecycle\", \"input\"],\n });\n } catch {\n return;\n }\n if (this.#closed) {\n try {\n handle.close();\n } catch {\n // best-effort\n }\n return;\n }\n try {\n for await (const _event of handle) {\n if (this.#closed) break;\n }\n } catch {\n // Best-effort; surface-level errors are reported by the\n // content pump.\n }\n }\n\n /**\n * Process an event from the dedicated lifecycle watcher stream.\n *\n * Unlike `#handleIncoming`, this does NOT fan out to user\n * subscriptions — user subs with namespace wildcards already widen\n * `#computeUnionFilter` and therefore receive the event on the\n * content pump. Delivering via both streams would only add per-sub\n * dedup churn without expanding what the user can observe.\n *\n * We still run global-dedup thread-level side effects (interrupt\n * capture, `onEvent` fan-out) so deeply-nested interrupts outside\n * the content pump's narrow scope are recorded.\n */\n #handleLifecycleWatcherMessage(message: Message): void {\n if (message.type !== \"event\") return;\n if (typeof message.seq === \"number\") {\n this.ordering.lastSeenSeq = maxSeq(\n this.ordering.lastSeenSeq,\n message.seq\n );\n }\n if (message.event_id) {\n this.ordering.lastEventId = message.event_id;\n }\n const eventId = message.event_id ?? undefined;\n const globallyProcessed =\n eventId != null && this.#seenEventIds.has(eventId);\n if (eventId != null) this.#seenEventIds.add(eventId);\n if (globallyProcessed) return;\n this.#applyThreadLevelEffects(message);\n this.#fireOnEvent(message);\n }\n\n #applyThreadLevelEffects(event: Event): void {\n if (event.method === \"lifecycle\") {\n const lifecycle = event as LifecycleEvent;\n if (lifecycle.params.data.event === \"interrupted\") {\n this.interrupted = true;\n }\n }\n if (event.method === \"input.requested\") {\n const data = event.params.data;\n const interruptId =\n data.interrupt_id ?? `interrupt_${this.interrupts.length}`;\n this.interrupts.push({\n interruptId,\n payload: data.payload,\n namespace: [...event.params.namespace],\n });\n if (isHeadlessToolInterrupt(data.payload)) {\n this.#headlessInterruptsAwaitingTerminal.add(interruptId);\n }\n }\n }\n\n #fireOnEvent(event: Event): void {\n if (this.#onEventListeners.size === 0) return;\n for (const listener of this.#onEventListeners) {\n try {\n listener(event);\n } catch {\n // Best-effort — a bad listener should not wedge event delivery.\n }\n }\n }\n\n #fireOnError(error: Error): void {\n for (const listener of this.#onErrorListeners) {\n try {\n listener(error);\n } catch {\n // A throwing listener must not block delivery to the others.\n }\n }\n }\n\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n if (this.#terminalPauseTimer != null) {\n clearTimeout(this.#terminalPauseTimer);\n this.#terminalPauseTimer = undefined;\n }\n this.#terminalPauseSeq = undefined;\n // Reject any `subscribe()` promises still waiting for a covering\n // rotation, and tear down the shared SSE stream. A rotation in\n // flight will observe `#closed` after its `await ready` and bail.\n for (const pending of this.#pendingSubResolves) {\n pending.reject(new Error(\"ThreadStream closed\"));\n }\n this.#pendingSubResolves.length = 0;\n if (this.#sharedStream != null) {\n try {\n this.#sharedStream.close();\n } catch {\n // best-effort\n }\n this.#sharedStream = null;\n this.#sharedStreamFilter = null;\n }\n if (this.#lifecycleWatcherHandle != null) {\n try {\n this.#lifecycleWatcherHandle.close();\n } catch {\n // best-effort\n }\n this.#lifecycleWatcherHandle = null;\n }\n const lifecycleWatcherStartPromise = this.#lifecycleWatcherStartPromise;\n this.#lifecycleWatcherStartPromise = undefined;\n this.#onEventListeners.clear();\n this.#onErrorListeners.clear();\n for (const subscription of this.#subscriptions.values()) {\n subscription.close();\n }\n this.#subscriptions.clear();\n try {\n await lifecycleWatcherStartPromise;\n } catch {\n // best-effort\n }\n // Safety net: revoke any object URLs minted by media handles so\n // long-lived consumers don't leak after thread teardown.\n for (const handle of this.#mediaHandles) {\n try {\n handle.revoke();\n } catch {\n // best-effort\n }\n }\n this.#mediaHandles.clear();\n this.#mediaAssembler?.close();\n this.#audioBuffer.close();\n this.#imagesBuffer.close();\n this.#videoBuffer.close();\n this.#filesBuffer.close();\n await this.#transportAdapter.close();\n }\n\n /**\n * Subscribe to raw wire channels and receive protocol events.\n *\n * For assembled projections, use the lazy getters instead:\n * `thread.messages`, `thread.values`, `thread.toolCalls`,\n * `thread.subgraphs`, `thread.subagents`, `thread.output`.\n */\n async subscribe<TChannel extends Channel>(\n channel: TChannel,\n options?: SubscribeOptions\n ): Promise<\n SubscriptionHandle<EventForChannel<TChannel>, YieldForChannel<TChannel>>\n >;\n async subscribe<const TChannels extends readonly Channel[]>(\n channels: TChannels,\n options?: SubscribeOptions\n ): Promise<\n SubscriptionHandle<EventForChannels<TChannels>, YieldForChannels<TChannels>>\n >;\n async subscribe(params: SubscribeParams): Promise<SubscriptionHandle<Event>>;\n async subscribe(\n paramsOrChannels: SubscribeParams | Channel | readonly Channel[],\n options: SubscribeOptions = {}\n ): Promise<unknown> {\n // The string / string-array overloads are typed to unwrap\n // `custom:<name>` payloads for ergonomic single-extension\n // subscriptions (`thread.subscribe(\"custom:a2a\")` yields the\n // raw payload). The `SubscribeParams` object overload, however,\n // is typed as `SubscriptionHandle<Event>` — it must deliver the\n // full event envelope so callers like `channelProjection` (which\n // backs `useChannel`) can see the `method`, `namespace`, and\n // `data.name` fields needed for filtering and rendering.\n const isParamsObject =\n typeof paramsOrChannels === \"object\" &&\n !Array.isArray(paramsOrChannels) &&\n \"channels\" in paramsOrChannels;\n const params = normalizeSubscribeParams(\n paramsOrChannels as SubscribeParams | Channel | readonly Channel[],\n options\n );\n return await this.#subscribeRaw(params, {\n unwrapNamedCustom: !isParamsObject,\n });\n }\n\n async #subscribeRaw(\n params: SubscribeParams,\n options: { unwrapNamedCustom?: boolean } = {}\n ): Promise<SubscriptionHandle<Event>> {\n await this.#ensureOpen();\n const { unwrapNamedCustom = true } = options;\n const hasOnlyNamedCustom =\n params.channels.length > 0 &&\n params.channels.every((ch) => ch.startsWith(\"custom:\"));\n const transform =\n unwrapNamedCustom && hasOnlyNamedCustom\n ? (event: Event) =>\n (\n (event.params as Record<string, unknown>).data as {\n payload?: unknown;\n }\n )?.payload ?? event\n : undefined;\n\n if (this.#transportAdapter.openEventStream != null) {\n return this.#subscribeViaSharedStream(params, transform);\n }\n\n return this.#subscribeViaCommand(params, transform);\n }\n\n /**\n * Subscribe via the single shared SSE connection.\n *\n * The subscription is registered immediately in `#subscriptions` so\n * fan-out can reach it the moment events begin flowing. The returned\n * promise resolves after a stream rotation completes whose union\n * filter covers this subscription's channels — mirroring the per-sub\n * `await streamHandle.ready` semantics callers depended on.\n *\n * Every subscribe schedules a stream rotation, even when the current\n * stream's filter already covers `params`. Rotating opens a fresh\n * server-side session that replays the run's full history from\n * `seq=0`; without it a late-joining sub would only see events that\n * arrive after it registered, because the shared pump's dedup drops\n * events the existing sub already consumed. Per-sub dedup\n * (`seenEventIds`) protects existing subs from receiving the\n * replay as duplicates. Rapid subscribes in the same microtask are\n * coalesced by `#scheduleReconcile` into a single rotation.\n */\n async #subscribeViaSharedStream(\n params: SubscribeParams,\n transform?: (event: Event) => unknown\n ): Promise<SubscriptionHandle<Event>> {\n const subscriptionId = `sse-${this.#nextCommandId++}`;\n const handle = new SubscriptionHandle<Event, unknown>(\n subscriptionId,\n params,\n async (id) => {\n this.#subscriptions.delete(id);\n this.#scheduleReconcile();\n },\n transform\n );\n const subscription = Object.assign(handle, {\n filter: params,\n registeredAfterSeq: this.ordering.lastSeenSeq,\n seenEventIds: new Set<string>(),\n });\n this.#subscriptions.set(subscriptionId, subscription);\n\n const covered = new Promise<void>((resolve, reject) => {\n this.#pendingSubResolves.push({ filter: params, resolve, reject });\n });\n this.#scheduleReconcile();\n\n try {\n await covered;\n } catch (err) {\n this.#subscriptions.delete(subscriptionId);\n throw err;\n }\n return handle as SubscriptionHandle<Event>;\n }\n\n /**\n * Progressive-expansion union of every currently-registered\n * subscription's filter. The server receives the narrowest filter\n * that still covers every active sub so deeply-namespaced or\n * selectively-opened projections don't pull down the entire thread's\n * event firehose.\n *\n * Unioning rules (matching the server's matching semantics in\n * `matchesSinkFilter`):\n * - Channels: set union.\n * - Namespaces: if any subscription requests a wildcard\n * (`namespaces === undefined`) the union is wildcard; otherwise\n * the union is the deduplicated list of every explicit prefix.\n * - Depth: if any subscription is unbounded (`depth === undefined`)\n * the union is unbounded; otherwise the union is the maximum\n * depth across all subscriptions (matching the per-sub \"max\n * reach below the prefix\" semantics).\n *\n * Returns `null` when there are no subscriptions.\n */\n #computeUnionFilter(): SubscribeParams | null {\n if (this.#subscriptions.size === 0) return null;\n\n const channels = new Set<Channel>();\n let wildcardNamespaces = false;\n const namespaceMap = new Map<string, Namespace>();\n let unboundedDepth = false;\n let maxDepth = 0;\n\n for (const sub of this.#subscriptions.values()) {\n for (const ch of sub.filter.channels) channels.add(ch);\n\n if (sub.filter.namespaces == null) {\n wildcardNamespaces = true;\n } else if (!wildcardNamespaces) {\n for (const ns of sub.filter.namespaces) {\n namespaceMap.set(namespaceKey(ns), ns);\n }\n }\n\n if (sub.filter.depth == null) {\n unboundedDepth = true;\n } else if (!unboundedDepth && sub.filter.depth > maxDepth) {\n maxDepth = sub.filter.depth;\n }\n }\n\n const result: SubscribeParams = {\n channels: [...channels] as Channel[],\n };\n if (!wildcardNamespaces) {\n result.namespaces = [...namespaceMap.values()];\n }\n if (!unboundedDepth) {\n result.depth = maxDepth;\n }\n return result;\n }\n\n /**\n * Schedule a stream reconciliation for the next microtask.\n *\n * Coalesces multiple subscribe/unsubscribe calls in the same tick\n * into a single rotation, and serializes across ticks (no two\n * rotations ever run concurrently).\n */\n #scheduleReconcile(): void {\n if (this.#closed) return;\n if (this.#rotationState !== \"idle\") return;\n this.#rotationState = \"scheduled\";\n queueMicrotask(() => {\n if (this.#closed) {\n this.#rotationState = \"idle\";\n return;\n }\n this.#rotationState = \"idle\";\n void this.#reconcileStream().catch(() => {\n this.#rotationState = \"idle\";\n });\n });\n }\n\n /**\n * Reconcile the shared SSE stream to match the desired union filter.\n *\n * Rotation strategy: open the new stream first, await its `ready`,\n * then close the old one. Overlap is absorbed by `#seenEventIds`\n * dedup in `#handleIncoming`.\n *\n * Error handling:\n * - Failure before `ready` resolves: reject all pending `subscribe`\n * promises whose filter isn't covered by the existing stream,\n * and keep the existing stream running for other subscriptions.\n * - Failure mid-pump on the active stream: close the thread via\n * {@link #failThreadWithError} so higher layers can rebind.\n */\n async #reconcileStream(): Promise<void> {\n if (this.#closed) return;\n if (this.#rotationState === \"rotating\") return;\n\n const desired = this.#computeUnionFilter();\n if (desired == null) return;\n\n // Wait for any in-flight `run.start` send so the SSE GET on\n // `/threads/{id}/stream/events` doesn't 404 against a thread the\n // server hasn't created yet. Late subscribers (after `run.start`\n // resolves) see a null gate and proceed immediately. The\n // `openEventStream` adapter contract requires implementations to\n // buffer events and replay them on new opens, so the rotation\n // doesn't lose events that were emitted during the wait.\n if (this.#runStartReady != null) {\n try {\n await this.#runStartReady;\n } catch (err) {\n // The pending `run.start` failed; abandon this rotation and\n // let the rejected `run.start` surface the error to callers.\n // Forward the original cause so pending subscribers see the\n // real reason rather than a generic \"run.start failed\".\n const normalized =\n // oxlint-disable-next-line no-instanceof/no-instanceof\n err instanceof Error ? err : new Error(\"run.start failed\");\n this.#rejectUncoveredPending(normalized);\n return;\n }\n if (this.#closed) return;\n // Re-read through a local — TS narrowed `#rotationState` above\n // and doesn't widen it back across the await, but another\n // reconcile may have set it in the interim.\n const stateNow: string = this.#rotationState;\n if (stateNow === \"rotating\") return;\n }\n\n // Bail only when nothing structurally changed AND nobody is\n // waiting on a fresh replay. A pending sub always needs a\n // rotation even when the filter is unchanged, because the server\n // replays buffered events only at the moment the SSE connection\n // is opened.\n if (\n this.#sharedStreamFilter != null &&\n filterEqual(desired, this.#sharedStreamFilter) &&\n this.#pendingSubResolves.length === 0\n ) {\n this.#resolvePending();\n return;\n }\n\n this.#rotationState = \"rotating\";\n let newHandle: EventStreamHandle;\n try {\n newHandle = this.#transportAdapter.openEventStream!(desired);\n } catch (err) {\n this.#rotationState = \"idle\";\n this.#rejectUncoveredPending(err);\n return;\n }\n\n try {\n await newHandle.ready;\n } catch (err) {\n this.#rotationState = \"idle\";\n try {\n newHandle.close();\n } catch {\n // best-effort\n }\n this.#rejectUncoveredPending(err);\n return;\n }\n\n if (this.#closed) {\n try {\n newHandle.close();\n } catch {\n // best-effort\n }\n this.#rotationState = \"idle\";\n return;\n }\n\n void this.#pumpStream(newHandle);\n\n const oldHandle = this.#sharedStream;\n this.#sharedStream = newHandle;\n this.#sharedStreamFilter = desired;\n if (oldHandle != null) {\n try {\n oldHandle.close();\n } catch {\n // best-effort\n }\n }\n\n this.#rotationState = \"idle\";\n this.#resolvePending();\n\n const next = this.#computeUnionFilter();\n if (next != null && !filterEqual(next, this.#sharedStreamFilter)) {\n this.#scheduleReconcile();\n }\n }\n\n /**\n * Pump events from a shared-stream handle into `#handleIncoming`.\n * One pump task runs per open stream; during rotation overlap two\n * pumps may be active briefly, with `#seenEventIds` deduping.\n */\n async #pumpStream(handle: EventStreamHandle): Promise<void> {\n try {\n for await (const message of handle.events) {\n if (this.#closed) {\n break;\n }\n this.#handleIncoming(message);\n }\n } catch (err) {\n if (handle === this.#sharedStream && !this.#closed) {\n this.#failThreadWithError(err);\n }\n // Errors on an old (being-rotated-out) stream are ignored —\n // the new stream is already pumping and holds authoritative state.\n }\n }\n\n /**\n * Resolve any pending `subscribe()` promises whose filter is now\n * covered by the active shared stream. Called after every successful\n * rotation (and after no-op reconciliations).\n */\n #resolvePending(): void {\n if (this.#sharedStreamFilter == null) return;\n const current = this.#sharedStreamFilter;\n if (this.#pendingSubResolves.length === 0) return;\n const stillPending: PendingSubResolve[] = [];\n for (const pending of this.#pendingSubResolves) {\n if (filterCovers(current, pending.filter)) {\n pending.resolve();\n } else {\n stillPending.push(pending);\n }\n }\n this.#pendingSubResolves.length = 0;\n this.#pendingSubResolves.push(...stillPending);\n }\n\n /**\n * Reject pending `subscribe()` promises whose filter isn't covered\n * by the existing stream (they're the ones that triggered the\n * failed rotation). Covered pending subs are resolved normally —\n * they didn't need the new stream.\n */\n #rejectUncoveredPending(err: unknown): void {\n if (this.#pendingSubResolves.length === 0) return;\n const current = this.#sharedStreamFilter;\n const stillPending: PendingSubResolve[] = [];\n for (const pending of this.#pendingSubResolves) {\n if (current != null && filterCovers(current, pending.filter)) {\n pending.resolve();\n } else {\n stillPending.push(pending);\n }\n }\n this.#pendingSubResolves.length = 0;\n for (const pending of stillPending) pending.reject(err);\n }\n\n /**\n * Terminate the thread due to an unrecoverable shared-stream error.\n * Rejects pending commands, closes subscriptions, and marks the\n * thread closed so no further rotations occur.\n */\n #failThreadWithError(err: unknown): void {\n const normalized =\n // oxlint-disable-next-line no-instanceof/no-instanceof\n err instanceof Error ? err : new Error(String(err));\n for (const pending of this.#pending.values()) {\n pending.reject(normalized);\n }\n this.#pending.clear();\n for (const pending of this.#pendingSubResolves) {\n pending.reject(normalized);\n }\n this.#pendingSubResolves.length = 0;\n for (const subscription of this.#subscriptions.values()) {\n subscription.close();\n }\n this.#fireOnError(normalized);\n }\n\n /**\n * Command-based subscription (WebSocket fallback). The server replays\n * matching buffered events on subscribe via the same WebSocket stream.\n */\n async #subscribeViaCommand(\n params: SubscribeParams,\n transform?: (event: Event) => unknown\n ): Promise<SubscriptionHandle<Event>> {\n // Register the subscription on the client BEFORE sending the\n // ``subscription.subscribe`` command. The WebSocket server replays\n // buffered events through ``install_subscription_with_replay``\n // *before* returning the success response that carries the\n // ``subscription_id``. If we waited for the response and only then\n // ran ``this.#subscriptions.set(...)``, those replayed events would\n // arrive at ``#handleIncoming`` while no matching subscription is\n // registered — they would never reach the iterator, so\n // namespace-scoped projections (``useMessages``) would render\n // empty after click-to-expand on the WebSocket transport.\n //\n // ``#handleIncoming``'s fan-out matches purely on\n // ``subscription.filter`` (channels + namespaces + depth), so a\n // pre-registered entry under any temporary key already catches\n // every replayed event. Once the server-assigned id arrives, we\n // re-key the entry so a later ``unsubscribe`` finds it.\n // ``#nextCommandId`` is post-incremented inside ``#send``; reading\n // it here doesn't reserve the value, so two concurrent subscribes\n // (typical under React StrictMode's mount→unmount→mount) would\n // collide on the same placeholder. Mint a UUID-like suffix instead.\n const placeholderId = `pending:${this.#nextCommandId}:${Math.random().toString(36).slice(2, 10)}`;\n let resolvedId = placeholderId;\n const handle = new SubscriptionHandle<Event, unknown>(\n placeholderId,\n params,\n async () => {\n // Use the server-assigned id once we have it; fall back to the\n // placeholder while the subscribe command is still in flight\n // (unsubscribe before subscribe-response is unusual but\n // possible — disposing a projection that mounted and unmounted\n // in the same React tick).\n this.#subscriptions.delete(resolvedId);\n if (!this.#closed && resolvedId !== placeholderId) {\n await this.#send(\"subscription.unsubscribe\", {\n subscription_id: resolvedId,\n }).catch((err: unknown) => {\n if (\n // oxlint-disable-next-line no-instanceof/no-instanceof\n err instanceof ProtocolError &&\n err.code === \"no_such_subscription\"\n ) {\n return;\n }\n throw err;\n });\n }\n },\n transform\n );\n const subscription = Object.assign(handle, {\n filter: params,\n registeredAfterSeq: this.ordering.lastSeenSeq,\n seenEventIds: new Set<string>(),\n });\n this.#subscriptions.set(placeholderId, subscription);\n // Wait for any in-flight `run.start` send to commit the thread\n // server-side. WS `subscription.subscribe` is rejected with\n // `404: Thread not found` if it arrives before the thread is\n // created — mirroring the SSE gates in `#startLifecycleWatcherSse`\n // and `#reconcileStream`.\n if (this.#runStartReady != null) {\n try {\n await this.#runStartReady;\n } catch (err) {\n this.#subscriptions.delete(placeholderId);\n throw err;\n }\n }\n let result: SubscribeResult;\n try {\n result = await this.#send(\"subscription.subscribe\", params);\n } catch (err) {\n this.#subscriptions.delete(placeholderId);\n throw err;\n }\n this.#subscriptions.delete(placeholderId);\n resolvedId = result.subscription_id;\n // Re-key the map AND update the handle's public id. Without the\n // second write, `#lifecycleSubId === handle.subscriptionId` checks\n // (see `#prepareForNextRun` and the terminal-pause logic) compare\n // the cached placeholder against the live map key and silently\n // fail, causing the lifecycle subscription to be paused at\n // terminal events on the WS transport.\n handle.subscriptionId = resolvedId;\n this.#subscriptions.set(resolvedId, subscription);\n return handle as SubscriptionHandle<Event>;\n }\n\n /**\n * Re-issue `subscription.subscribe` for every active WS subscription\n * after the transport reconnects. The server replays buffered events on\n * the new socket; client-side `event_id` dedup suppresses duplicates.\n */\n async #resubscribeWebSocketSubscriptions(): Promise<void> {\n if (this.#transportAdapter.openEventStream != null || this.#closed) {\n return;\n }\n\n const entries = [...this.#subscriptions.entries()];\n await Promise.all(\n entries.map(async ([id, subscription]) => {\n if (id.startsWith(\"pending:\")) {\n return;\n }\n try {\n const result = await this.#send(\n \"subscription.subscribe\",\n subscription.filter\n );\n const nextId = result.subscription_id;\n if (nextId === id) {\n return;\n }\n this.#subscriptions.delete(id);\n (\n subscription as unknown as SubscriptionHandle<Event>\n ).subscriptionId = nextId;\n this.#subscriptions.set(nextId, subscription);\n if (this.#lifecycleSubId === id) {\n this.#lifecycleSubId = nextId;\n }\n } catch {\n // Best-effort; the content pump may still receive replayed events.\n }\n })\n );\n }\n\n async #consumeEvents(): Promise<void> {\n try {\n for await (const message of this.#transportAdapter.events()) {\n this.#handleIncoming(message);\n }\n for (const subscription of this.#subscriptions.values()) {\n subscription.close();\n }\n } catch (error) {\n this.#failThreadWithError(error);\n }\n }\n\n /**\n * Pause non-lifecycle subscriptions after a root terminal lifecycle.\n *\n * The pause is deferred one macrotask so same-run trailing events\n * emitted immediately after terminal (for example final `values`)\n * can still drain. `terminalSeq` lets replay attachers skip terminals\n * that happened before they registered, so late subscribers can keep\n * consuming the replayed history they joined for.\n */\n #scheduleTerminalPause(terminalSeq: number | undefined): void {\n if (this.#terminalPauseTimer != null) {\n clearTimeout(this.#terminalPauseTimer);\n }\n this.#terminalPauseSeq = terminalSeq ?? null;\n this.#terminalPauseTimer = setTimeout(() => {\n this.#terminalPauseTimer = undefined;\n if (this.#closed) return;\n for (const [id, subscription] of this.#subscriptions) {\n if (id === this.#lifecycleSubId) continue;\n if (\n terminalSeq != null &&\n subscription.registeredAfterSeq != null &&\n subscription.registeredAfterSeq >= terminalSeq\n ) {\n continue;\n }\n subscription.pause();\n }\n }, 0);\n }\n\n #handleIncoming(message: Message): void {\n if (message.type === \"event\") {\n if (typeof message.seq === \"number\") {\n this.ordering.lastSeenSeq = maxSeq(\n this.ordering.lastSeenSeq,\n message.seq\n );\n }\n if (message.event_id) {\n this.ordering.lastEventId = message.event_id;\n }\n\n // Two flavors of dedup live here:\n // 1. Thread-level side effects (interrupt state, interrupt\n // capture) — must run AT MOST ONCE per unique event_id\n // regardless of how many times the event is redelivered\n // (rotation overlap, WebSocket fan-out). Gated by the\n // global `#seenEventIds`.\n // 2. Per-subscription fan-out — gated by each sub's own\n // `seenEventIds`. This is what lets a rotation-triggered\n // replay (the server opens a fresh session that replays\n // from seq=0) reach newly-registered subs while NOT\n // redelivering events to subs that have already consumed\n // them. Event IDs are stable across sessions for the same\n // run, so per-sub set membership is the correct predicate.\n const eventId = message.event_id ?? undefined;\n const globallyProcessed =\n eventId != null && this.#seenEventIds.has(eventId);\n if (eventId != null) {\n this.#seenEventIds.add(eventId);\n }\n\n const TERMINAL_LIFECYCLE_EVENTS = new Set([\n \"interrupted\",\n \"completed\",\n \"failed\",\n ]);\n\n if (!globallyProcessed) {\n this.#applyThreadLevelEffects(message);\n this.#fireOnEvent(message);\n }\n\n // Unified fan-out: both SSE (shared stream) and WebSocket paths\n // deliver every event through a single connection; the client\n // dispatches to matching subscriptions based on each sub's\n // advertised filter, with per-sub dedup.\n let fannedToAny = false;\n for (const subscription of this.#subscriptions.values()) {\n if (!matchesSubscription(message, subscription.filter)) continue;\n if (eventId != null) {\n if (subscription.seenEventIds.has(eventId)) {\n continue;\n }\n subscription.seenEventIds.add(eventId);\n }\n subscription.push(message);\n fannedToAny = true;\n }\n\n // A root terminal schedules subscription pause on a macrotask,\n // but reconnect/replay can still deliver same-run trailing state\n // afterward (for example the final `values` snapshot). Drain that\n // event, briefly resume any paused consumers, then re-arm the\n // terminal pause so idle subscriptions still settle. This includes\n // root lifecycle events from a later run in the same replay.\n if (fannedToAny && this.#terminalPauseSeq !== undefined) {\n const eventSeq =\n typeof message.seq === \"number\" ? message.seq : undefined;\n const terminalSeq = this.#terminalPauseSeq;\n if (\n terminalSeq === null ||\n eventSeq == null ||\n eventSeq > terminalSeq\n ) {\n if (this.#terminalPauseTimer != null) {\n clearTimeout(this.#terminalPauseTimer);\n this.#terminalPauseTimer = undefined;\n }\n for (const [id, subscription] of this.#subscriptions) {\n if (id !== this.#lifecycleSubId) {\n subscription.resume();\n }\n }\n this.#scheduleTerminalPause(\n terminalSeq === null ? undefined : terminalSeq\n );\n }\n }\n\n if (\n fannedToAny &&\n message.method === \"lifecycle\" &&\n message.params.namespace.length === 0 &&\n TERMINAL_LIFECYCLE_EVENTS.has(message.params.data.event)\n ) {\n const shouldSkipPause =\n message.params.data.event === \"interrupted\" &&\n this.#headlessInterruptsAwaitingTerminal.size > 0;\n if (shouldSkipPause) {\n this.#headlessInterruptsAwaitingTerminal.clear();\n return;\n }\n // A single shared stream delivers every subscription's events,\n // so a terminal event applies to all currently active\n // non-lifecycle subscriptions. Defer the pause one macrotask:\n // transformer `finalize()` hooks can emit trailing custom events\n // immediately after root lifecycle completion, and pausing\n // synchronously would buffer those same-run events until the\n // next submit resumes subscriptions.\n this.#scheduleTerminalPause(\n typeof message.seq === \"number\" ? message.seq : undefined\n );\n }\n return;\n }\n\n const messageId = typeof message.id === \"number\" ? message.id : undefined;\n const pending =\n messageId === undefined ? undefined : this.#pending.get(messageId);\n if (!pending) {\n if (message.type === \"error\" && message.id == null) {\n this.#fireOnError(new ProtocolError(message));\n }\n return;\n }\n if (messageId !== undefined) {\n this.#pending.delete(messageId);\n }\n if (message.type === \"error\") {\n pending.reject(new ProtocolError(message));\n return;\n }\n if (typeof message.meta?.applied_through_seq === \"number\") {\n this.ordering.lastAppliedThroughSeq = message.meta.applied_through_seq;\n }\n pending.resolve(message);\n }\n\n async #send<TMethod extends keyof CommandResultMap>(\n method: TMethod,\n params: CommandParamsMap[TMethod]\n ): Promise<CommandResultMap[TMethod]> {\n await this.#ensureOpen();\n const id = this.#nextCommandId++;\n const command = {\n id,\n method,\n params,\n } as Command;\n const responsePromise = new Promise<CommandResponse>((resolve, reject) => {\n this.#pending.set(id, { resolve, reject });\n });\n let immediate: Awaited<ReturnType<TransportAdapter[\"send\"]>>;\n try {\n immediate = await this.#transportAdapter.send(command);\n } catch (error) {\n this.#pending.delete(id);\n throw error;\n }\n if (immediate) {\n this.#pending.delete(id);\n if (immediate.type === \"error\") {\n throw new ProtocolError(immediate);\n }\n if (typeof immediate.meta?.applied_through_seq === \"number\") {\n this.ordering.lastAppliedThroughSeq =\n immediate.meta.applied_through_seq;\n }\n return immediate.result as CommandResultMap[TMethod];\n }\n const response = await responsePromise;\n return response.result as CommandResultMap[TMethod];\n }\n}\n\nexport {\n MessageAssembler,\n StreamingMessageAssembler,\n StreamingMessage,\n} from \"./messages.js\";\nexport type { AssembledMessage, MessageAssemblyUpdate } from \"./messages.js\";\nexport {\n ToolCallAssembler,\n toClientAssembledToolCall,\n SubgraphDiscoveryHandle,\n SubgraphHandle,\n SubagentHandle,\n SubagentDiscoveryHandle,\n} from \"./handles/index.js\";\nexport type {\n ClientAssembledToolCall,\n ClientAssembledToolCall as AssembledToolCall,\n ToolCallStatus,\n Subscribable,\n} from \"./handles/index.js\";\nexport { inferChannel, matchesSubscription } from \"./subscription.js\";\nexport type { TransportAdapter, AgentServerAdapter } from \"./transport.js\";\nexport type * from \"./types.js\";\nexport { ProtocolError, MaxWebSocketReconnectAttemptsError } from \"./error.js\";\nexport { MediaAssembler, MediaAssemblyError } from \"./media.js\";\nexport type {\n AnyMediaHandle,\n AudioMedia,\n FileMedia,\n ImageMedia,\n MediaAssemblerCallbacks,\n MediaAssemblerOptions,\n MediaAssemblyErrorKind,\n MediaBase,\n MediaBlockType,\n VideoMedia,\n} from \"./media.js\";\n"],"mappings":"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"}