@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
1 lines • 154 kB
Source Map (JSON)
{"version":3,"file":"controller.cjs","names":["#options","#messagesKey","#subagents","SubagentDiscovery","#subgraphs","SubgraphDiscovery","#messageMetadata","MessageMetadataTracker","#resolvedInterrupts","#selfCreatedThreadIds","#missingThreadIds","#namespaceResolves","#scopedHistorySeeds","#rootEventListeners","#rootBus","#heldLifecycleReleases","ToolCallAssembler","#threadListeners","#currentThreadId","#trySeedProjectionFromHistory","ChannelRegistry","StreamStore","#createInitialSnapshot","#rootMessages","RootMessageProjection","#lifecycleLoading","LifecycleLoadingTracker","#disposed","#submitter","#submittedRunMatch","EMPTY_QUEUE","SubmitCoordinator","#ensureThread","#startDeferredRootPump","#abandonDeferredRootPump","#rootPumpReady","#awaitNextTerminal","#awaitResumedRunTerminal","#submitGeneration","#interruptCommandPending","#hydratedActiveInterruptIds","#pendingInterruptEvents","#pendingHydrationInterruptEvents","#markLocalRunStart","#submittedRunId","#submittedRunIdPending","#advanceInterruptReplayBarrier","#notifyCreated","#notifyCompleted","#markLocalRunEnd","#beginOptimistic","#settleOptimistic","#hydrationPromise","#createHydrationPromise","#resolveHydration","#rejectHydration","#fetchHydrationState","#discoverySeedPromise","#resetHydrationPromise","#teardownThread","#hydratedCheckpointTime","#applyValues","seedToolCallsFromMessages","ensureMessageInstances","upsertToolCall","#interruptReplayThroughSeq","#seedDiscoveryFromHistory","getHistoryPage","#primeScopedHistorySeedsFromHistory","collectSubgraphHostNamespaces","mapSubagentNamespaces","resolveSubagentNamespaces","#rootPumpDeferred","#skipDefaultSubagentProjection","#getScopedHistorySeed","namespaceKey","#activeRunId","#localRunDepth","#runLifecycleListener","isRootNamespace","#thread","#resolveNamespaceForInterruptId","#resolveInterruptForResume","#resolveDispatchUpdate","normalizeHitlResponseForServer","#markInterruptResolvedInRootStore","#discardPendingInterruptEvents","#cancelPendingDispose","#pendingDisposeTimer","#rootPump","#startRootPump","#notifyThreadListeners","#rootPumpGeneration","#threadEventUnsubscribe","#threadErrorUnsubscribe","#rootSubscription","#rootToolAssembler","#onWildcardEvent","#usesEventStreamTransport","#onRootEvent","#recordInterrupt","#settleParkedInterruptsOnTerminal","isInternalWorkNamespace","isLegacySubagentNamespace","prepareOptimisticInput","#sawValuesForRun","serializeUpdateMessages","reconcileToolCallsFromMessages","normalizeInterruptForClient","#reconcilePendingInterruptsFromServer","#settleParkedInterrupts","#settleParkedInterruptsPromise","#awaitRootTerminal","resolveInterruptTargetForHeadlessResume","DEFAULT_MESSAGES_KEY"],"sources":["../../src/stream/controller.ts"],"sourcesContent":["/**\n * Framework-agnostic controller for the experimental v2 stream.\n *\n * Responsibilities:\n * - Owns at most one {@link ThreadStream} at a time (swapped on\n * `hydrate(newThreadId)` or `dispose`).\n * - Exposes three always-on observable surfaces via {@link StreamStore}:\n * - `rootStore` : root values/messages/toolCalls/interrupts/…\n * - `subagentStore` : discovery map of subagents (no content)\n * - `subgraphStore` : discovery map of subgraphs (no content)\n * - Owns a {@link ChannelRegistry} that framework selector hooks\n * (`useMessages`, `useToolCalls`, `useExtension`, `useChannel`)\n * use to lazily open per-namespace subscriptions.\n * - Imperative run surface: `submit`, `stop`, `respond`, `joinStream`.\n *\n * A single multi-channel subscription (`values`, `lifecycle`, `input`,\n * `messages`, `tools`) powers every always-on projection and both\n * discovery runners. Selector hooks add their own (deduped)\n * subscriptions on top — so even a UI with many subagents only opens\n * one extra subscription per `(channels, namespace)` actually\n * rendered on screen.\n */\nimport { v7 as uuidv7 } from \"@langchain/core/utils/uuid\";\nimport { AIMessage, type BaseMessage } from \"@langchain/core/messages\";\nimport type {\n Channel,\n Event,\n LifecycleEvent,\n MessagesEvent,\n ToolsEvent,\n ValuesEvent,\n} from \"@langchain/protocol\";\nimport type { Interrupt, ThreadState } from \"../schema.js\";\nimport type { ThreadStream } from \"../client/stream/index.js\";\nimport type { SubscriptionHandle } from \"../client/stream/index.js\";\nimport { ToolCallAssembler } from \"../client/stream/handles/tools.js\";\nimport type { AssembledToolCall } from \"../client/stream/handles/tools.js\";\nimport { normalizeInterruptForClient } from \"../ui/interrupts.js\";\nimport { normalizeHitlResponseForServer } from \"../ui/hitl-interrupt-payload.js\";\nimport type { Message } from \"../types.messages.js\";\nimport { NAMESPACE_SEPARATOR, DEFAULT_MESSAGES_KEY } from \"./constants.js\";\nimport { StreamStore } from \"./store.js\";\nimport { ChannelRegistry } from \"./channel-registry.js\";\nimport { ensureMessageInstances } from \"./message-coercion.js\";\nimport {\n SubagentDiscovery,\n type SubagentMap,\n SubgraphDiscovery,\n type SubgraphMap,\n type SubgraphByNodeMap,\n} from \"./discovery/index.js\";\nimport {\n collectSubgraphHostNamespaces,\n getHistoryPage,\n mapSubagentNamespaces,\n resolveSubagentNamespaces,\n} from \"./discovery/namespace-from-history.js\";\nimport type { SubagentDiscoverySnapshot } from \"./types.js\";\nimport {\n isInternalWorkNamespace,\n isLegacySubagentNamespace,\n isRootNamespace,\n namespaceKey,\n} from \"./namespace.js\";\nimport {\n MessageMetadataTracker,\n type CheckpointEnvelope,\n type MessageMetadata,\n type MessageMetadataMap,\n} from \"./message-metadata-tracker.js\";\nimport { LifecycleLoadingTracker } from \"./lifecycle-loading-tracker.js\";\nimport { RootMessageProjection } from \"./root-message-projection.js\";\nimport {\n prepareOptimisticInput,\n serializeUpdateMessages,\n type OptimisticHandle,\n} from \"./optimistic-input.js\";\nimport {\n EMPTY_QUEUE,\n SubmitCoordinator,\n type SubmissionQueueEntry,\n type SubmissionQueueSnapshot,\n} from \"./submit-coordinator.js\";\nimport {\n reconcileToolCallsFromMessages,\n seedToolCallsFromMessages,\n upsertToolCall,\n} from \"./tool-calls.js\";\nimport { resolveInterruptTargetForHeadlessResume } from \"../headless-tools.js\";\nimport type {\n RootEventBus,\n RootSnapshot,\n RunExecutionReason,\n StreamControllerOptions,\n StreamRespondAllOptions,\n StreamRespondOptions,\n StreamStopOptions,\n StreamSubmitOptions,\n} from \"./types.js\";\n\nfunction isAbortLikeError(error: unknown): boolean {\n if (error == null || typeof error !== \"object\") return false;\n const maybeError = error as { name?: unknown; message?: unknown };\n return (\n maybeError.name === \"AbortError\" ||\n (typeof maybeError.message === \"string\" &&\n maybeError.message.includes(\"aborted\"))\n );\n}\n\nfunction lifecycleReason(event: string | undefined): RunExecutionReason | null {\n if (event === \"completed\") return \"success\";\n if (event === \"failed\") return \"error\";\n if (event === \"interrupted\") return \"interrupt\";\n return null;\n}\n\ninterface ScopedHistorySeed {\n readonly messages: BaseMessage[];\n readonly toolCalls: AssembledToolCall[];\n}\n\n/**\n * Decide whether a hydrated thread is *active* (a run is executing or\n * paused awaiting resume) from the `getState()` snapshot alone — no\n * extra request.\n *\n * Why this gate exists: a finished thread does not need either of the\n * always-on SSE pumps. Subagent/subgraph cards are already seeded from\n * the `getState()` messages and a single bounded `getHistory()` page, so\n * opening the depth-1 content pump + the wildcard lifecycle watcher only\n * to replay a completed run and then idle forever is pure waste. We open\n * the pumps eagerly only when the thread is active; otherwise they come\n * up on the first local `submit()` (the existing deferred-pump path) or\n * a thread swap that lands on an active thread.\n *\n * The gate is deliberately conservative: we only conclude *idle* when\n * the state proves it. A thread is treated as active unless `next` is a\n * present, empty array AND no task carries a pending interrupt:\n * - `next` missing / not an array: unknown shape (a server or custom\n * client may omit it). Treat as active so an already-running\n * server-side run is still observed on reconnect — never silently\n * disable streaming on an unfamiliar `getState` shape.\n * - `next.length > 0`: the checkpoint still has nodes to execute, i.e.\n * a run is mid-flight or paused at an interrupt.\n * - `next` is `[]` but a `tasks[].interrupts` is non-empty: the thread\n * is interrupted and a resume (which starts a run) must be observable.\n * - `next` is `[]` and no pending interrupts: a completed run → idle.\n */\nfunction isThreadStateActive(\n state: { next?: unknown; tasks?: unknown } | null | undefined\n): boolean {\n if (state == null) return true;\n // Only a present, empty `next` array proves \"no nodes pending\". A\n // missing/non-array `next` is an unknown shape → assume active.\n if (!Array.isArray(state.next)) return true;\n if (state.next.length > 0) return true;\n if (Array.isArray(state.tasks)) {\n for (const task of state.tasks) {\n const interrupts = (task as { interrupts?: unknown } | null)?.interrupts;\n if (Array.isArray(interrupts) && interrupts.length > 0) return true;\n }\n }\n return false;\n}\n\nconst ROOT_NAMESPACE: readonly string[] = [];\n\n/**\n * Channel set covered by the always-on root subscription. Exported so\n * projections (and transports) can reason about what the root pump\n * already delivers before opening additional server subscriptions.\n */\nexport const ROOT_PUMP_CHANNELS: readonly Channel[] = [\n \"values\",\n \"checkpoints\",\n \"lifecycle\",\n \"input\",\n \"messages\",\n \"tools\",\n];\n\n// The server writes an interrupt into thread state shortly after it streams\n// the `input.requested` event, so a state fetch on the terminal lifecycle can\n// miss it; mirrors the server's own interrupt settle window.\nconst PARKED_INTERRUPT_SETTLE_MS = 5_000;\nconst PARKED_INTERRUPT_SETTLE_POLL_MS = 500;\n\ninterface ResolvedInterrupt {\n interruptId: string;\n namespace: string[];\n}\n\nexport type {\n MessageMetadata,\n MessageMetadataMap,\n SubmissionQueueEntry,\n SubmissionQueueSnapshot,\n};\n\n/**\n * Coordinates one thread's protocol-v2 stream and exposes stable\n * observable projections for framework bindings.\n *\n * The controller owns the root subscription, lazily binds scoped\n * projections through {@link ChannelRegistry}, and normalizes protocol\n * events into class-message, tool-call, discovery, interrupt, and queue\n * stores.\n *\n * @typeParam StateType - Shape of the graph state exposed on `values`.\n * @typeParam InterruptType - Shape of protocol interrupt payloads.\n * @typeParam ConfigurableType - Shape of `config.configurable` accepted by submit.\n */\nexport class StreamController<\n StateType extends object = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n> {\n readonly rootStore: StreamStore<RootSnapshot<StateType, InterruptType>>;\n readonly subagentStore: StreamStore<SubagentMap>;\n readonly subgraphStore: StreamStore<SubgraphMap>;\n readonly subgraphByNodeStore: StreamStore<SubgraphByNodeMap>;\n readonly messageMetadataStore: StreamStore<MessageMetadataMap>;\n readonly queueStore: StreamStore<SubmissionQueueSnapshot<StateType>>;\n readonly registry: ChannelRegistry;\n\n readonly #options: StreamControllerOptions<StateType>;\n readonly #messagesKey: string;\n readonly #subagents = new SubagentDiscovery();\n readonly #subgraphs = new SubgraphDiscovery();\n readonly #messageMetadata = new MessageMetadataTracker();\n\n #thread: ThreadStream | undefined;\n #currentThreadId: string | null;\n #rootSubscription: SubscriptionHandle<Event> | undefined;\n #rootPump: Promise<void> | undefined;\n #rootPumpReady: Promise<void> | undefined;\n /**\n * `true` while a self-created thread has its root pump deferred until\n * the first `submitRun` / `respondInput` commits the thread row\n * server-side. See `#ensureThread` and `#startDeferredRootPump`.\n */\n #rootPumpDeferred = false;\n #threadEventUnsubscribe: (() => void) | undefined;\n #threadErrorUnsubscribe: (() => void) | undefined;\n #disposed = false;\n #pendingDisposeTimer: ReturnType<typeof setTimeout> | null = null;\n /**\n * Interrupt ids this controller has locally marked resolved via\n * {@link respond} / {@link respondAll}. Used only to suppress\n * *historical* SSE replay of those `input.requested` events (there\n * is no `input.responded` protocol event). A live event after the\n * resume barrier clears an id from this set so an interrupt raised\n * again by a later run can reappear on `rootStore.interrupts`.\n */\n readonly #resolvedInterrupts = new Set<string>();\n /**\n * Set of interrupt IDs the server reports as currently *active* on\n * the thread (from `state.tasks[].interrupts`). Populated during\n * {@link hydrate} from `client.threads.getState()` and used as a\n * strict allowlist when processing replayed `input.requested`\n * events from the persistent SSE subscription. Without this guard,\n * SSE replay re-adds historically-requested interrupts that have\n * since been resolved (no `input.responded` event exists in the\n * protocol, so the SDK has no other way to tell replay from live\n * for an idle thread). After a command is accepted, events newer\n * than {@link #interruptReplayThroughSeq} bypass the allowlist.\n */\n #hydratedActiveInterruptIds: Set<string> | null = null;\n /**\n * Creation time of the checkpoint the latest {@link hydrate} seeded\n * from. A new stream subscription replays the thread's retained\n * history, and events produced before this moment are already part of\n * the seed: applying them again rewinds `messages`, `values` and\n * `toolCalls` to older turns and then rebuilds them.\n */\n #hydratedCheckpointTime: number | undefined;\n /**\n * Highest event sequence already applied when the latest run command\n * was accepted. Interrupts outside the hydrate-time allowlist remain\n * filtered through this sequence, while newer events are live output\n * from the newly-started run and must be accepted.\n */\n #interruptReplayThroughSeq: number | undefined;\n /** Unknown inputs waiting to be classified as live or replayed history. */\n #pendingHydrationInterruptEvents: Event[] = [];\n #settleParkedInterruptsPromise: Promise<void> | undefined;\n /**\n * Unknown interrupt events received between local command dispatch and its\n * response. The response supplies the sequence barrier needed to classify\n * each event as historical replay or live output from the new run.\n */\n #pendingInterruptEvents: Event[] = [];\n #interruptCommandPending = false;\n /**\n * Monotonic counter bumped at the start of each `submit()` and used\n * by {@link hydrate} to skip its post-fetch allowlist write when a\n * submit started while the state fetch was in flight. Without this\n * guard, a submit-then-hydrate race could re-install a stale\n * allowlist that filters out genuinely-new live interrupts emitted\n * by the just-started run.\n */\n #submitGeneration = 0;\n /**\n * Monotonic counter bumped at the start of each `#teardownThread`.\n * The root pump captures the generation when it starts and drops\n * any event whose generation no longer matches — including queued\n * events that `SubscriptionHandle.close()` still drains after the\n * snapshot has already been cleared by `hydrate()`.\n */\n #rootPumpGeneration = 0;\n /**\n * Thread ids this controller minted client-side on first `submit()`.\n * `hydrate()` skips `threads.getState()` for these — we know there\n * is nothing checkpointed yet. Cleared once dispatch commits the\n * thread server-side.\n */\n readonly #selfCreatedThreadIds = new Set<string>();\n /**\n * Caller-supplied thread ids that 404'd on hydrate. Unlike\n * {@link #selfCreatedThreadIds}, these are revalidated on every\n * hydrate: another client may create the same id between visits.\n * While marked missing, `submit()` still defers the root SSE pump\n * until `run.start` / `commands` commits the row — joining\n * `/stream/events` beforehand leaves a dead subscription on\n * langgraph_api's in-mem runtime.\n */\n readonly #missingThreadIds = new Set<string>();\n /**\n * In-flight per-subagent namespace resolutions, keyed by tool-call\n * id. De-dupes concurrent {@link resolveSubagentNamespace} calls so\n * re-renders / multiple consumers of the same subagent don't issue\n * parallel `getHistory` walks.\n */\n readonly #namespaceResolves = new Map<string, Promise<void>>();\n /**\n * In-flight hydrate-time discovery seed ({@link #seedDiscoveryFromHistory}):\n * a single bounded `getHistory` page that bulk-promotes every\n * still-default subagent namespace and seeds subgraph hosts. Per-card\n * {@link resolveSubagentNamespace} calls await this shared promise\n * instead of each firing their own `getHistory` walk, so opening N\n * cards right after reconnect costs one history read, not N. Re-armed\n * per hydrate cycle and cleared once it settles.\n */\n #discoverySeedPromise: Promise<void> | undefined;\n readonly #scopedHistorySeeds = new Map<\n string,\n Promise<ScopedHistorySeed | null>\n >();\n readonly #rootEventListeners = new Set<(event: Event) => void>();\n readonly #rootBus: RootEventBus;\n #activeRunId: string | undefined;\n /**\n * Run id `run.start` returned for the in-flight local `submit()`. Kept\n * apart from {@link #activeRunId}, which a rolled-back submit's late\n * response can still overwrite.\n */\n #submittedRunId: string | undefined;\n /** `true` from a local run's dispatch until its `run.start` answers. */\n #submittedRunIdPending = false;\n /** One per armed terminal wait: re-runs the lifecycle events it held until `run.start` answered. */\n readonly #heldLifecycleReleases = new Set<() => void>();\n #localRunDepth = 0;\n /**\n * `true` once a root `values` event has been applied for the current\n * optimistic run. Reset to `false` in {@link #beginOptimistic} and\n * read in {@link #settleOptimistic}: when a run terminates without\n * the server ever echoing a `values` snapshot, optimistically-merged\n * non-message keys are rolled back to their pre-submit values.\n */\n #sawValuesForRun = false;\n\n /**\n * Single-shot hydration promise. Exposed via `hydrationPromise`\n * so Suspense wrappers can throw it until the first hydrate\n * completes (resolve) or fails (reject). Reset whenever a new\n * hydrate cycle begins so `<Suspense>` boundaries re-suspend on\n * thread switch.\n */\n #hydrationPromise: Promise<void>;\n #resolveHydration!: () => void;\n #rejectHydration!: (error: unknown) => void;\n\n /**\n * Tool assembler lives for the lifetime of a thread; reset on\n * rebind so a fresh thread starts with a clean slate.\n */\n #rootToolAssembler = new ToolCallAssembler();\n #rootMessages!: RootMessageProjection<StateType, InterruptType>;\n #lifecycleLoading!: LifecycleLoadingTracker<\n RootSnapshot<StateType, InterruptType>\n >;\n #submitter!: SubmitCoordinator<StateType, InterruptType, ConfigurableType>;\n\n readonly #threadListeners = new Set<\n (thread: ThreadStream | undefined) => void\n >();\n\n /**\n * Create a controller around a LangGraph client and optional initial thread.\n *\n * @param options - Runtime configuration, client, thread id, and initial state.\n */\n constructor(options: StreamControllerOptions<StateType>) {\n this.#options = options;\n this.#messagesKey = options.messagesKey ?? DEFAULT_MESSAGES_KEY;\n this.#currentThreadId = options.threadId ?? null;\n this.#rootBus = {\n channels: ROOT_PUMP_CHANNELS,\n subscribe: (listener) => {\n this.#rootEventListeners.add(listener);\n return () => {\n this.#rootEventListeners.delete(listener);\n };\n },\n trySeedFromHistory: (params) =>\n this.#trySeedProjectionFromHistory(params),\n };\n this.registry = new ChannelRegistry(this.#rootBus);\n this.subagentStore = this.#subagents.store;\n this.subgraphStore = this.#subgraphs.store;\n this.subgraphByNodeStore = this.#subgraphs.byNodeStore;\n this.rootStore = new StreamStore<RootSnapshot<StateType, InterruptType>>(\n this.#createInitialSnapshot()\n );\n this.#rootMessages = new RootMessageProjection({\n messagesKey: this.#messagesKey,\n store: this.rootStore,\n });\n this.#lifecycleLoading = new LifecycleLoadingTracker({\n store: this.rootStore,\n isDisposed: () => this.#disposed,\n // `#submitter` is assigned just below; this callback only ever\n // fires later (async), by which point construction has finished.\n onSettled: () => this.#submitter.scheduleQueueDrainOnObservedIdle(),\n // `submit()` settles `isLoading` itself, so skipping a pending\n // event here can't leave the flag stuck.\n ignore: (event) => this.#submittedRunMatch(event) != null,\n });\n this.messageMetadataStore = this.#messageMetadata.store;\n this.queueStore = new StreamStore<SubmissionQueueSnapshot<StateType>>(\n EMPTY_QUEUE as SubmissionQueueSnapshot<StateType>\n );\n this.#submitter = new SubmitCoordinator({\n options: this.#options,\n rootStore: this.rootStore,\n queueStore: this.queueStore,\n getDisposed: () => this.#disposed,\n getCurrentThreadId: () => this.#currentThreadId,\n setCurrentThreadId: (threadId) => {\n this.#currentThreadId = threadId;\n },\n rememberSelfCreatedThreadId: (threadId) => {\n this.#selfCreatedThreadIds.add(threadId);\n },\n isSelfCreatedThreadId: (threadId) =>\n this.#selfCreatedThreadIds.has(threadId) ||\n this.#missingThreadIds.has(threadId),\n hydrate: (threadId) => this.hydrate(threadId),\n ensureThread: (threadId, deferRootPump) =>\n this.#ensureThread(threadId, deferRootPump),\n startDeferredRootPump: () => this.#startDeferredRootPump(),\n abandonDeferredRootPump: () => this.#abandonDeferredRootPump(),\n forgetSelfCreatedThreadId: (threadId) => {\n this.#selfCreatedThreadIds.delete(threadId);\n this.#missingThreadIds.delete(threadId);\n },\n waitForRootPumpReady: () => this.#rootPumpReady,\n awaitNextTerminal: (signal) => this.#awaitNextTerminal(signal),\n awaitResumedRunTerminal: (signal) =>\n this.#awaitResumedRunTerminal(signal),\n onSubmitStart: () => {\n // Bump the generation so any in-flight hydrate skips its\n // allowlist write on return. Keep an existing allowlist until\n // dispatch is accepted: the root pump may still be replaying\n // historical events while the command is in flight.\n this.#submitGeneration += 1;\n this.#interruptCommandPending =\n this.#hydratedActiveInterruptIds != null;\n this.#pendingInterruptEvents = this.#pendingHydrationInterruptEvents;\n this.#pendingHydrationInterruptEvents = [];\n },\n onRunStart: () => this.#markLocalRunStart(),\n onRunStartReturned: (runId) => {\n this.#submittedRunId = runId;\n this.#submittedRunIdPending = false;\n for (const release of [...this.#heldLifecycleReleases]) release();\n },\n onRunCreated: (runId) => {\n this.#advanceInterruptReplayBarrier();\n this.#notifyCreated(runId);\n },\n onRunCompleted: (reason, runId) => this.#notifyCompleted(reason, runId),\n onRunEnd: () => {\n // Stop buffering new events, but keep any already-queued\n // `input.requested` frames. A fast run can emit its interrupt\n // and terminal before `run.start` returns; `onRunCreated` still\n // has to classify those frames against `applied_through_seq`.\n this.#interruptCommandPending = false;\n this.#markLocalRunEnd();\n },\n beginOptimistic: (input) => this.#beginOptimistic(input),\n settleOptimistic: (handle, event) =>\n this.#settleOptimistic(handle, event),\n });\n this.#hydrationPromise = this.#createHydrationPromise();\n /**\n * Attach a default no-op catch so orphaned hydrationPromise\n * rejections (e.g. controllers spawned during Suspense retries\n * whose promise never gets subscribed to because the suspense\n * cache already holds an earlier one) don't surface as unhandled\n * rejections. Callers that attach their own handlers via .then()\n * still receive the rejection on their derived promise.\n */\n this.#hydrationPromise.catch(() => undefined);\n /**\n * Kick off the initial hydrate eagerly when a caller-supplied\n * thread id is present. Suspense consumers throw\n * `hydrationPromise` on the very first render, which unmounts the\n * subtree before any `useEffect` can run — so if we waited for an\n * effect to drive the hydrate we'd deadlock. Firing here makes\n * the promise settle independently of the component lifecycle.\n */\n if (this.#currentThreadId != null) {\n void this.hydrate(this.#currentThreadId);\n } else {\n this.#resolveHydration();\n }\n }\n\n /**\n * Promise that settles the first time {@link hydrate} finishes on\n * the current thread. Resolves on a clean hydration, rejects when\n * the thread-state fetch errors. A fresh promise is installed on\n * every thread swap so `<Suspense>` wrappers re-suspend on\n * `switchThread`.\n */\n get hydrationPromise(): Promise<void> {\n return this.#hydrationPromise;\n }\n\n /**\n * Create the deferred promise backing the current hydration cycle.\n */\n #createHydrationPromise(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.#resolveHydration = resolve;\n this.#rejectHydration = reject;\n });\n }\n\n /**\n * Replace the current hydration promise before a thread swap.\n */\n #resetHydrationPromise(): void {\n /**\n * Swallow rejection on the orphaned promise so Node doesn't\n * flag it as unhandled; Suspense callers that still hold a\n * reference see the rejection they subscribed to.\n */\n this.#hydrationPromise.catch(() => undefined);\n this.#hydrationPromise = this.#createHydrationPromise();\n }\n\n // ---------- public imperatives ----------\n\n /**\n * Load thread state for hydration, preferring the active custom\n * adapter's `getState()` when present.\n */\n async #fetchHydrationState(): Promise<ThreadState<StateType> | null> {\n const threadId = this.#currentThreadId;\n if (threadId == null) return null;\n\n const transport = this.#options.transport;\n if (\n transport != null &&\n typeof transport === \"object\" &&\n typeof transport.getState === \"function\"\n ) {\n return (await transport.getState<StateType>()) as ThreadState<StateType> | null;\n }\n\n return this.#options.client.threads.getState<StateType>(threadId);\n }\n\n /**\n * Fetch the checkpointed thread state and seed the root snapshot.\n * Re-calling with a different `threadId` swaps the underlying\n * {@link ThreadStream}, rewires the registry to the new thread, and\n * resets assemblers.\n *\n * @param threadId - Optional replacement thread id; `null` clears the active thread.\n */\n async hydrate(threadId?: string | null): Promise<void> {\n if (this.#disposed) return;\n const target = threadId === undefined ? this.#currentThreadId : threadId;\n const changed = target !== this.#currentThreadId;\n this.#currentThreadId = target ?? null;\n // Re-arm per hydrate cycle: a stale seed from a previous thread must\n // not be awaited by this thread's lazy namespace resolves.\n this.#discoverySeedPromise = undefined;\n this.#scopedHistorySeeds.clear();\n this.rootStore.setState((s) => ({ ...s, threadId: this.#currentThreadId }));\n\n if (changed) {\n /**\n * Swap to a new thread: re-arm the hydration promise so any\n * Suspense boundary remounted against the new id suspends again.\n */\n this.#resetHydrationPromise();\n /**\n * Kick teardown so the synchronous abort (unbind, drop onEvent,\n * close the root subscription, reset assemblers) runs before we\n * touch the snapshot. Then reset immediately so the UI does not\n * wait on pump/close. An interrupted thread parks the root pump\n * on `waitForResume()`; awaiting teardown *before* this reset\n * left `threadId` null while `messages` still showed the previous\n * conversation (`useStream` fire-and-forgets `hydrate()`).\n */\n const teardown = this.#teardownThread();\n this.rootStore.setState(() => ({\n ...this.#createInitialSnapshot(),\n threadId: this.#currentThreadId,\n }));\n /**\n * Drop queued submissions — they were targeted at the previous\n * thread so dispatching them against the new thread would be\n * surprising. Mirrors the legacy `StreamOrchestrator` behaviour.\n */\n this.queueStore.setState(\n () => EMPTY_QUEUE as SubmissionQueueSnapshot<StateType>\n );\n await teardown;\n }\n\n if (this.#currentThreadId == null) {\n this.rootStore.setState((s) => ({ ...s, isThreadLoading: false }));\n this.#resolveHydration();\n return;\n }\n\n /**\n * Self-generated thread ids have nothing to fetch server-side yet\n * — the thread is created lazily by the first `run.start`. Calling\n * `threads.getState()` here would return a 404 and surface a\n * spurious error to the UI.\n */\n if (this.#selfCreatedThreadIds.has(this.#currentThreadId)) {\n this.rootStore.setState((s) => ({ ...s, isThreadLoading: false }));\n this.#resolveHydration();\n return;\n }\n\n this.rootStore.setState((s) => ({ ...s, isThreadLoading: true }));\n // Thread id this hydrate cycle is fetching for; used to detect a thread\n // clear/swap across the getState() await below.\n const hydratedThreadId = this.#currentThreadId;\n let hydrationError: unknown;\n let threadExists = false;\n // True only when getState 404s — the id is bound in the client but\n // the server row doesn't exist yet. A null state payload is\n // different (thread may exist with nothing to seed) and still\n // opens the pump below. Distinct from `hydrationError` so a\n // transport failure still takes the eager pump path.\n let threadMissing = false;\n // Default active so a getState error / non-404 failure never\n // silently disables streaming — the pumps open eagerly as before.\n // Flipped to the real signal once we have the state in hand.\n let threadActive = true;\n // Set below from `state.tasks[].interrupts`, if present. Combined\n // with `threadActive` where it's used, to decide whether to seed\n // `isLoading`.\n let hasActiveInterrupts = false;\n try {\n const state = await this.#fetchHydrationState();\n // The await above yields. If the thread id changed or was cleared while\n // we were suspended (host cleared it, hydrate(null), or the component\n // unmounted during navigation), this hydrate is stale: applying its\n // fetched state would repopulate rootStore for a thread we've left, and\n // the reconnect below would call threads.stream(null, …) → `.fetch` on\n // null. Bail before touching any state. Hydration is settled in finally.\n if (this.#disposed || this.#currentThreadId !== hydratedThreadId) return;\n threadExists = state != null;\n threadActive = isThreadStateActive(state);\n const checkpointTime = Date.parse(state?.created_at ?? \"\");\n this.#hydratedCheckpointTime = Number.isNaN(checkpointTime)\n ? undefined\n : checkpointTime;\n // A prior hydrate-404 may have marked this id missing; clear it\n // now that the server row exists (e.g. another client created it).\n this.#missingThreadIds.delete(hydratedThreadId);\n if (state?.values != null) {\n /**\n * `threads.getState()` returns the legacy `ThreadState` shape\n * where `parent_checkpoint` is an object (`{ thread_id,\n * checkpoint_id, checkpoint_ns }`). Synthesize the v2\n * `Checkpoint` envelope (matching the `checkpoints` channel\n * payload) so hydrated messages also get their\n * `parentCheckpointId` populated for fork / edit flows.\n */\n const checkpointId = state.checkpoint?.checkpoint_id;\n const parentCheckpointId =\n state.parent_checkpoint?.checkpoint_id ?? undefined;\n /**\n * Carry the checkpoint `step` from `getState()` metadata so the\n * root message projection treats this seed as the authoritative\n * latest superstep. The content pump's reconnect replay emits\n * older checkpoints (lower step); marking the seed's step lets\n * the projection reject those as stale instead of letting them\n * remove the seeded message tail (the final assistant turn).\n */\n const seedStep = (state.metadata as { step?: unknown } | undefined)\n ?.step;\n const syntheticCheckpoint =\n typeof checkpointId === \"string\"\n ? {\n id: checkpointId,\n ...(parentCheckpointId != null\n ? { parent_id: parentCheckpointId }\n : {}),\n ...(typeof seedStep === \"number\" ? { step: seedStep } : {}),\n }\n : undefined;\n this.#applyValues(state.values as unknown, syntheticCheckpoint);\n\n /**\n * Seed subagent discovery from checkpoint messages so deep-agent\n * cards render on refresh without waiting for SSE replay. Zero\n * extra HTTP (reuses the `getState` payload); mirrors the\n * interrupt-seeding below. `#subagents` was cleared in\n * `#teardownThread`, and `seedFromCheckpointMessages` is\n * idempotent, so this is safe on re-hydrate.\n */\n const seedMessages = (state.values as Record<string, unknown>)[\n this.#messagesKey\n ];\n if (Array.isArray(seedMessages)) {\n this.#subagents.seedFromCheckpointMessages(seedMessages);\n\n // Root `toolCalls` are otherwise only built from `tools` events,\n // and the replayed ones predate the seed and are skipped. A call\n // with no result yet is left to the live stream, as an open tab\n // would only show it once it starts.\n const finishedToolCalls = seedToolCallsFromMessages(\n ROOT_NAMESPACE,\n ensureMessageInstances(seedMessages as (Message | BaseMessage)[])\n ).filter((toolCall) => toolCall.status === \"finished\");\n if (finishedToolCalls.length > 0) {\n this.rootStore.setState((s) => ({\n ...s,\n toolCalls: finishedToolCalls.reduce(\n (toolCalls, toolCall) => upsertToolCall(toolCalls, toolCall),\n s.toolCalls\n ),\n }));\n }\n\n /**\n * An idle (finished) thread defers its root SSE pump; the first\n * `submit()` brings it up and the transport replays the finished\n * run from `seq=0`. Seal the seeded message ids so that replay's\n * `messages` channel deltas can't downgrade the already-complete\n * tail to empty partials (a visible \"messages replay\"). Only safe\n * for idle threads, where every seeded message is final — an\n * active thread's tail may still be streaming and must keep\n * receiving deltas. New ids from the next run are never sealed,\n * and the seal lifts once a newer checkpoint advances the\n * timeline.\n */\n if (!threadActive) {\n const sealedIds = (seedMessages as Array<{ id?: unknown }>)\n .map((message) => message?.id)\n .filter((id): id is string => typeof id === \"string\");\n if (sealedIds.length > 0) {\n this.#rootMessages.sealMessageIds(sealedIds);\n }\n }\n }\n }\n /**\n * Converge to server truth: drop any optimistic messages the\n * server state does not contain (`pending` / `failed` that were\n * never persisted — e.g. a failed run's user message). Echoed\n * ids were flipped to `\"sent\"` by `#applyValues` above and so are\n * excluded from `unpersistedOptimisticIds()`.\n */\n const unpersisted = this.#messageMetadata.unpersistedOptimisticIds();\n if (unpersisted.size > 0) {\n this.#rootMessages.dropMessages(unpersisted);\n this.#messageMetadata.forget(unpersisted);\n }\n /**\n * Sync the visible interrupt list to the server's authoritative\n * `state.tasks[].interrupts`. Without this, SSE replay of past\n * `input.requested` events would re-add resolved interrupts to\n * the UI on every page navigation back to the thread.\n *\n * Only runs when `state.tasks` is an array — runtimes that don't\n * surface tasks in `threads.getState()` are left untouched (an\n * unconditional overwrite would wipe any in-flight interrupt\n * state the wildcard watcher may already have recorded).\n */\n if (Array.isArray(state?.tasks)) {\n const generationAtFetch = this.#submitGeneration;\n const { activeInterrupts, activeIds } =\n collectActiveInterruptsFromTasks<InterruptType>(state.tasks);\n // A thread parked at an unresolved interrupt is \"active\" (the pump\n // must stay open to observe a resume) but not \"loading\" — it's\n // waiting on a human, not mid-computation.\n hasActiveInterrupts = activeInterrupts.length > 0;\n // Server still lists these as pending — drop any local\n // \"resolved\" tombstone so live replay / later reconcile can\n // keep them visible.\n for (const id of activeIds) {\n this.#resolvedInterrupts.delete(id);\n }\n this.rootStore.setState((s) => ({\n ...s,\n interrupts: activeInterrupts,\n interrupt: activeInterrupts[0],\n }));\n // Only seed the allowlist when no submit started while the\n // state fetch was in flight. If one did, leave the existing\n // filter untouched so this stale fetch cannot overwrite the\n // active run's replay boundary.\n if (this.#submitGeneration === generationAtFetch) {\n this.#hydratedActiveInterruptIds = activeIds;\n this.#interruptReplayThroughSeq = undefined;\n }\n }\n } catch (error) {\n /**\n * A 404 on hydrate means the thread does not exist server-side\n * yet (most commonly because the caller supplied a brand-new,\n * externally-minted thread id and is about to create it via the\n * first `submit()`). Treat it as \"empty state\" rather than a\n * fatal hydration error so Suspense boundaries resolve cleanly\n * and no spurious error renders in the UI.\n */\n const status = (error as { status?: number } | null)?.status;\n if (status !== 404) {\n hydrationError = error;\n this.rootStore.setState((s) => ({ ...s, error }));\n } else {\n // Caller supplied a brand-new / externally-minted thread id.\n // There is no server row yet — same lifecycle as a client-\n // minted id on first `submit()`.\n threadMissing = true;\n }\n } finally {\n this.rootStore.setState((s) => ({ ...s, isThreadLoading: false }));\n if (hydrationError != null) {\n this.#rejectHydration(hydrationError);\n } else {\n this.#resolveHydration();\n }\n }\n\n /**\n * Missing threads must not open `/stream/events`. The in-mem\n * runtime accepts the join against a not-yet-created id but the\n * subscription never attaches to the live channel — the first run\n * then delivers 0 bytes until idle reconnect. Park the pump until\n * `submit()`'s `run.start` creates the row (see\n * {@link #startDeferredRootPump}). Tracked in `#missingThreadIds`\n * (not `#selfCreatedThreadIds`) so a later hydrate revalidates —\n * another client may create the same id between visits.\n */\n if (threadMissing) {\n this.#missingThreadIds.add(hydratedThreadId);\n return;\n }\n\n /**\n * Open the shared subscription on mount so in-flight server-side\n * runs are observed even when no local `submit()` is active — BUT\n * only when the thread is actually active (see\n * {@link isThreadStateActive}). A finished thread's cards are seeded\n * from `getState()` + the bounded `getHistory()` below, so opening\n * the depth-1 content pump just to replay a completed run and idle\n * forever is pure waste. When idle we take the deferred path: the\n * pump (and watcher) come up on the first local `submit()` via\n * {@link #startDeferredRootPump}, exactly like a self-created thread.\n * The transport replays from `seq=0` on the deferred subscribe, so\n * nothing is missed.\n */\n const thread = this.#ensureThread(hydratedThreadId, !threadActive);\n\n /**\n * Picks up runs pending from before this page load, or another tab.\n * Fire-and-forget. Must run after `#ensureThread` above, not before:\n * `AgentServerQueueAdapter`'s own `getThread` callback also calls\n * `#ensureThread(threadId, true)`, which would otherwise create\n * `#thread` with the pump deferred before the line above decides it\n * should be eager.\n */\n void this.#submitter.hydrateQueue(hydratedThreadId);\n\n /**\n * Start the wildcard lifecycle watcher up-front for existing,\n * active threads. The root content pump runs at `depth: 1`, which\n * covers root-namespace and one-deep events but not arbitrarily-\n * nested subagent / subgraph lifecycle — the dedicated watcher\n * handles those.\n *\n * Skipped when:\n * - the thread is idle/finished — there are no live events to\n * watch; discovery is seeded from history below, and the watcher\n * starts with the deferred pump on the first `submit()`.\n * - the thread is self-created (new) — the watcher would 404\n * against a not-yet-existent thread; `submitRun` / `respondInput`\n * call `startLifecycleWatcher` on first submission instead.\n */\n if (threadExists && threadActive) {\n thread.startLifecycleWatcher();\n /**\n * Seed `isLoading` from the checkpoint itself, not just a live\n * lifecycle event: a subscriber that joins after a foreign run's\n * own `running` event already fired would otherwise never observe\n * it. Excludes a thread merely parked at an interrupt — that's\n * waiting on a human, not \"loading\", matching\n * `LifecycleLoadingTracker`'s own `interrupted → isLoading = false`.\n */\n if (threadActive && !hasActiveInterrupts) {\n this.rootStore.setState((s) =>\n s.isLoading ? s : { ...s, isLoading: true }\n );\n }\n }\n if (threadExists) {\n /**\n * Seed subgraph discovery and promote subagent execution\n * namespaces from a single bounded `getHistory` page. Subgraph\n * structure is not present in the root checkpoint messages\n * (unlike subagents), so it can only be reconstructed from\n * history. Fire-and-forget — not awaited into the hydration\n * promise, so Suspense / first paint stay unblocked; cards fill\n * in progressively when it resolves.\n *\n * Held in `#discoverySeedPromise` so lazy per-card\n * {@link resolveSubagentNamespace} calls coalesce onto this single\n * read instead of each firing their own `getHistory` walk.\n */\n const seed: Promise<void> = this.#seedDiscoveryFromHistory(\n this.#currentThreadId\n ).finally(() => {\n // Only clear if a later hydrate cycle hasn't re-armed it.\n if (this.#discoverySeedPromise === seed) {\n this.#discoverySeedPromise = undefined;\n }\n });\n this.#discoverySeedPromise = seed;\n }\n }\n\n /**\n * One bounded, non-blocking `getHistory` read at hydrate that seeds\n * subgraph hosts and bulk-promotes still-default subagent execution\n * namespaces. O(1) in requests regardless of subagent/subgraph count.\n */\n async #seedDiscoveryFromHistory(threadId: string): Promise<void> {\n try {\n const history = await getHistoryPage(this.#options.client, threadId, {\n limit: 20,\n });\n // A thread swap (or dispose) during the fetch invalidates this seed.\n if (this.#disposed || this.#currentThreadId !== threadId) return;\n\n this.#primeScopedHistorySeedsFromHistory(threadId, history);\n\n const hosts = collectSubgraphHostNamespaces(history);\n this.#subgraphs.seedFromHistory(hosts);\n\n const defaultOnlyIds = [...this.#subagents.snapshot.values()]\n .filter(namespaceIsDefaultOnly)\n .map((entry) => entry.id);\n if (defaultOnlyIds.length > 0) {\n const map = mapSubagentNamespaces(\n history,\n defaultOnlyIds,\n this.#messagesKey\n );\n for (const [id, segment] of map) {\n this.#subagents.applyExecutionNamespace(id, segment);\n }\n }\n } catch {\n /* non-fatal: SSE replay still reconciles discovery */\n }\n }\n\n /**\n * Lazily resolve a single subagent's execution namespace from\n * checkpoint history. Intended call site: the first scoped\n * `useMessages` / `useToolCalls` mount for a subagent whose namespace\n * is still the default `tools:<toolCallId>`. A fallback for the\n * hydrate-time bulk seed ({@link #seedDiscoveryFromHistory}) — most\n * subagents are already promoted by the time a panel opens.\n *\n * Skips ids already promoted past default-only (SSE replay or a prior\n * resolve). Concurrent calls for the same id share one `getHistory`\n * walk via {@link #namespaceResolves}.\n *\n * @param toolCallId - Parent `task` tool-call id (the subagent's discovery key).\n */\n async resolveSubagentNamespace(toolCallId: string): Promise<void> {\n if (this.#disposed) return;\n const threadId = this.#currentThreadId;\n if (threadId == null) return;\n if (!namespaceIsDefaultOnly(this.#subagents.snapshot.get(toolCallId))) {\n return;\n }\n const inflight = this.#namespaceResolves.get(toolCallId);\n if (inflight != null) return inflight;\n\n const run = (async () => {\n try {\n /**\n * Coalesce onto the hydrate-time discovery seed. That single\n * bounded `getHistory` page bulk-promotes every default-only\n * subagent, so when many cards mount at once (the common\n * reconnect case) they all await this one read instead of each\n * firing their own walk. Re-check after it settles: usually the\n * bulk seed already promoted us and no further fetch is needed.\n */\n const seed = this.#discoverySeedPromise;\n if (seed != null) {\n await seed;\n if (this.#disposed || this.#currentThreadId !== threadId) return;\n if (\n !namespaceIsDefaultOnly(this.#subagents.snapshot.get(toolCallId))\n ) {\n return;\n }\n }\n const map = await resolveSubagentNamespaces(\n this.#options.client,\n threadId,\n [toolCallId],\n { messagesKey: this.#messagesKey }\n );\n if (this.#disposed || this.#currentThreadId !== threadId) return;\n const segment = map.get(toolCallId);\n if (segment != null) {\n this.#subagents.applyExecutionNamespace(toolCallId, segment);\n }\n } catch {\n /* non-fatal: SSE replay still reconciles the namespace */\n } finally {\n this.#namespaceResolves.delete(toolCallId);\n }\n })();\n this.#namespaceResolves.set(toolCallId, run);\n return run;\n }\n\n /**\n * Try to satisfy a scoped selector projection from checkpoint history\n * instead of opening a scoped `/events` replay.\n *\n * This is only valid while the root pump is deferred, which means hydrate\n * has classified the thread as idle/stale. Active and interrupted threads\n * must keep using SSE so ongoing work and resumes are observed. For an idle\n * thread, though, a late-mounted subagent card only needs the latest scoped\n * checkpoint snapshot; opening `/events` just asks the server to replay work\n * that already finished and can be slow for namespaces discovered from\n * history.\n *\n * Returns `true` when the projection was handled without `/events`. That can\n * mean either the store was seeded from namespace-specific history, or the\n * projection targeted a default subagent namespace that should be skipped\n * because hydrate promoted it to its execution namespace. Returns `false`\n * when the caller should fall back to the normal subscription path.\n */\n async #trySeedProjectionFromHistory<T>(params: {\n kind: \"messages\" | \"toolCalls\";\n namespace: readonly string[];\n store: StreamStore<T>;\n }): Promise<boolean> {\n const threadId = this.#currentThreadId;\n if (\n this.#disposed ||\n threadId == null ||\n params.namespace.length === 0 ||\n !this.#rootPumpDeferred ||\n this.#selfCreatedThreadIds.has(threadId) ||\n this.#missingThreadIds.has(threadId)\n ) {\n return false;\n }\n\n if (await this.#skipDefaultSubagentProjection(params.namespace, threadId)) {\n return true;\n }\n if (\n this.#disposed ||\n this.#currentThreadId !== threadId ||\n !this.#rootPumpDeferred\n ) {\n return false;\n }\n\n const seed = await this.#getScopedHistorySeed(threadId, params.namespace);\n if (\n seed == null ||\n this.#disposed ||\n this.#currentThreadId !== threadId ||\n !this.#rootPumpDeferred\n ) {\n return false;\n }\n\n if (await this.#skipDefaultSubagentProjection(params.namespace, threadId)) {\n return true;\n }\n\n if (params.kind === \"messages\") {\n params.store.setValue(seed.messages as T);\n return true;\n }\n params.store.setValue(seed.toolCalls as T);\n return true;\n }\n\n /**\n * Suppress subscriptions for placeholder subagent namespaces once hydrate has\n * resolved the real execution namespace.\n *\n * Deep-agent discovery first creates cards at `tools:<toolCallId>`. The\n * actual worker history usually lives under a different checkpoint namespace\n * such as `tools:<uuid>`, and hydrate resolves that mapping from the bounded\n * root history seed. React/Vue/Svelte/Angular selector effects can mount\n * while that seed is still in flight, so this helper waits for it and then\n * returns `true` when the original placeholder namespace is stale. Returning\n * `true` tells the projection runtime not to open an `/events` subscription\n * for the wrong namespace; the framework will re-render with the promoted\n * card namespace and acquire the real projection.\n */\n async #skipDefaultSubagentProjection(\n namespace: readonly string[],\n threadId: string\n ): Promise<boolean> {\n const toolCallId = defaultSubagentToolCallId(namespace);\n if (toolCallId == null) return false;\n if (!namespaceIsDefaultOnly(this.#subagents.snapshot.get(toolCallId))) {\n return false;\n }\n const seed = this.#discoverySeedPromise;\n if (seed != null) {\n await seed;\n }\n if (this.#disposed || this.#currentThreadId !== threadId) return true;\n return !namespaceIsDefaultOnly(this.#subagents.snapshot.get(toolCallId));\n }\n\n /**\n * Load and cache the latest checkpoint snapshot for one scoped namespace.\n *\n * `useMessages(stream, subagent)` and `useToolCalls(stream, subagent)` often\n * mount together. Both need the same namespace-specific history page, so the\n * controller keeps an in-flight promise per `threadId + checkpoint_ns`.\n * The cache may already be primed by the hydrate-time discovery history page;\n * otherwise this method performs a narrow `checkpoint_ns` read and derives\n * both projection snapshots from that one response:\n *\n * - `messages` are coerced with the stream-local message coercion rules, so\n * serialized `content_blocks` and tool-call metadata hydrate correctly.\n * - `toolCalls` are reconstructed from AI tool calls plus matching\n * ToolMessages, enough for finished/stale card panels without replaying\n * the `tools` channel.\n *\n * Returns `null` when history does not contain usable values, or the request\n * fails. Callers treat that as a signal to fall back to `/events` so custom\n * servers or unusual state shapes still work.\n */\n #getScopedHistorySeed(\n threadId: string,\n namespace: readonly string[]\n ): Promise<ScopedHistorySeed | null> {\n const checkpointNs = namespaceKey(namespace);\n const key = `${threadId}|${checkpointNs}`;\n const existing = this.#scopedHistorySeeds.get(key);\n if (existing != null) return existing;\n\n const seed = (async (): Promise<ScopedHistorySeed | null> => {\n try {\n const history = await getHistoryPage(this.#options.client, threadId, {\n limit: 1,\n checkpoint: { checkpoint_ns: checkpointNs },\n });\n const values = history[0]?.values;\n if (values == null || typeof values !== \"object\") return null;\n const messages = extractAndCoerceMessagesWithFallback(\n values as Record<string, unknown>,\n this.#messagesKey\n );\n if (messages == null) return null;\n return {\n messages,\n toolCalls: seedToolCallsFromMessages(namespace, messages),\n };\n } catch {\n return null;\n }\n })();\n this.#scopedHistorySeeds.set(key, seed);\n return seed;\n }\n\n /**\n * Reuse the hydrate-time discovery history page as scoped projection data\n * when it already contains checkpoint values for a namespace.\n *\n * The discovery read is required to resolve subagent execution namespaces and\n * subgraph hosts. That same page often includes the latest values for those\n * namespaces, so priming `#scopedHistorySeeds` here lets later\n * `useMessages(stream, subagent)` / `useToolCalls(stream, subagent)` mounts\n * hydrate from memory instead of issuing an immediate second `getHistory`\n * request. If a namespace is not present in the bounded page,\n * `#getScopedHistorySeed` still falls back to a targeted `checkpoint_ns`\n * history read.\n */\n #primeScopedHistorySeedsFromHistory(\n threadId: string,\n history: Array<{\n checkpoint?: { checkpoint_ns?: unknown };\n values?: unknown;\n }>\n ): void {\n for (const state of history) {\n const checkpointNs = state.checkpoint?.checkpoint_ns;\n if (typeof checkpointNs !== \"string\" || checkpointNs.length === 0) {\n continue;\n }\n const namespace = checkpointNs\n .split(NAMESPACE_SEPARATOR)\n .filter((segment) => segment.length > 0);\n if (namespace.length === 0) continue;\n const key = `${threadId}|${namespaceKey(namespace)}`;\n if (this.#scopedHistorySeeds.has(key)) continue;\n const values = state.values;\n if (values == null || typeof values !== \"object\") continue;\n const messages = extractAndCoerceMessagesWithFallback(\n values as Record<string, unknown>,\n this.#messagesKey\n );\n if (messages == null) continue;\n this.#scopedHistorySeeds.set(\n key,\n Promise.resolve({\n messages,\n toolCalls: seedToolCallsFromMessages(namespace, messages),\n })\n );\n }\n }\n\n /**\n * Submit input to the active thread.\n *\n * To resume a pending interrupt, use {@link respond} instead.\n *\n * @param input - Input payload for a new run.\n * @param options - Per-run config, metadata, multitask behavior, and callbacks.\n */\n async submit(\n input: unknown,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void> {\n await this.#submitter.submit(input, options);\n }\n\n /**\n * Disconnect the client from the active run and mark the controller\n * idle. By default also cancels the run server-side; pass\n * `{ cancel: false }` or call {@link disconnect} to keep the agent\n * running (join/rejoin).\n */\n async stop(options?: StreamStopOptions): Promise<void> {\n const shouldCancel = options?.cancel ?? true;\n if (shouldCancel) {\n const threadId = this.#currentThreadId;\n const runId = this.#activeRunId;\n if (runId != null && this.rootStore.getSnapshot().isLoading) {\n // Drop the partial reply now rather than on the server's terminal.\n const dropped = this.#rootMessages.closeRun({\n sync: true,\n unfinishedOnly: true,\n });\n if (dropped.size > 0) this.#messageMetadata.forget(dropped);\n }\n if (threadId != null && runId != null) {\n try {\n await this.#options.client.runs.cancel(threadId, runId);\n } catch {\n /* server cancel failures must not block client disconnect */\n }\n }\n }\n await this.#submitter.stop();\n }\n\n /**\n * Disconnect the client without cancelling the run server-side.\n * Alias for `stop({ cancel: false })`.\n */\n async disconnect(): Promise<void> {\n return this.stop({ cancel: false });\n }\n\n #markLocalRunStart(): void {\n this.#localRunDepth += 1;\n this.#submittedRunId = undefined;\n this.#submittedRunIdPending = true;\n }\n\n #markLocalRunEnd(): void {\n this.#localRunDepth = Math.max(0, this.#localRunDepth - 1);\n if (this.#localRunDepth === 0) this.#submittedRunIdPending = false;\n }\n\n #notifyCreated(runId: string): void {\n this.#activeRunId = runId;\n try {\n this.#options.onCreated?.({ runId });\n } catch {\n /* caller-supplied callback errors must not crash the stream */\n }\n }\n\n #notifyCompleted(\n reason: RunExecutionReason,\n runId = this.#activeRunId\n ): void {\n if (runId != null && runId === this.#activeRunId) {\n this.#activeRunId = undefined;\n }\n setTimeout(() => {\n if (this.#disposed) return;\n try {\n this.#options.onCompleted?.(\n runId == null ? { reason } : { runId, reason }\n );\n } catch {\n /* caller-supplied callback errors must not crash the stream */\n }\n }, 0);\n }\n\n readonly #runLifecycleListener = (event: Event): void => {\n if (this.#localRunDepth > 0) return;\n if (event.method !== \"lifecycle\") return;\n if (!isRootNamespace(event.params.namespace)) return;\n if (!this.rootStore.getSnapshot().isLoading) return;\n const lifecycle = (event as LifecycleEvent).params.data as {\n event?: string;\n };\n const reason = lifecycleReason(lifecycle?.event);\n if (reason == null) return;\n this.#notifyCompleted(reason);\n };\n\n /**\n * Cancel a queued submission by id. Returns `true` when the entry\n * was found and removed, `false` otherwise.\n *\n * Removes the client-side entry either way; also issues a server-side\n * cancel when the configured queue adapter is server-backed (see\n * `AgentServerAdapter.serverQueue`). A no-op for the default,\n * client-only adapter.\n *\n * @param id - Client-side queue entry id to remove.\n */\n async cancelQueued(id: string): Promise<boolean> {\n return this.#submitter.cancelQueued(id);\n }\n\n /**\n * Drop every queued submission. Cancels the underlying server-side\n * runs too when the configured queue adapter is server-backed.\n */\n async clearQueue(): Promise<void> {\n await this.#submitter.clearQueue();\n }\n\n /**\n * Respond to a single pending protocol interrupt.\n *\n * When `options.interruptId` is omitted, resolution walks\n * {@link ThreadStream.interrupts `thread.interrupts`} from newest to\n * oldest and picks the first entry whose `interruptId` has not already\n * been resolved by a prior `respond()` call. That entry may be at the\n * root (`namespace: []`) or inside a subgraph (non-empty `namespace`).\n * {@link RootSnapshot.interrupts `rootStore.interrupts`} /\n * framework `stream.interrupts` mirrors the same pending interrupts\n * (including nested namespaces) for UI rendering.\n *\n * Omitting `interruptId` is fine when exactly one interrupt is pending.\n * When several can be active (parallel subagents, fan-out, nested\n * graphs), pass an explicit `interruptId` so you resume the interrupt\n * the user acted on. `namespace` is resolved automatically from\n * `thread.interrupts` / `stream.interrupts` when omitted.\n *\n * To resume several interrupts pending at the same checkpoint in one\n * command, use {@link respondAll} — sequential single `respond()` calls\n * would not work, since the first resume starts a run, leaving the\n * others with no interrupted run to respond to.\n *\n * The server validates `namespace` against the pending interrupt. Root\n * interrupts use `namespace: []`. Subgraph interrupts carry the exact\n * tuple on each {@link Interrupt} / {@link InterruptPayload} entry.\n *\n * @param response - Payload sent back to the interrupted namespace.\n * @param options - Optional target (`interruptId` / `namespace`) and\n * run-level `config` / `metadata` folded into the run that services\n * the resume (model/user config, trigger source, test flags, …).\n * Equivalent to the same fields on {@link StreamSubmitOptions}.\n *\n * @example Single pending interrupt (safe to omit a target)\n * ```ts\n * await controller.respond({ approved: true });\n * ```\n *\n * @example Carry run config / metadata onto the resume\n * ```ts\n * await controller.respond(\n * { approved: true },\n * { config: { configurable: { model: \"gpt-4o\" } }, metadata: { source: \"ui\" } },\n * );\n * ```\n *\n * @example Multiple / nested interrupts — target by id\n * ```tsx\n * for (const intr of stream.interrupts) {\n * await stream.respond(decide(intr.value), { interruptId: intr.id! });\n * }\n * ```\n *\n * Each {@link InterruptPayload} on `thread.interrupts` and each\n * {@link Interrupt} on `stream.interrupts` mirrors an\n * `input.requested` event with its protocol `namespace`.\n */\n async respond(\n response: unknown,\n options?: StreamRespondOptions<ConfigurableType>\n ): Promise<void> {\n if (this.#disposed || this.#thread == null) {\n throw new Error(\"No active thread to respond to.\");\n }\n\n const resolved =\n options?.interruptId != null\n ? {\n interruptId: options.interruptId,\n namespace: this.#resolveNamespaceForInterruptId(\n options.interruptId,\n options.namespace\n ),\n }\n : this.#resolveInterruptForResume();\n if (resolved == null) {\n throw new Error(\"No pending interrupt to respond to.\");\n }\n const thread = this.#thread;\n\n // Apply the state `update` optimistically, mirroring `submit()`: append its\n // messages to the root projection and mint stable ids so the resumed run's\n // echo reconciles by id. Without this the interrupt is cleared the instant\n // `respond()` dispatches while the pushed messages only reappear after a\n // server round-trip — so a HITL \"card\" pushed via `update` would vanish for\n // that window (the flicker). The id-injected payload is what we dispatch,\n // so the server echoes the same ids back and `#applyValues` flips them\n // `pending` → `sent` in place (no duplicate, no gap).\n const prepared =\n options?.update != null\n ? this.#beginOptimistic(options.update)\n : undefined;\n const dispatchUpdate = this.#resolveDispatchUpdate(\n options?.update,\n prepared\n );\n\n try {\n // Route through the coordinator so a resumed run that fails (e.g. a\n // missing model key surfaced after the user answers) lands in the\n // reactive `rootStore.error` slot, exactly like a `submit()` failure.\n // The dispatch (`respondInput` + interrupt-resolved bookkeeping) is\n // what's awaited; the resumed run's terminal is watched in the\n // background (see {@link SubmitCoordinator.dispatchResume}), which also\n // settles the optimistic handle (rolls back un-echoed keys on failure).\n await this.#submitter.dispatchResume(async () => {\n await thread.respondInput({\n namespace: resolved.namespace,\n interrupt_id: resolved.interruptId,\n response: normalizeHitlResponseForServer(response),\n // Fold an optional state update / directed jump into the same\n // superstep as the resume (HITL \"push card into state + resume\").\n // Omitted when absent so the server still sees a plain resume.\n // `BaseMessage` instances under the messages key are serialized to\n // plain dicts (like `submit()`) so they coerce server-side.\n ...(dispatchUpdate != null ? { update: dispatchUpdate } : {}),\n ...(options?.goto != null ? { goto: options.goto } : {}),\n config: options?.config,\n metadata: options?.metadata,\n });\n this.#advanceInterruptReplayBarrier();\n this.#markInterruptResolvedInRootStore(resolved.interruptId);\n }, prepared?.handle);\n } catch (error) {\n this.#discardPendingInterruptEvents();\n if (this.#disposed && isAbortLikeError(error)) {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Resume several pending interrupts at the same checkpoint in a single\n * command.\n *\n * Required when a run pauses on multiple interrupts simultaneously\n * (e.g. parallel tool-authorization prompts): a single\n * `Command({ resume })` carrying every interrupt's payload resumes them\n * together. Sequential {@link respond} calls would fail because the\n * first resume starts a run, leaving the rest with no interrupted run to\n * respond to.\n *\n * `responsesById` maps each pending `interruptId` to the payload sent\n * back to it, so different interrupts can receive different responses\n * (approve one, deny another). To send the *same* payload to several\n * interrupts, build the map with that value for each id, e.g.\n * `Object.fromEntries(ids.map((id) => [id, response]))`.\n *\n * The server resumes by `interruptId`, so namespaces are resolved\n * internally from `getThread()?.interrupts` and need not be supplied.\n *\n * @param responsesById - Map of pending `interruptId` to its response\n * payload. Must contain at least one entry.\n * @param options - Optional run-level `config` / `metadata` folded into\n * the single run that services the batched resume. Equivalent to the\n * same fields on {@link StreamSubmitOptions}.\n *\n * @example Distinct payloads per interrupt\n * ```tsx\n * await stream.respondAll({\n * [interruptA.id]: { approved: true },\n * [interruptB.id]: { approved: false },\n * });\n * ```\n *\n * @example Same payload to every pending interrupt\n * ```tsx\n * await stream.respondAll(\n * Object.fromEntries(stream.interrupts.map((i) => [i.id!, { approved: true }])),\n * );\n * ```\n */\n async respondAll(\n responsesById: Record<string, unknown>,\n options?: StreamRespondAllOptions<ConfigurableType>\n ): Promise<void> {\n if (this.#disposed || this.#thread == null) {\n throw new Error(\"No active thread to respond to.\");\n }\n const entries = Object.entries(responsesById);\n if (entries.length === 0) {\n throw new Error(\"respondAll() requires at least one response.\");\n }\n const thread = this.#thread;\n const responses = entries.map(([interruptId, response]) => ({\n interrupt_id: interruptId,\n response: normalizeHitlResponseForServer(response),\n namespace: this.#resolveNamespaceForInterruptId(interruptId),\n }));\n // Apply the run-level `update` optimistically (see `respond()` for the\n // rationale): the batched resume's pushed messages paint immediately and\n // reconcile by id when the single servicing run echoes them back.\n const prepared =\n options?.update != null\n ? this.#beginOptimistic(options.update)\n : undefined;\n const dispatchUpdate = this.#resolveDispatchUpdate(\n options?.update,\n prepared\n );\n\n try {\n // See `respond()` — route through the coordinator so the single run\n // that services the batched resume surfaces failures on the reactive\n // `rootStore.error` slot and settles the optimistic handle.\n await this.#submitter.dispatchResume(async () => {\n await thread.respondInput({\n responses,\n // A batched resume services every targeted interrupt in one run, so\n // the update / jump are run-level (not per-entry) — applied once in\n // that run's superstep alongside all the resumes. `BaseMessage`\n // instances under the messages key are serialized to plain dicts\n // (like `submit()`) so they coerce server-side.\n ...(dispatchUpdate != null ? { update: dispatchUpdate } : {}),\n ...(options?.goto != null ? { goto: options.goto } : {}),\n config: options?.config,\n metadata: options?.metadata,\n });\n this.#advanceInterruptReplayBarrier();\n for (const { interrupt_id: interruptId } of responses) {\n this.#markInterruptResolvedInRootStore(interruptId);\n }\n }, prepared?.handle);\n } catch (error) {\n this.#discardPendingInterruptEvents();\n if (this.#disposed && isAbortLikeError(error)) {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Dispose the active thread, subscriptions, registry entries, and listeners.\n */\n async dispose(): Promise<void> {\n if (this.#disposed) return;\n this.#cancelPendingDispose();\n this.#disposed = true;\n this.#submitter.abortActiveRun();\n await this.#teardownThread();\n await this.registry.dispose();\n this.#threadListeners.clear();\n }\n\n /**\n * StrictMode-safe lifecycle hook for framework bindings.\n *\n * React 18+ `StrictMode` intentionally mounts → unmounts → remounts\n * components in dev to surface effect-cleanup bugs. A naive\n * `useEffect(() => () => controller.dispose())` would permanently\n * tear the controller down on that first synthetic unmount, leaving\n * every subsequent `submit()` a silent no-op.\n *\n * Call {@link activate} from the bind site's effect and return the\n * result as the effect's cleanup. The controller uses deferred\n * disposal: a `release()` only schedules a dispose on the next\n * microtask, which is cancelled if another `activate()` arrives\n * before it fires (the normal StrictMode remount path).\n */\n activate(): () => void {\n this.#cancelPendingDispose();\n return () => {\n if (this.#disposed) return;\n this.#pendingDisposeTimer = setTimeout(() => {\n this.#pendingDisposeTimer = null;\n void this.dispose().catch(() => undefined);\n }, 0);\n };\n }\n\n /**\n * Cancel a deferred dispose scheduled by {@link activate}.\n */\n #cancelPendingDispose(): void {\n if (this.#pendingDisposeTimer != null) {\n clearTimeout(this.#pendingDisposeTimer);\n this.#pendingDisposeTimer = null;\n }\n }\n\n // ---------- thread access ----------\n\n /**\n * Returns the bound {@link ThreadStream}, if one exists. Prefer\n * {@link StreamController.rootStore} and selector projections for\n * UI work; use this for low-level protocol access.\n */\n getThread(): ThreadStream | undefined {\n return this.#thread;\n }\n\n /**\n * Listen for `ThreadStream` lifecycle (swap on thread-id change,\n * detach on dispose). The listener fires immediately with the\n * current thread (may be `undefined`).\n *\n * @param listener - Callback invoked immediately and on every thread swap.\n */\n subscribeThread(\n listener: (thread: ThreadStream | undefined) => void\n ): () => void {\n this.#threadListeners.add(listener);\n listener(this.#thread);\n return () => {\n this.#threadListeners.delete(listener);\n };\n }\n\n // ---------- internals ----------\n\n /**\n * Build the initial root snapshot from configured initial values.\n */\n #createInitialSnapshot(): RootSnapshot<StateType, InterruptType> {\n const values = (this.#options.initialValues ??\n ({} as StateType)) as StateType;\n const messages = extractAndCoerceMessages(\n values as unknown as Record<string, unknown>,\n this.#messagesKey\n );\n /**\n * Seed `isThreadLoading: true` synchronously when a caller-supplied\n * threadId is on the controller at construction/swap time. Without\n * this Suspense wrappers would render their fallback for a tick\n * because `isThreadLoading` flips false → true → false once the\n * deferred `hydrate()` starts, and the synchronous render observes\n * the initial `false`.\n */\n const willHydrate =\n this.#currentThreadId != null &&\n !this.#selfCreatedThreadIds.has(this.#currentThreadId);\n return {\n values,\n messages,\n toolCalls: [],\n interrupts: [],\n interrupt: undefined,\n isLoading: false,\n isThreadLoading: willHydrate,\n error: undefined,\n threadId: this.#currentThreadId,\n };\n }\n\n /**\n * Return the active thread stream, creating and binding one when needed.\n *\n * @param threadId - Thread id used when constructing the stream.\n * @param deferRootPump - When `true`, build the ThreadStream and bind\n * the registry but skip starting the persistent root SSE pump. Used\n * for client-self-created thread ids whose server-side thread row\n * doesn't exist yet — opening the pump's `subscription.subscribe`\n * against a not-yet-existent thread produces a `404: Thread not\n * found` protocol error that strands terminal lifecycle events and\n * leaves the UI showing nothing until the user reloads. The pump is\n * started later via {@link #startDeferredRootPump} after `submitRun`\n * / `respondInput` commits the thread server-side.\n *\n * Note: PR 2381's `#runStartReady` gate covers the analogous race\n * for the in-flight `run.start` send, but only when that send is\n * already pending. `#ensureThread` runs *before* `submitRun` is\n * called (and thus before the gate is armed), so on transports\n * that subscribe synchronously (WebSocket) the deferred path is\n * still required.\n */\n #ensureThread(threadId: string, deferRootPump = false): ThreadStream {\n if (this.#thread != null) {\n if (!deferRootPump && !this.#rootPumpDeferred && this.#rootPump == null) {\n this.#startRootPump(this.#thread);\n }\n return this.#thread;\n }\n this.#thread = this.#options.client.threads.stream(threadId, {\n assistantId: this.#options.assistantId,\n transport: this.#options.transport,\n fetch: this.#options.fetch,\n webSocketFactory: this.#options.webSocketFactory,\n maxReconnectAttempts: this.#options.maxReconnectAttempts,\n streamIdleReconnect: this.#options.streamIdleReconnect,\n reconnectDelayMs: this.#options.reconnectDelayMs,\n onReconnect: this.#options.onReconnect,\n onConnected: this.#options.onConnected,\n });\n this.registry.bind(this.#thread);\n if (deferRootPump) {\n // Resolve `#rootPumpReady` immediately so `submit()`'s `await\n // this.#rootPumpReady` doesn't block — the dispatch path only\n // needs the ThreadStream wired up to call `submitRun`, not the\n // persistent subscription.\n this.#rootPumpReady = Promise.resolve();\n this.#rootPumpDeferred = true;\n } else {\n this.#startRootPump(this.#thread);\n }\n this.#notifyThreadListeners();\n return this.#thread;\n }\n\n /**\n * Start the previously-deferred root SSE pump after the first\n * `submitRun` / `respondInput` has committed the thread server-side.\n *\n * No-op when the pump was started eagerly in {@link #ensureThread}\n * (i.e. for hydrated existing threads, or for any thread whose pump\n * has already been brought up).\n */\n #startDeferredRootPump(): void {\n if (!this.#rootPumpDeferred) return;\n if (this.#thread == null) return;\n this.#rootPumpDeferred = false;\n this.#startRootPump(this.#thread);\n }\n\n /**\n * Abandon a deferred root pump that never started because its\n * triggering dispatch (`submitRun` / `respondInput`) failed.\n *\n * Without this, the controller would be wedged in a state where:\n * - `#thread` is wired but no content pump is open\n * - `#rootPumpDeferred` stays `true`\n *\n * A retry submit must re-run `#ensureThread` from scratch (with\n * `deferRootPump` still true — the id stays in\n * `#selfCreatedThreadIds` until a successful dispatch). Tearing\n * down `#thread` is the simplest recovery; the failed dispatch\n * means there was nothing to subscribe to anyway.\n */\n #abandonDeferredRootPump(): void {\n if (!this.#rootPumpDeferred) return;\n this.#rootPumpDeferred = false;\n void this.#teardownThread();\n }\n\n /**\n * Close the current thread stream and reset per-thread assembly state.\n */\n async #teardownThread(): Promise<void> {\n /**\n * Invalidate the in-flight root pump before `close()` unparks it.\n * `SubscriptionHandle.close()` leaves queued events intact and the\n * iterator drains them before observing `closed`, so without this\n * bump a parked interrupted pump would still dispatch stale\n * `values` / `messages` into a snapshot `hydrate()` already cleared.\n */\n this.#rootPumpGeneration += 1;\n const thread = this.#thread;\n this.#thread = undefined;\n this.registry.bind(undefined);\n this.#threadEventUnsubscribe?.();\n this.#threadEventUnsubscribe = undefined;\n this.#threadErrorUnsubscribe?.();\n this.#threadErrorUnsubscribe = undefined;\n /**\n * Persistent lifecycle driver is scoped to the current thread\n * stream. Remove it so a swap to a new thread starts with a clean\n * listener set (a new one is installed in `#startRootPump`).\n */\n this.#rootEventListeners.delete(this.#lifecycleLoading.listener);\n this.#rootEventListeners.delete(this.#runLifecycleListener);\n /**\n * Close first so a pump parked on `waitForResume()` (interrupted\n * run) unparks even if the unsubscribe RPC is slow. `close()` is\n * idempotent; `unsubscribe()` is then a no-op once closed.\n */\n const subscription = this.#rootSubscription;\n this.#rootSubscription = undefined;\n subscription?.close();\n this.#rootPumpReady = undefined;\n // Reset so a swap to a new thread doesn't carry over a stale\n // deferred flag — `#ensureThread` will set it again if the new\n // thread is self-created.\n this.#rootPumpDeferred = false;\n\n // Reset per-thread assembly state before any awaits so hydrate()\n // can clear the UI snapshot without waiting on pump/close.\n this.#rootMessages.reset();\n this.#rootToolAssembler = new ToolCallAssembler();\n this.#lifecycleLoading.reset();\n this.#subagents.reset();\n this.#subgraphs.reset();\n this.#scopedHistorySeeds.clear();\n this.#activeRunId = undefined;\n this.#localRunDepth = 0;\n this.#messageMetadata.reset();\n // Drop the hydrate-window allowlist — the next thread's hydrate\n // will repopulate it from that thread's `state.tasks[].interrupts`.\n this.#hydratedActiveInterruptIds = null;\n this.#hydratedCheckpointTime = undefined;\n this.#interruptReplayThroughSeq = undefined;\n this.#pendingHydrationInterruptEvents = [];\n this.#discardPendingInterruptEvents();\n this.queueStore.setState(\n () => EMPTY_QUEUE as SubmissionQueueSnapshot<StateType>\n );\n this.#submitter.detachQueue();\n\n try {\n await subscription?.unsubscribe();\n } catch {\n /* already closed */\n }\n try {\n await this.#rootPump;\n } catch {\n /* ignore */\n }\n this.#rootPump = undefined;\n\n if (thread != null) {\n try {\n await thread.close();\n } catch {\n /* already closed */\n }\n this.#notifyThreadListeners();\n }\n }\n\n /**\n * Determine whether the configured transport uses the resumable event-stream path.\n */\n #usesEventStreamTransport(): boolean {\n const transport = this.#options.transport;\n if (transport === \"websocket\") return false;\n if (transport == null || transport === \"sse\") return true;\n return typeof transport.openEventStream === \"function\";\n }\n\n /**\n * Start the always-on root subscription pump for the provided thread.\n *\n * @param thread - Thread stream to subscribe to and fan out from.\n */\n #startRootPump(thread: ThreadStream): void {\n if (this.#rootPump != null) return;\n const pumpGeneration = this.#rootPumpGeneration;\n let resolveReady: (() => void) | undefined;\n this.#rootPumpReady = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n\n /**\n * Wildcard discovery + interrupt tracking is delivered via the\n * thread's dedicated lifecycle watcher (see `ThreadStream.onEvent`).\n * This callback fires once per globally-unique event across both\n * the content pump AND the watcher, so we can drive discovery\n * runners and nested HITL capture without widening the content\n * pump's narrow filter.\n */\n this.#threadEventUnsubscribe = thread.onEvent((event) =>\n this.#onWildcardEvent(event)\n );\n this.#threadErrorUnsubscribe = thread.onError((error) => {\n this.rootStore.setState((s) => ({ ...s, error, isLoading: false }));\n this.#rootSubscription?.close();\n });\n\n /**\n * Persistent isLoading driver. Drives `isLoading` from\n * root-namespace lifecycle events so that in-flight runs observed\n * via `hydrate()` (not initiated by a local `submit()`) still flip\n * the UI to loading. `running` → true; terminals → false. The\n * optimistic `isLoading = true` inside `submit()` stays because\n * that fires before any subscription event arrives.\n */\n this.#rootEventListeners.add(this.#lifecycleLoading.listener);\n this.#rootEventListeners.add(this.#runLifecycleListener);\n\n const pump = (async () => {\n try {\n /**\n * Root content pump: depth 1 is required because the controller\n * classifies tool events at namespace length ≤ 1 as root-level\n * (see `#onWildcardEvent`'s `isRootLevelTool` check). The deep-\n * agent `task` dispatcher fires `tools.tool-started` at\n * `[\"tools:<id>\"]` (length 1), so a depth-0 filter would drop\n * those events server-side before they reached `root.toolCalls`.\n *\n * Deeper content (subagent message tokens, values snapshots) is\n * pulled in on demand by per-namespace selector projections\n * (e.g. `useMessages(sub)`).\n */\n const subscriptionPromise = thread.subscribe({\n channels: [...ROOT_PUMP_CHANNELS] as Channel[],\n namespaces: [[] as string[]],\n depth: 1,\n });\n if (this.#usesEventStreamTransport()) {\n /**\n * SSE streams can legitimately withhold response headers until\n * the first event is available. Waiting for `subscribe()` here\n * would deadlock new-thread submits: the run is not dispatched\n * until the root pump is \"ready\", but the pump does not become\n * ready until the run emits. `thread.subscribe()` has already\n * registered the local subscription and scheduled the stream\n * rotation by this point; waiting one microtask lets the fetch\n * get kicked off without requiring headers to arrive.\n */\n queueMicrotask(() => {\n resolveReady?.();\n resolveReady = undefined;\n });\n }\n const subscription = await subscriptionPromise;\n if (pumpGeneration !== this.#rootPumpGeneration) {\n resolveReady?.();\n resolveReady = undefined;\n try {\n subscription.close();\n } catch {\n /* ignore */\n }\n return;\n }\n resolveReady?.();\n resolveReady = undefined;\n this.#rootSubscription = subscription;\n /**\n * The SSE transport pauses the underlying subscription when\n * a terminal root lifecycle event arrives (so `for await`\n * loops observing a single run exit cleanly) and re-opens\n * the next run's server stream on `#prepareForNextRun`,\n * resuming the subscription handle. The root pump needs to\n * survive that hand-off: we re-enter the inner `for await`\n * for every resumed iteration until the subscription is\n * permanently closed or the controller is disposed.\n */\n while (!this.#disposed && pumpGeneration === this.#rootPumpGeneration) {\n for await (const event of subscription) {\n if (this.#disposed || pumpGeneration !== this.#rootPumpGeneration) {\n break;\n }\n /**\n * Resilience: isolate per-event dispatch from the pump loop.\n *\n * `#onRootEvent` runs synchronously and, transitively,\n * invokes every root-bus listener (selector projections that\n * opted into the shared stream) plus every `rootStore`\n * subscriber. Some of those subscribers live in a React\n * render tree — `useStream` drives\n * `useSyncExternalStore`, so a misbehaving component can\n * surface a render-phase error (\"Maximum update depth\n * exceeded\", \"The result of getSnapshot should be cached\",\n * etc.) that propagates out here.\n *\n * Without this guard, a single throw bubbles through the\n * `for await` loop and terminates the root pump permanently.\n * That is catastrophic: no more root events get processed —\n * the terminal `lifecycle: completed` never lands, so\n * `#awaitNextTerminal` never resolves, `isLoading` stays\n * `true`, composers stay disabled, and the final assistant\n * turn never commits to `stream.messages`. The UI looks\n * hung even though the server is still emitting events\n * (and `ThreadStream.onEvent` keeps firing).\n *\n * We therefore swallow the error and keep pumping. The\n * the pump's correctness guarantees do not depend on any\n * consumer behaving well.\n */\n try {\n this.#onRootEvent(event);\n } catch {\n /**\n * Best-effort — a consumer-facing store subscriber should not\n * terminate the root pump. Store mutations happen before\n * listeners are notified, so continuing with later events keeps\n * the controller's authoritative state moving forward.\n */\n }\n }\n if (this.#disposed || pumpGeneration !== this.#rootPumpGeneration) {\n break;\n }\n if (!subscription.isPaused) {\n const snapshot = this.rootStore.getSnapshot();\n if (snapshot.isLoading && snapshot.error == null) {\n this.rootStore.setState((s) => ({\n ...s,\n error: new Error(\n \"Thread event stream closed before the active run completed.\"\n ),\n isLoading: false,\n }));\n }\n break;\n }\n await subscription.waitForResume();\n }\n } catch {\n resolveReady?.();\n resolveReady = undefined;\n /* thread closed or errored */\n }\n })();\n this.#rootPump = pump;\n void pump.finally(() => {\n if (pumpGeneration !== this.#rootPumpGeneration) return;\n if (this.#rootPump !== pump) return;\n this.#rootPumpGeneration += 1;\n this.#rootSubscription = undefined;\n this.#rootPump = undefined;\n this.#rootPumpReady = undefined;\n this.#threadEventUnsubscribe?.();\n this.#threadEventUnsubscribe = undefined;\n this.#threadErrorUnsubscribe?.();\n this.#threadErrorUnsubscribe = undefined;\n this.#rootEventListeners.delete(this.#lifecycleLoading.listener);\n this.#rootEventListeners.delete(this.#runLifecycleListener);\n });\n }\n\n /**\n * Handle an event delivered via {@link ThreadStream.onEvent}.\n *\n * `onEvent` fires once per globally-unique event across the content\n * pump and the wildcard lifecycle watcher, so this is the single\n * entry point for wildcard discovery / interrupt tracking. It does\n * NOT fan events out to the root bus (that's driven by the content\n * pump iterator so root-bus short-circuits stay depth-1 scoped) and\n * it does NOT process root content — messages/tools/values at root\n * are handled by `#onRootEvent` off the content pump.\n *\n * @param event - Raw protocol event observed by the thread-wide listener.\n */\n #onWildcardEvent(event: Event): void {\n try {\n this.#subagents.push(event);\n } catch {\n /**\n * Discovery store subscribers are user/UI code. If one throws, still\n * let the wildcard watcher update subgraphs, loading, and interrupts.\n */\n }\n this.#subgraphs.push(event);\n this.#lifecycleLoading.handle(event);\n\n /**\n * `input.requested` events (including HITL inside a subagent /\n * subgraph) are not always observable via the narrow content pump.\n * Mirror every namespace into `rootStore.interrupts` here so UI\n * state does not depend on the content pump being the first\n * consumer. `ThreadStream.interrupts` is updated in parallel for\n * resume targeting.\n */\n this.#recordInterrupt(event);\n this.#settleParkedInterruptsOnTerminal(event);\n }\n\n /**\n * Process one root-pump event and update all root projections.\n *\n * @param event - Event yielded by the root subscription.\n */\n #onRootEvent(event: Event): void {\n try {\n this.#subagents.push(event);\n } catch {\n /**\n * Discovery store subscribers are user/UI code. If one throws, still\n * process the root event below so orchestrator messages and terminal\n * state continue to advance.\n */\n }\n\n /**\n * Fan root-pump events out to every root-bus listener (selector\n * projections that opted into the shared stream,\n * `#awaitTerminal`, etc.). The root bus mirrors the content\n * pump's narrow scope (depth 1 at root) so projections that\n * short-circuit via the bus stay bounded.\n */\n if (this.#rootEventListeners.size > 0) {\n for (const listener of this.#rootEventListeners) {\n try {\n listener(event);\n } catch {\n /**\n * Best-effort — a bad listener should not wedge other\n * projections or the root pump itself.\n */\n }\n }\n }\n\n // After discovery and the root bus on purpose: root selector projections\n // start empty and build from the replayed history.\n const floor = this.#hydratedCheckpointTime;\n if (floor != null && event.params.timestamp < floor) return;\n\n /**\n * `messages` and `tools` events are emitted under a node's\n * namespace — for a typical StateGraph the LLM's token deltas\n * land on `[\"model:<uuid>\"]`, tool executions on\n * `[\"tools:<uuid>\"]`, etc. The orchestrator's own turns (root\n * agent, or an orchestrator-scoped subgraph like `model:*` /\n * `model_request:*`) belong in `root.messages` and\n * `root.toolCalls`.\n *\n * Subagent / tool-internal branches do NOT:\n * - `task:*` segment — legacy subagent convention.\n * - `tools:*` segment — every tool execution is wrapped in a\n * `tools` subgraph. For simple tools its only content is\n * the eventual tool result (also echoed verbatim by\n * `values.messages` so we don't lose anything). For the\n * deep-agent `task` tool its content IS the spawned\n * subagent's full message + tool stream, which is surfaced\n * separately via `useMessages(stream, subagent)` /\n * `useToolCalls(stream, subagent)`.\n *\n * We therefore drop `messages` events from any namespace that\n * contains a `task:*` or `tools:*` segment; the authoritative\n * tool-result text lands in `root.messages` via the root\n * `values.messages` snapshot merge in `#applyValues`.\n */\n const isInternalNamespace = isInternalWorkNamespace(event.params.namespace);\n const hasLegacySubagentNamespace = isLegacySubagentNamespace(\n event.params.namespace\n );\n\n if (event.method === \"messages\") {\n if (!isInternalNamespace) {\n this.#rootMessages.handleMessage(event as MessagesEvent);\n }\n return;\n }\n\n if (event.method === \"tools\") {\n /**\n * Root-level tool events (both for simple orchestrator tools\n * and the deep-agent `task` dispatcher) fire at a\n * single-segment `[\"tools:<id>\"]` namespace. Anything deeper\n * (e.g. `[tools:<outer>, tools:<inner>]`) is a subagent's own\n * tool call and belongs to that subagent's `useToolCalls`\n * view, not the orchestrator's `root.toolCalls`.\n */\n const isRootLevelTool =\n event.params.namespace.length <= 1 && !hasLegacySubagentNamespace;\n if (isRootLevelTool) {\n /**\n * Record the `namespace → tool_call_id` association so that\n * the ensuing `message-start` (role: \"tool\") at the same\n * namespace can recover the `tool_call_id` (the `messages`\n * channel's start event doesn't carry it directly).\n */\n const toolData = event.params.data as {\n event?: string;\n tool_call_id?: string;\n };\n if (\n toolData.event === \"tool-started\" &&\n typeof toolData.tool_call_id === \"string\"\n ) {\n this.#rootMessages.recordToolCallNamespace(\n event.params.namespace,\n toolData.tool_call_id\n );\n }\n const tc = this.#rootToolAssembler.consume(event as ToolsEvent);\n if (tc != null) {\n this.rootStore.setState((s) => ({\n ...s,\n toolCalls: upsertToolCall(s.toolCalls, tc),\n }));\n }\n }\n return;\n }\n\n /**\n * The `checkpoints` channel carries the lightweight envelope\n * (`id`, `parent_id`, `step`, `source`) emitted immediately\n * before its companion `values` event on the same superstep.\n * Buffer the envelope per-namespace so the ensuing `values`\n * event at the same namespace can pair with it in `#applyValues`.\n * The buffer is read-and-cleared on consumption so a subsequent\n * `values` event without a new checkpoint doesn't reuse stale\n * metadata.\n */\n if (event.method === \"checkpoints\") {\n const data = event.params.data as {\n id?: unknown;\n parent_id?: unknown;\n step?: unknown;\n } | null;\n this.#messageMetadata.bufferCheckpoint(event.params.namespace, data);\n return;\n }\n\n // Channels below are only meaningful at the root namespace.\n const isRoot = isRootNamespace(event.params.namespace);\n if (!isRoot) return;\n\n if (event.method === \"values\") {\n const valuesEvent = event as ValuesEvent;\n const bufferedCheckpoint = this.#messageMetadata.consumeCheckpoint(\n event.params.namespace\n );\n this.#applyValues(valuesEvent.params.data, bufferedCheckpoint);\n return;\n }\n\n if (event.method === \"input.requested\") {\n this.#recordInterrupt(event);\n return;\n }\n\n if (event.method === \"lifecycle\") {\n /**\n * Root lifecycle transitions are observed elsewhere\n * (#awaitTerminal) to unblock `submit`. Here they drop a closed\n * run's never-checkpointed messages.\n */\n const lifecycle = (event as LifecycleEvent).params.data as {\n event?: string;\n };\n const dropped = this.#rootMessages.applyLifecycle(lifecycle?.event);\n if (dropped.size > 0) this.#messageMetadata.forget(dropped);\n }\n }\n\n /**\n * How a lifecycle event relates to the run a local `submit()` started.\n * New subscriptions replay earlier runs' terminals, and accepting one\n * would end the submitted run early: `\"other\"` marks those, `\"pending\"`\n * an event that names a run before `run.start` has answered. `undefined`\n * when it can't be told apart (no submit in flight, no run named, or no\n * run id returned).\n */\n #submittedRunMatch(event: Event): \"other\" | \"pending\" | undefined {\n if (event.method !== \"lifecycle\" || this.#localRunDepth === 0) {\n return undefined;\n }\n const runId = synthesizedEventRunId(event.event_id);\n if (runId == null) return undefined;\n if (this.#submittedRunIdPending) return \"pending\";\n if (this.#submittedRunId == null) return undefined;\n return runId === this.#submittedRunId ? undefined : \"other\";\n }\n\n /**\n * Merge a `values` payload into root values and root messages.\n *\n * @param raw - Raw `values` channel payload.\n * @param checkpoint - Optional checkpoint envelope paired with the values event.\n */\n /**\n * Apply a submit input optimistically to the root projection before\n * the server responds. Mints stable ids for id-less messages (so the\n * server echo reconciles by id), appends them to the projection, and\n * shallow-merges non-message input keys into `values`.\n *\n * Returns the dispatch payload (id-injected) for the coordinator to\n * send, plus an {@link OptimisticHandle} for terminal reconciliation.\n * Returns `undefined` when optimistic UI is disabled or there is\n * nothing to echo, in which case the coordinator dispatches the raw\n * input unchanged.\n *\n * @param input - Raw input passed to `submit()`.\n */\n #beginOptimistic(\n input: unknown\n ): { dispatchInput: unknown; handle: OptimisticHandle } | undefined {\n if (this.#options.optimistic === false) return undefined;\n if (input == null || typeof input !== \"object\" || Array.isArray(input)) {\n return undefined;\n }\n const prepared = prepareOptimisticInput(\n input as Record<string, unknown>,\n this.#messagesKey,\n () => uuidv7()\n );\n const extraKeys = Object.keys(prepared.extraValues);\n if (prepared.echoedIds.length === 0 && extraKeys.length === 0) {\n return undefined;\n }\n\n const currentValues = this.rootStore.getSnapshot().values as Record<\n string,\n unknown\n >;\n const restoreKeys = extraKeys.map((key) => ({\n key,\n hadKey: Object.prototype.hasOwnProperty.call(currentValues, key),\n prevValue: currentValues[key],\n }));\n\n this.#sawValuesForRun = false;\n // Commit synchronously: this runs inside the user's `submit()` /\n // `respond()` call (before the first await), so the optimistic\n // message lands in the same tick — and therefore the same React /\n // framework commit — as any local UI state the caller flips\n // alongside it. A macrotask-deferred flush would paint the message\n // one tick late, leaving a blink (e.g. a HITL card vanishing between\n // \"form hidden\" and \"resolved card shown\").\n this.#rootMessages.appendOptimistic(\n prepared.optimisticMessages,\n prepared.extraValues,\n { sync: true }\n );\n if (prepared.echoedIds.length > 0) {\n this.#messageMetadata.markPending(prepared.echoedIds);\n }\n return {\n dispatchInput: prepared.dispatchInput,\n handle: { echoedIds: prepared.echoedIds, restoreKeys },\n };\n }\n\n /**\n * Pick the `update` payload to dispatch on a resume (`respond` /\n * `respondAll`).\n *\n * When the optimistic path ran ({@link #beginOptimistic} returned a handle),\n * its `dispatchInput` already carries the minted message ids the server must\n * echo back, so dispatch that — the echo reconciles the optimistic messages\n * by id (no duplicate). Otherwise (optimistic UI disabled, or an `update`\n * with no echoable messages — e.g. the tuple-entry form) fall back to\n * serializing `BaseMessage` instances to dicts, exactly as before. Returns\n * `undefined` when there is no `update`, so the server still sees a plain\n * resume.\n */\n #resolveDispatchUpdate(\n update: Record<string, unknown> | [string, unknown][] | undefined,\n prepared: { dispatchInput: unknown; handle: OptimisticHandle } | undefined\n ): Record<string, unknown> | [string, unknown][] | undefined {\n if (prepared != null) {\n return prepared.dispatchInput as Record<string, unknown>;\n }\n if (update == null) return undefined;\n return serializeUpdateMessages(update, this.#messagesKey);\n }\n\n /**\n * Reconcile optimistic state when a run terminates.\n *\n * - Messages: any echoed id still `\"pending\"` (never echoed by the\n * server) is flipped to `\"sent\"` on success/interrupt, or\n * `\"failed\"` on failure/abort. Ids the server already echoed were\n * flipped to `\"sent\"` in {@link #applyValues} and are untouched.\n * - Non-message keys: rolled back to their pre-submit values when no\n * server `values` event landed during the run (otherwise the\n * server snapshot already reconciled them). Skipped on abort,\n * where a superseding run (or `stop()`) owns subsequent state.\n *\n * @param handle - Handle returned by {@link #beginOptimistic}.\n * @param event - Terminal lifecycle event for the run.\n */\n #settleOptimistic(\n handle: OptimisticHandle,\n event: \"completed\" | \"failed\" | \"interrupted\" | \"aborted\"\n ): void {\n const failed = event === \"failed\" || event === \"aborted\";\n this.#messageMetadata.resolvePending(\n handle.echoedIds,\n failed ? \"failed\" : \"sent\"\n );\n if (event !== \"aborted\" && !this.#sawValuesForRun) {\n this.#rootMessages.restoreValueKeys(handle.restoreKeys);\n }\n }\n\n #applyValues(raw: unknown, checkpoint?: CheckpointEnvelope): void {\n if (raw == null || typeof raw !== \"object\" || Array.isArray(raw)) {\n return;\n }\n const state = raw as Record<string, unknown>;\n // A root `values` snapshot landed: optimistic non-message keys are\n // now reconciled against server truth (see #settleOptimistic).\n this.#sawValuesForRun = true;\n /**\n * Surface parent_checkpoint per-message when the values event\n * carries the lightweight checkpoint envelope (populated by\n * `@langchain/langgraph-core`'s `_emitValuesWithCheckpointMeta` and\n * forwarded through `convertToProtocolEvent`). Consumers surface\n * this as `useMessageMetadata(stream, msg.id).parentCheckpointId`\n * for fork / edit flows.\n */\n const parentCheckpointId = checkpoint?.parent_id;\n if (parentCheckpointId != null && Array.isArray(state[this.#messagesKey])) {\n this.#messageMetadata.recordMessages(\n state[this.#messagesKey] as Array<{ id?: string }>,\n { parentCheckpointId }\n );\n }\n const maybeMessages = state[this.#messagesKey];\n let nextValues: StateType;\n let nextMessages: BaseMessage[];\n if (Array.isArray(maybeMessages)) {\n const coerced = ensureMessageInstances(\n maybeMessages as (Message | BaseMessage)[]\n );\n nextValues = {\n ...(state as StateType),\n [this.#messagesKey]: coerced,\n } as StateType;\n nextMessages = coerced;\n } else {\n nextValues = state as StateType;\n nextMessages = [];\n }\n this.#rootMessages.applyValues(nextValues, nextMessages, {\n step: checkpoint?.step,\n });\n if (nextMessages.length > 0) {\n // Any optimistic message the server just echoed is now\n // server-authoritative: flip its status `pending` → `sent`.\n this.#messageMetadata.resolvePending(\n nextMessages\n .map((m) => m.id)\n .filter((id): id is string => typeof id === \"string\"),\n \"sent\"\n );\n this.rootStore.setState((s) => {\n const toolCalls = reconcileToolCallsFromMessages(\n s.toolCalls,\n nextMessages\n );\n if (toolCalls === s.toolCalls) return s;\n return { ...s, toolCalls };\n });\n }\n }\n\n /**\n * Mirror protocol interrupts (any namespace) into the root snapshot.\n *\n * This can be called from both the wildcard lifecycle/input watcher and the\n * root content pump. Store-level dedup keeps the user-facing list stable.\n */\n #recordInterrupt(event: Event): void {\n if (event.method !== \"input.requested\") return;\n const data = event.params.data as {\n interrupt_id?: string;\n payload?: unknown;\n };\n const interruptId = data?.interrupt_id;\n if (typeof interruptId !== \"string\") {\n return;\n }\n // Before a run command is accepted, accept only ids the hydrated\n // state reported as active. After acceptance, the command response's\n // `applied_through_seq` separates replayed history from live events:\n // unknown ids at or below the barrier are stale, while newer ids are\n // interrupts raised by the new run.\n const eventSeq = typeof event.seq === \"number\" ? event.seq : undefined;\n // Locally-resolved ids: still drop historical replay, but accept a\n // live reappearance (server still pending after sequential\n // multi-interrupt resume, or the same interrupt site re-raised).\n if (this.#resolvedInterrupts.has(interruptId)) {\n const isLiveReappearance =\n this.#hydratedActiveInterruptIds == null ||\n (typeof this.#interruptReplayThroughSeq === \"number\" &&\n eventSeq != null &&\n eventSeq > this.#interruptReplayThroughSeq);\n if (!isLiveReappearance) {\n return;\n }\n this.#resolvedInterrupts.delete(interruptId);\n }\n const isUnknownInterrupt =\n this.#hydratedActiveInterruptIds != null &&\n !this.#hydratedActiveInterruptIds.has(interruptId);\n if (isUnknownInterrupt && this.#interruptCommandPending) {\n this.#pendingInterruptEvents.push(event);\n return;\n }\n const barrier = this.#interruptReplayThroughSeq;\n if (isUnknownInterrupt && barrier == null) {\n this.#pendingHydrationInterruptEvents.push(event);\n return;\n }\n const isHistoricalUnknownInterrupt =\n isUnknownInterrupt &&\n barrier != null &&\n eventSeq != null &&\n eventSeq <= barrier;\n if (isHistoricalUnknownInterrupt) {\n return;\n }\n const namespace = Array.isArray(event.params.namespace)\n ? [...event.params.namespace]\n : [...ROOT_NAMESPACE];\n const interrupt: Interrupt<InterruptType> = normalizeInterruptForClient({\n id: interruptId,\n value: data.payload as InterruptType,\n namespace,\n });\n this.rootStore.setState((s) => {\n if (s.interrupts.some((entry) => entry.id === interruptId)) return s;\n const interrupts = [...s.interrupts, interrupt];\n return { ...s, interrupts, interrupt: interrupts[0] };\n });\n }\n\n /**\n * Convert the hydrate-time allowlist into a replay barrier after a command\n * is accepted. Built-in transports update `lastAppliedThroughSeq` from the\n * command response before resolving `submitRun` / `respondInput`.\n */\n #advanceInterruptReplayBarrier(): void {\n if (this.#hydratedActiveInterruptIds == null) {\n this.#discardPendingInterruptEvents();\n return;\n }\n const throughSeq = this.#thread?.ordering?.lastAppliedThroughSeq;\n if (typeof throughSeq === \"number\") {\n this.#interruptReplayThroughSeq = throughSeq;\n } else {\n // Custom transports may not implement sequence metadata. Preserve the\n // previous behavior so their genuinely new interrupts are not dropped.\n this.#hydratedActiveInterruptIds = null;\n this.#interruptReplayThroughSeq = undefined;\n }\n this.#interruptCommandPending = false;\n const pendingEvents = this.#pendingInterruptEvents;\n this.#pendingInterruptEvents = [];\n for (const event of pendingEvents) {\n this.#recordInterrupt(event);\n }\n }\n\n #discardPendingInterruptEvents(): void {\n this.#interruptCommandPending = false;\n this.#pendingInterruptEvents = [];\n }\n\n /**\n * Resolve the protocol namespace for a targeted resume.\n *\n * Prefer an explicit caller-supplied namespace, then the matching\n * {@link ThreadStream.interrupts} entry, then the UI mirror on\n * `rootStore.interrupts`, finally root (`[]`).\n */\n #resolveNamespaceForInterruptId(\n interruptId: string,\n explicitNamespace?: string[]\n ): string[] {\n if (explicitNamespace != null) return [...explicitNamespace];\n const fromThread = this.#thread?.interrupts.find(\n (entry) => entry.interruptId === interruptId\n )?.namespace;\n if (fromThread != null) return [...fromThread];\n const fromRoot = this.rootStore\n .getSnapshot()\n .interrupts.find((entry) => entry.id === interruptId)?.namespace;\n if (fromRoot != null) return [...fromRoot];\n return [...ROOT_NAMESPACE];\n }\n\n /**\n * Mark an interrupt resolved for historical-replay filtering and\n * mirror the removal into the root snapshot the framework hooks read.\n *\n * Tombstones are not permanent: a live `input.requested` after the\n * resume barrier clears the id when the same interrupt is raised again.\n */\n #markInterruptResolvedInRootStore(interruptId: string): void {\n this.#resolvedInterrupts.add(interruptId);\n this.rootStore.setState((s) => {\n const interrupts = s.interrupts.filter(\n (entry) => entry.id !== interruptId\n );\n if (\n interrupts.length === s.interrupts.length &&\n s.interrupt?.id !== interruptId\n ) {\n return s;\n }\n return {\n ...s,\n interrupts,\n interrupt: interrupts[0],\n };\n });\n }\n\n /**\n * Re-sync `rootStore.interrupts` from the server's authoritative\n * `state.tasks[].interrupts` after a resumed run settles.\n *\n * Sequential `respond()` of parallel interrupts optimistically clears\n * each targeted id client-side. The server checkpoint can continue to\n * list the original interrupt batch after accepting a partial response,\n * so locally-resolved ids remain filtered while untouched siblings are\n * restored. This keeps `stream.interrupts` truthful without re-exposing\n * an already-consumed interrupt.\n *\n * Uses the same transport-aware state fetch as {@link hydrate}, and\n * drops the result if the thread swapped or a new submit/respond\n * started while the fetch was in flight.\n */\n async #reconcilePendingInterruptsFromServer(): Promise<ThreadState<StateType> | null> {\n const threadId = this.#currentThreadId;\n if (threadId == null || this.#disposed) return null;\n const generationAtFetch = this.#submitGeneration;\n try {\n const state = await this.#fetchHydrationState();\n if (\n this.#disposed ||\n this.#currentThreadId !== threadId ||\n this.#submitGeneration !== generationAtFetch\n ) {\n return null;\n }\n if (!Array.isArray(state?.tasks)) return null;\n const { activeInterrupts, activeIds } =\n collectActiveInterruptsFromTasks<InterruptType>(state.tasks);\n const pendingInterrupts = activeInterrupts.filter(\n (interrupt) =>\n interrupt.id == null || !this.#resolvedInterrupts.has(interrupt.id)\n );\n this.rootStore.setState((s) => ({\n ...s,\n interrupts: pendingInterrupts,\n interrupt: pendingInterrupts[0],\n }));\n this.#hydratedActiveInterruptIds = activeIds;\n return state;\n } catch {\n /* best-effort — leave the optimistic interrupt list alone */\n return null;\n }\n }\n\n #settleParkedInterruptsOnTerminal(event: Event): void {\n if (this.#pendingHydrationInterruptEvents.length === 0) return;\n if (event.method !== \"lifecycle\") return;\n if (!isRootNamespace(event.params.namespace)) return;\n const status = (event as LifecycleEvent).params.data?.event;\n if (\n status !== \"interrupted\" &&\n status !== \"completed\" &&\n status !== \"failed\"\n ) {\n return;\n }\n void this.#settleParkedInterrupts();\n }\n\n /**\n * Decide parked interrupts with server state instead of a stream marker.\n *\n * After a passive rejoin the stream cannot tell a replayed, already\n * resolved `input.requested` from one the current run just raised: the\n * SSE replays the thread buffer on connect with no marker for where the\n * replay ends. `state.tasks[].interrupts` is authoritative: parked ids it\n * lists are live, the rest are history.\n */\n async #settleParkedInterrupts(): Promise<void> {\n const makePromise = async () => {\n try {\n const threadId = this.#currentThreadId;\n const generation = this.#submitGeneration;\n const deadline = Date.now() + PARKED_INTERRUPT_SETTLE_MS;\n for (;;) {\n if (\n this.#disposed ||\n this.#currentThreadId !== threadId ||\n this.#submitGeneration !== generation ||\n this.#pendingHydrationInterruptEvents.length === 0\n ) {\n return;\n }\n const parkedIds = new Set(\n this.#pendingHydrationInterruptEvents.map(\n (event) =>\n (event.params.data as { interrupt_id?: string }).interrupt_id\n )\n );\n // A null state is a failed or unusable fetch; the terminal that\n // started this loop will not come again, so keep trying until the\n // deadline rather than stranding the parked interrupts.\n const state = await this.#reconcilePendingInterruptsFromServer();\n if (state != null) {\n const settled = [...(this.#hydratedActiveInterruptIds ?? [])].some(\n (id) => parkedIds.has(id)\n );\n if (settled || !isThreadStateActive(state)) {\n this.#pendingHydrationInterruptEvents = [];\n return;\n }\n }\n if (Date.now() >= deadline) return;\n await new Promise<void>((resolve) => {\n setTimeout(resolve, PARKED_INTERRUPT_SETTLE_POLL_MS);\n });\n }\n } finally {\n this.#settleParkedInterruptsPromise = undefined;\n }\n };\n this.#settleParkedInterruptsPromise ??= makePromise();\n return this.#settleParkedInterruptsPromise;\n }\n\n /**\n * Resolve on the next root-namespace terminal lifecycle event\n * (`completed` / `failed` / `interrupted`) or on abort.\n *\n * Attaches to the controller's root event bus instead of opening\n * a second server subscription. Callers should register the\n * returned promise **before** dispatching the command that\n * triggers the run (`thread.run.start` / `thread.input.respond`)\n * — the root pump fans events out synchronously on arrival, so a\n * late registration would miss the terminal for fast runs.\n *\n * @param signal - Abort signal for the local submit lifecycle.\n */\n #awaitNextTerminal(signal: AbortSignal): Promise<{\n event: \"completed\" | \"failed\" | \"interrupted\" | \"aborted\";\n error?: string;\n }> {\n return this.#awaitRootTerminal(signal, {\n skipInterruptedUntilRunning: false,\n });\n }\n\n /**\n * Resolve on the resumed run's root terminal lifecycle.\n *\n * Unlike {@link #awaitNextTerminal}, ignores `interrupted` events until a\n * root `running` lifecycle has been observed. Headless-tool flows can emit\n * a stale `interrupted` for the run being resumed after `input.requested`\n * but before `respondInput` calls `#prepareForNextRun`; accepting that\n * terminal would unsubscribe the watcher before the resumed run's `failed`\n * terminal arrives.\n *\n * On `interrupted` / `completed`, reconciles pending interrupts from\n * server state so optimistic clears from {@link respond} cannot leave\n * `stream.interrupts` empty while the checkpoint still has siblings.\n */\n async #awaitResumedRunTerminal(signal: AbortSignal): Promise<{\n event: \"completed\" | \"failed\" | \"interrupted\" | \"aborted\";\n error?: string;\n }> {\n const terminal = await this.#awaitRootTerminal(signal, {\n skipInterruptedUntilRunning: true,\n });\n if (\n !signal.aborted &&\n !this.#disposed &&\n (terminal.event === \"interrupted\" || terminal.event === \"completed\")\n ) {\n await this.#reconcilePendingInterruptsFromServer();\n }\n return terminal;\n }\n\n #awaitRootTerminal(\n signal: AbortSignal,\n options: { skipInterruptedUntilRunning: boolean }\n ): Promise<{\n event: \"completed\" | \"failed\" | \"interrupted\" | \"aborted\";\n error?: string;\n }> {\n return new Promise((resolve) => {\n let settled = false;\n let sawRunning = false;\n const held: Event[] = [];\n const heldReleases = this.#heldLifecycleReleases;\n function finish(result: {\n event: \"completed\" | \"failed\" | \"interrupted\" | \"aborted\";\n error?: string;\n }) {\n if (settled) return;\n settled = true;\n heldReleases.delete(releaseHeld);\n unsubscribeRoot?.();\n unsubscribeThread?.();\n unsubscribeError?.();\n signal.removeEventListener(\"abort\", finishAborted);\n resolve(result);\n }\n const finishAborted = () => finish({ event: \"aborted\" });\n const onEvent = (event: Event) => {\n if (settled) return;\n if (event.method !== \"lifecycle\") return;\n if (!isRootNamespace(event.params.namespace)) return;\n const match = this.#submittedRunMatch(event);\n if (match === \"other\") return;\n if (match === \"pending\") {\n held.push(event);\n return;\n }\n const lifecycle = (event as LifecycleEvent).params.data as {\n event?: string;\n error?: string;\n };\n if (lifecycle?.event === \"running\") {\n sawRunning = true;\n return;\n }\n if (lifecycle?.event === \"completed\") {\n setTimeout(() => finish({ event: \"completed\" }), 0);\n } else if (lifecycle?.event === \"failed\") {\n setTimeout(\n () => finish({ event: \"failed\", error: lifecycle.error }),\n 0\n );\n } else if (lifecycle?.event === \"interrupted\") {\n if (options.skipInterruptedUntilRunning && !sawRunning) {\n return;\n }\n setTimeout(() => finish({ event: \"interrupted\" }), 0);\n }\n };\n const releaseHeld = () => {\n for (const event of held.splice(0)) onEvent(event);\n };\n heldReleases.add(releaseHeld);\n const unsubscribeRoot = this.#rootBus.subscribe(onEvent);\n const unsubscribeThread = this.#thread?.onEvent(onEvent);\n const unsubscribeError = this.#thread?.onError((error) =>\n finish({ event: \"failed\", error: error.message })\n );\n if (signal.aborted) {\n finishAborted();\n } else {\n signal.addEventListener(\"abort\", finishAborted, { once: true });\n }\n });\n }\n\n /**\n * Resolve which protocol interrupt a resume command should target.\n * Headless-tool resumes are keyed by tool-call id; without matching\n * on that id, parallel tool handlers would respond to the wrong\n * interrupt (always the newest).\n */\n #resolveInterruptForResume(resume?: unknown): ResolvedInterrupt | null {\n const thread = this.#thread;\n if (thread == null) return null;\n return resolveInterruptTargetForHeadlessResume(\n resume,\n thread.interrupts,\n this.#resolvedInterrupts\n );\n }\n\n /**\n * Notify listeners that the underlying thread stream changed.\n */\n #notifyThreadListeners(): void {\n for (const listener of this.#threadListeners) listener(this.#thread);\n }\n}\n\n// ---------- helpers ----------\n\n/**\n * True when a subagent still sits on its default `tools:<toolCallId>`\n * namespace — i.e. no execution namespace has been observed (via SSE\n * replay) or resolved (via history) yet. Used to gate lazy namespace\n * resolution so already-promoted subagents aren't re-fetched.\n */\nfunction namespaceIsDefaultOnly(\n entry: SubagentDiscoverySnapshot | undefined\n): boolean {\n if (entry == null) return false;\n return (\n entry.namespace.length === 1 && entry.namespace[0] === `tools:${entry.id}`\n );\n}\n\nfunction defaultSubagentToolCallId(\n namespace: readonly string[]\n): string | undefined {\n if (namespace.length !== 1) return undefined;\n const segment = namespace[0];\n if (!segment.startsWith(\"tools:\")) return undefined;\n const id = segment.slice(\"tools:\".length);\n return id.length > 0 ? id : undefined;\n}\n\n/**\n * Extract and coerce the configured messages key from a values object.\n *\n * @param values - State values object to read from.\n * @param messagesKey - Key that contains the message array.\n */\nfunction extractAndCoerceMessages(\n values: Record<string, unknown>,\n messagesKey: string\n): BaseMessage[] {\n const raw = values[messagesKey];\n if (!Array.isArray(raw)) return [];\n return ensureMessageInstances(\n raw as (Message | BaseMessage)[]\n ) as BaseMessage[];\n}\n\nfunction extractAndCoerceMessagesWithFallback(\n values: Record<string, unknown>,\n messagesKey: string\n): BaseMessage[] | null {\n let raw = values[messagesKey];\n if (!Array.isArray(raw) && messagesKey !== DEFAULT_MESSAGES_KEY) {\n raw = values[DEFAULT_MESSAGES_KEY];\n }\n if (!Array.isArray(raw)) return null;\n return ensureMessageInstances(\n raw as (Message | BaseMessage)[]\n ) as BaseMessage[];\n}\n\n/**\n * Collect pending interrupts from a `threads.getState()` `tasks` array.\n *\n * Shared by {@link StreamController.hydrate} and the post-resume\n * reconcile path so both stay aligned on namespace derivation and\n * id dedupe.\n */\nfunction collectActiveInterruptsFromTasks<InterruptType>(tasks: unknown[]): {\n activeInterrupts: Interrupt<InterruptType>[];\n activeIds: Set<string>;\n} {\n const activeInterrupts: Interrupt<InterruptType>[] = [];\n const activeIds = new Set<string>();\n for (const task of tasks) {\n if (!Array.isArray((task as { interrupts?: unknown } | null)?.interrupts)) {\n continue;\n }\n const typedTask = task as {\n interrupts: unknown[];\n checkpoint?: { checkpoint_ns?: unknown } | null;\n };\n const checkpointNs = typedTask.checkpoint?.checkpoint_ns;\n const namespace =\n typeof checkpointNs === \"string\" && checkpointNs.length > 0\n ? checkpointNs.split(\"|\").filter((segment) => segment.length > 0)\n : [...ROOT_NAMESPACE];\n for (const interrupt of typedTask.interrupts) {\n const typed = interrupt as\n | { id?: string; value?: unknown; namespace?: string[] }\n | null\n | undefined;\n const id = typed?.id;\n if (typeof id !== \"string\" || activeIds.has(id)) continue;\n activeIds.add(id);\n activeInterrupts.push(\n normalizeInterruptForClient({\n id,\n value: typed?.value as InterruptType,\n namespace: Array.isArray(typed?.namespace)\n ? [...typed.namespace]\n : namespace,\n })\n );\n }\n }\n return { activeInterrupts, activeIds };\n}\n\n// Unused import guard — `AIMessage` is only referenced by type tests.\nvoid AIMessage;\n\n/**\n * Run id from a `synth:<run_id>:...` event id, the form the agent server\n * uses for events it synthesizes such as root `lifecycle`. Events carry no\n * run id field.\n */\nfunction synthesizedEventRunId(\n eventId: string | undefined\n): string | undefined {\n if (eventId == null || !eventId.startsWith(\"synth:\")) return undefined;\n return eventId.split(\":\")[1] || undefined;\n}\n"],"mappings":"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"}