@langchain/vue 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -149,7 +149,8 @@ function useStream(options) {
149
149
  submit: (input, submitOptions) => controller.submit(input, submitOptions),
150
150
  stop: (options) => controller.stop(options),
151
151
  disconnect: () => controller.disconnect(),
152
- respond: (response, target) => controller.respond(response, target),
152
+ respond: (response, options) => controller.respond(response, options),
153
+ respondAll: (responsesById, options) => controller.respondAll(responsesById, options),
153
154
  getThread: () => controller.getThread(),
154
155
  client,
155
156
  assistantId,
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.cjs","names":["LANGCHAIN_OPTIONS","ClientCtor","StreamController"],"sources":["../src/use-stream.ts"],"sourcesContent":["import {\n computed,\n onScopeDispose,\n readonly,\n shallowRef,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from \"vue\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n filterOutHeadlessToolInterrupts,\n flushPendingHeadlessToolInterrupts,\n scheduleCoalescedHeadlessToolFlush,\n type AnyHeadlessToolImplementation,\n type OnToolCallback,\n} from \"@langchain/langgraph-sdk\";\nimport {\n Client as ClientCtor,\n type ClientConfig,\n type ThreadStream,\n} from \"@langchain/langgraph-sdk/client\";\nimport {\n StreamController,\n type AgentServerAdapter,\n type AgentServerOptions as StreamAgentServerOptions,\n type ChannelRegistry,\n type CustomAdapterOptions as StreamCustomAdapterOptions,\n type InferStateType,\n type InferSubagentStates,\n type InferToolCalls,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\n type StreamStopOptions,\n type StreamSubmitOptions,\n type SubagentDiscoverySnapshot,\n type SubagentMap,\n type SubgraphByNodeMap,\n type SubgraphDiscoverySnapshot,\n type SubgraphMap,\n type UseStreamOptions as StreamUseStreamOptions,\n type WidenUpdateMessages,\n} from \"@langchain/langgraph-sdk/stream\";\nimport { inject } from \"vue\";\nimport { LANGCHAIN_OPTIONS } from \"./context.js\";\n\ntype VueThreadId = MaybeRefOrGetter<string | null | undefined>;\ntype VueApiString = MaybeRefOrGetter<string | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, VueThreadId, VueApiString, VueApiString>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, VueThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n VueThreadId,\n VueApiString,\n VueApiString,\n string\n>;\n\n/**\n * Private field on the handle that carries the {@link StreamController}\n * reference. Selector composables read this to reach the shared\n * {@link ChannelRegistry}. Use the selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, …) instead of reading this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/vue/controller\"\n);\n\n/**\n * Vue binding return type for {@link useStream}.\n *\n * Reactive primitives follow Vue conventions:\n *\n * - Data projections are `Readonly<ShallowRef<T>>` / `ComputedRef<T>`\n * so templates auto-unwrap via `msg.value` in `<script setup>`\n * and directly in templates. They are snapshots — never mutate.\n * - Imperative methods (`submit` / `stop` / `respond`) are plain\n * functions — no refs involved.\n * - Identity values captured at setup time (`client` / `assistantId`)\n * are exposed as plain values; if you need to swap the bound agent\n * or client, remount the composable.\n */\nexport interface UseStreamReturn<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n StateType extends object = InferStateType<T>,\n SubagentStates = InferSubagentStates<T>,\n> {\n // ----- always-on root projections -----\n /**\n * The most recent `values`-channel snapshot emitted at the root\n * namespace — i.e. the thread-level state as the server sees it\n * after each superstep. Updated on every root `values` event, not\n * on token-level deltas: if you render `stream.values.value.messages`\n * directly you'll see full turns appear at once instead of\n * streaming token-by-token. Use {@link messages} (or\n * `useMessages`) for the token-streamed view.\n *\n * Equivalent to calling `useValues(stream)`.\n */\n readonly values: Readonly<ShallowRef<StateType>>;\n /**\n * The root message projection. Assembled from two sources and\n * merged in real time:\n *\n * 1. `messages`-channel deltas — token-level streaming events\n * (`message-start`, `content-block-delta`, `message-finish`)\n * emitted by the runtime. These drive live, token-by-token\n * updates.\n * 2. `values.messages` snapshots — the authoritative ordering\n * and any messages the agent produces without token streaming\n * (human turns, tool results, echoes from subagents).\n *\n * If the backend only emits `values` events (no `messages`\n * channel), every message will appear fully-formed on each\n * values update rather than streaming. This is a backend/runtime\n * concern — the Vue layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: Readonly<ShallowRef<BaseMessage[]>>;\n /**\n * Root-namespace tool calls assembled from the `tools` channel.\n * Each entry is a fully parsed {@link AssembledToolCall} with\n * name, args, and id — suitable for rendering approval UIs or\n * forwarding to headless tool handlers.\n *\n * When the stream is typed with an agent brand or tool list,\n * entries are narrowed via {@link InferToolCalls}. Equivalent to\n * calling `useToolCalls(stream)` with no target.\n */\n readonly toolCalls: Readonly<ShallowRef<InferToolCalls<T>[]>>;\n /**\n * All unresolved protocol interrupts observed on the root\n * namespace during the active thread. Populated from lifecycle /\n * input events and seeded on hydration from `thread.getState()`.\n * Cleared optimistically when a new run starts or an interrupt is\n * resolved via {@link respond} / `submit({ command: { resume } })`.\n */\n readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;\n /**\n * Convenience alias for {@link interrupts}[0] — the primary\n * interrupt most UIs should act on when only one is pending.\n * `undefined` when no interrupt is active.\n */\n readonly interrupt: ComputedRef<Interrupt<InterruptType> | undefined>;\n /**\n * `true` while a run is active or being started on the current\n * thread. Driven by root-namespace lifecycle events (`running` →\n * `true`, terminal phases → `false`). Use this to disable submit\n * buttons and show in-flight spinners.\n */\n readonly isLoading: ComputedRef<boolean>;\n /**\n * `true` while the initial `thread.getState()` hydration for the\n * active thread is in flight. Distinct from {@link isLoading} —\n * thread loading covers the one-time fetch that seeds\n * {@link values} / {@link messages} before any user submit.\n */\n readonly isThreadLoading: ComputedRef<boolean>;\n /**\n * The last error observed on the active run or hydration attempt.\n * `undefined` when no error has occurred. Cleared optimistically\n * when a new {@link submit} starts.\n */\n readonly error: ComputedRef<unknown>;\n /**\n * Id of the thread the controller is bound to. `null` until the\n * first {@link submit} creates or selects a thread (or until an\n * explicit `threadId` option is provided and hydrated).\n */\n readonly threadId: ComputedRef<string | null>;\n /**\n * Promise that settles when the active thread's initial hydration\n * completes. Exposed so `async setup()` sites can\n * `await stream.hydrationPromise.value` to implement a\n * Suspense-like boundary. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: ComputedRef<Promise<void>>;\n\n // ----- always-on discovery -----\n /**\n * Subagents discovered on the root run. For DeepAgent-typed\n * streams the key set is narrowed to the subagent names declared\n * on the agent brand (`keyof InferSubagentStates<T>`).\n */\n readonly subagents: Readonly<\n ShallowRef<\n ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >\n >\n >;\n /**\n * Subgraphs discovered on the root run.\n *\n * A namespace is classified as a subgraph iff at least one\n * strictly-deeper namespace has been observed with it as a prefix.\n * This is inferred from the lifecycle event stream — plain function\n * nodes (`orchestrator`, `writer` in the nested-stategraph example)\n * never appear here even though the server emits namespaced\n * lifecycle events for them. Promotion is monotonic and retroactive;\n * an entry appears as soon as the first descendant event lands.\n */\n readonly subgraphs: Readonly<\n ShallowRef<ReadonlyMap<string, SubgraphDiscoverySnapshot>>\n >;\n /**\n * Subgraphs indexed by the graph node that produced them\n * (`addNode(\"visualizer_0\", …)`). Each value is an array because\n * parallel fan-outs and loops can spawn multiple invocations of\n * the same node; arrays preserve insertion order. Updates in\n * lock-step with {@link subgraphs}.\n */\n readonly subgraphsByNode: Readonly<\n ShallowRef<ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>>\n >;\n\n // ----- imperatives -----\n /**\n * Dispatch a new run on the bound thread.\n *\n * `input` is typed as `Partial<StateType>` so IDE autocompletion\n * surfaces the state keys declared on the root composable. Pass\n * `null` (or omit fields) when resuming an interrupt via\n * `options.command.resume` — the server accepts a null payload\n * in that case.\n */\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n /**\n * Stop the active run on the current thread. By default cancels the\n * run server-side and disconnects the client; pass `{ cancel: false }`\n * or use {@link disconnect} for join/rejoin. Sets {@link isLoading} to\n * `false` immediately; {@link values} and {@link messages} are preserved.\n */\n stop(options?: StreamStopOptions): Promise<void>;\n /**\n * Disconnect the client without cancelling the run server-side.\n * Alias for `stop({ cancel: false })`.\n */\n disconnect(): Promise<void>;\n /**\n * Resume a pending protocol interrupt by sending a response payload\n * back to the interrupted namespace.\n *\n * When `target` is omitted, responds to the latest unresolved\n * interrupt in {@link interrupts}. Pass an explicit\n * `{ interruptId, namespace? }` when multiple interrupts are\n * pending or the interrupt lives in a subgraph namespace.\n */\n respond(\n response: unknown,\n target?: { interruptId: string; namespace?: string[] }\n ): Promise<void>;\n\n // ----- identity -----\n /** LangGraph SDK client used to construct thread streams. */\n readonly client: Client;\n /** Assistant id the thread is bound to for its lifetime. */\n readonly assistantId: string;\n\n /**\n * Returns the bound {@link ThreadStream}, if one exists (`undefined`\n * until the thread is hydrated or the first submit completes). Prefer\n * the projections and selector composables for UI work; use this for\n * low-level protocol access (raw subscriptions, state commands, etc.).\n */\n getThread(): ThreadStream | undefined;\n\n /** @internal Used by selector composables. */\n readonly [STREAM_CONTROLLER]: StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >;\n}\n\n/**\n * Erased handle useful as a parameter type for helpers and wrapper\n * components that pass a `stream` through to selector composables\n * without reading `values` directly. Mirrors the React\n * `AnyStream` alias.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyStream = UseStreamReturn<any, any, any>;\n\n/** Convenience alias for the fully-resolved stream handle type. */\nexport type UseStreamResult<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n> = UseStreamReturn<T, InterruptType, ConfigurableType>;\n\n/**\n * Vue Composition API binding for the v2-native stream runtime.\n *\n * Returns a handle whose projections are Vue refs so templates\n * auto-unwrap and scripts can feed them into `computed`/`watch`.\n * Scoped views (subagents, subgraphs, any namespaced projection) are\n * surfaced via the companion selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, `useMessageMetadata`,\n * `useSubmissionQueue`, `useExtension`, `useChannel`, plus media\n * composables).\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useStream } from \"@langchain/vue\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"msg in stream.messages.value\" :key=\"msg.id\">\n * {{ msg.content }}\n * </div>\n * <button @click=\"stream.submit({ messages: [{ type: 'human', content: 'Hi' }] })\">\n * Send\n * </button>\n * </template>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at setup time.\n * To bind a new assistant/transport, remount the component. Reactive\n * inputs (`threadId`, `apiUrl`, `apiKey`) trigger in-place behaviour\n * changes on the active controller.\n */\nexport function useStream<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n>(\n options: UseStreamOptions<InferStateType<T>>\n): UseStreamReturn<T, InterruptType, ConfigurableType> {\n type StateType = InferStateType<T>;\n\n interface OptionsBag {\n assistantId?: string;\n threadId?: MaybeRefOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: MaybeRefOrGetter<string | undefined>;\n apiKey?: MaybeRefOrGetter<string | undefined>;\n callerOptions?: ClientConfig[\"callerOptions\"];\n defaultHeaders?: ClientConfig[\"defaultHeaders\"];\n transport?: \"sse\" | \"websocket\" | AgentServerAdapter;\n fetch?: typeof fetch;\n webSocketFactory?: (url: string) => WebSocket;\n onThreadId?: (threadId: string) => void;\n onCreated?: (info: RunExecutionInfo) => void;\n onCompleted?: (info: RunCompletedInfo) => void;\n initialValues?: StateType;\n messagesKey?: string;\n tools?: AnyHeadlessToolImplementation[];\n onTool?: OnToolCallback;\n }\n const asBag = options as OptionsBag;\n\n // Inherit missing apiUrl / apiKey / client from any LangChainPlugin\n // installed on the app. Vue's `inject` returns `undefined` if the\n // key was never provided; that's fine — we only merge when the\n // caller didn't set a value.\n const pluginOptions =\n inject(LANGCHAIN_OPTIONS, undefined) ?? ({} as Record<string, unknown>);\n\n const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // ─── Client construction ────────────────────────────────────────────\n //\n // Identity-stable per setup. Watches apiUrl/apiKey refs so callers\n // that flip a backend at runtime get a fresh client without a full\n // remount — the controller is swapped in lock-step below.\n const resolveApiUrl = () =>\n toValue(asBag.apiUrl) ?? (pluginOptions as { apiUrl?: string }).apiUrl;\n const resolveApiKey = () =>\n toValue(asBag.apiKey) ?? (pluginOptions as { apiKey?: string }).apiKey;\n const explicitClient =\n asBag.client ?? (pluginOptions as { client?: Client }).client;\n\n const clientRef = shallowRef<Client>(\n explicitClient ??\n (new ClientCtor({\n apiUrl: resolveApiUrl(),\n apiKey: resolveApiKey(),\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client)\n );\n\n // Note: we intentionally bind the controller to the *initial* client\n // instance. A dynamic client swap would require tearing the\n // controller down (in-flight subscriptions, queue, hydration), so we\n // keep the rule simple: client is captured at setup. Mirrors React\n // v1 which bakes `useMemo` on `[client, assistantId, transport]`.\n const client = clientRef.value;\n\n // Custom adapters may omit `assistantId`; the controller still\n // requires one so it has something to forward to `threads.stream`.\n const sentinel = \"_\";\n const assistantId =\n \"assistantId\" in options ? (options.assistantId ?? sentinel) : sentinel;\n\n const initialThreadId = toValue(asBag.threadId) ?? null;\n\n // ─── Controller construction ────────────────────────────────────────\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n client: client as unknown as Client<StateType>,\n threadId: initialThreadId,\n transport,\n fetch: hasCustomAdapter ? undefined : asBag.fetch,\n webSocketFactory: hasCustomAdapter ? undefined : asBag.webSocketFactory,\n onThreadId: options.onThreadId,\n onCreated: options.onCreated,\n onCompleted: options.onCompleted,\n initialValues: options.initialValues,\n messagesKey: options.messagesKey,\n });\n\n // Deferred dispose: on the next microtask after the owning scope\n // disappears. Mirrors React's StrictMode-safe activate/deactivate\n // pattern — HMR and other scope-reuse scenarios stay clean because\n // `activate()` cancels the pending dispose if the scope survives.\n const deactivate = controller.activate();\n onScopeDispose(deactivate);\n\n // ─── Reactivity adapters — StreamStore → shallowRef ─────────────────\n function bindStore<S>(\n subscribe: (listener: () => void) => () => void,\n getSnapshot: () => S\n ): Readonly<ShallowRef<S>> {\n const ref = shallowRef<S>(getSnapshot());\n const unsubscribe = subscribe(() => {\n ref.value = getSnapshot();\n });\n onScopeDispose(unsubscribe);\n return readonly(ref) as Readonly<ShallowRef<S>>;\n }\n\n const rootRef = bindStore<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.subscribe,\n controller.rootStore.getSnapshot\n );\n const subagentRef = bindStore<SubagentMap>(\n controller.subagentStore.subscribe,\n controller.subagentStore.getSnapshot\n );\n const subgraphRef = bindStore<SubgraphMap>(\n controller.subgraphStore.subscribe,\n controller.subgraphStore.getSnapshot\n );\n const subgraphByNodeRef = bindStore<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.subscribe,\n controller.subgraphByNodeStore.getSnapshot\n );\n\n // Derived refs for individual root-snapshot fields. Using computed\n // means templates that read `values.value` only retrigger when the\n // root snapshot's identity actually changes — we can't split further\n // because `StreamStore` fans the whole snapshot out on every update.\n const values = computed(() => rootRef.value.values);\n const messages = computed(() => rootRef.value.messages);\n const toolCalls = computed(\n () => rootRef.value.toolCalls as InferToolCalls<T>[]\n );\n const interrupts = computed(() =>\n filterOutHeadlessToolInterrupts(rootRef.value.interrupts)\n );\n const interrupt = computed(() => interrupts.value[0]);\n const isLoading = computed(() => rootRef.value.isLoading);\n const isThreadLoading = computed(() => rootRef.value.isThreadLoading);\n const error = computed(() => rootRef.value.error);\n const threadId = computed(() => rootRef.value.threadId);\n const hydrationPromise = computed(() => controller.hydrationPromise);\n\n // Expose the derived refs through a `readonly(shallowRef)` shape to\n // match the rest of the public surface. `computed` already gives us\n // read-only semantics but templates type-check more cleanly when the\n // fully-typed return claims `Readonly<ShallowRef<T>>` everywhere.\n // The cast is safe — a ComputedRef<T> is structurally a\n // Readonly<Ref<T>>.\n const asShallow = <V>(c: ComputedRef<V>): Readonly<ShallowRef<V>> =>\n c as unknown as Readonly<ShallowRef<V>>;\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Re-hydrate whenever the caller's threadId input changes post-setup.\n // The initial hydrate already fired synchronously in the controller\n // constructor, so we skip that first tick; otherwise we'd double-fetch\n // `thread.state.get()`.\n let skipFirstThreadIdWatch = true;\n watch(\n () => toValue(asBag.threadId) ?? null,\n (next) => {\n if (skipFirstThreadIdWatch) {\n skipFirstThreadIdWatch = false;\n return;\n }\n void controller.hydrate(next);\n }\n );\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch root values + protocol interrupts for items targeting a\n // registered tool, invoke the handler, and resume the run with the\n // handler's return value. Dedup via an id set so StrictMode /\n // rerenders don't replay a tool call twice.\n const handledTools = new Set<string>();\n watch(\n () => toValue(asBag.threadId) ?? null,\n () => handledTools.clear()\n );\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n watch(\n () => [rootRef.value.values, rootRef.value.interrupts] as const,\n () => {\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const rootValues = rootRef.value.values;\n const rootInterrupts = rootRef.value.interrupts;\n const bag = rootValues as unknown as Record<string, unknown>;\n const protocolInterrupts = rootInterrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(bag?.__interrupt__)\n ? (bag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0\n ? protocolInterrupts\n : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...bag, __interrupt__: headlessInterrupts },\n tools,\n handledTools,\n {\n onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n controller.submit(null, {\n command,\n } as StreamSubmitOptions<StateType, ConfigurableType>),\n }\n );\n });\n },\n { immediate: true }\n );\n }\n\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n values: asShallow(values) as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"values\"],\n messages: asShallow(messages),\n toolCalls: asShallow(toolCalls),\n interrupts: asShallow(interrupts),\n interrupt,\n isLoading,\n isThreadLoading,\n error,\n threadId,\n hydrationPromise,\n subagents: subagentRef as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"],\n subgraphs: subgraphRef,\n subgraphsByNode: subgraphByNodeRef,\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: (options) => controller.stop(options),\n disconnect: () => controller.disconnect(),\n respond: (response, target) => controller.respond(response, target),\n getThread: () => controller.getThread(),\n client,\n assistantId,\n [STREAM_CONTROLLER]: controller,\n };\n\n return handle;\n}\n\n/**\n * Helper used by the selector composables to reach the underlying\n * {@link ChannelRegistry} from a stream handle. Kept internal —\n * application code should call `useMessages`, `useToolCalls`, etc.\n *\n * @internal\n */\nexport function getRegistry(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream: UseStreamReturn<any, any, any>\n): ChannelRegistry {\n return stream[STREAM_CONTROLLER].registry;\n}\n\nexport type { ThreadStream };\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-stream.cjs","names":["LANGCHAIN_OPTIONS","ClientCtor","StreamController"],"sources":["../src/use-stream.ts"],"sourcesContent":["import {\n computed,\n onScopeDispose,\n readonly,\n shallowRef,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from \"vue\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n filterOutHeadlessToolInterrupts,\n flushPendingHeadlessToolInterrupts,\n scheduleCoalescedHeadlessToolFlush,\n type AnyHeadlessToolImplementation,\n type OnToolCallback,\n} from \"@langchain/langgraph-sdk\";\nimport {\n Client as ClientCtor,\n type ClientConfig,\n type ThreadStream,\n} from \"@langchain/langgraph-sdk/client\";\nimport {\n StreamController,\n type AgentServerAdapter,\n type AgentServerOptions as StreamAgentServerOptions,\n type ChannelRegistry,\n type CustomAdapterOptions as StreamCustomAdapterOptions,\n type InferStateType,\n type InferSubagentStates,\n type InferToolCalls,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\n type StreamRespondAllOptions,\n type StreamRespondOptions,\n type StreamStopOptions,\n type StreamSubmitOptions,\n type SubagentDiscoverySnapshot,\n type SubagentMap,\n type SubgraphByNodeMap,\n type SubgraphDiscoverySnapshot,\n type SubgraphMap,\n type UseStreamOptions as StreamUseStreamOptions,\n type WidenUpdateMessages,\n} from \"@langchain/langgraph-sdk/stream\";\nimport { inject } from \"vue\";\nimport { LANGCHAIN_OPTIONS } from \"./context.js\";\n\ntype VueThreadId = MaybeRefOrGetter<string | null | undefined>;\ntype VueApiString = MaybeRefOrGetter<string | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, VueThreadId, VueApiString, VueApiString>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, VueThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n VueThreadId,\n VueApiString,\n VueApiString,\n string\n>;\n\n/**\n * Private field on the handle that carries the {@link StreamController}\n * reference. Selector composables read this to reach the shared\n * {@link ChannelRegistry}. Use the selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, …) instead of reading this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/vue/controller\"\n);\n\n/**\n * Vue binding return type for {@link useStream}.\n *\n * Reactive primitives follow Vue conventions:\n *\n * - Data projections are `Readonly<ShallowRef<T>>` / `ComputedRef<T>`\n * so templates auto-unwrap via `msg.value` in `<script setup>`\n * and directly in templates. They are snapshots — never mutate.\n * - Imperative methods (`submit` / `stop` / `respond`) are plain\n * functions — no refs involved.\n * - Identity values captured at setup time (`client` / `assistantId`)\n * are exposed as plain values; if you need to swap the bound agent\n * or client, remount the composable.\n */\nexport interface UseStreamReturn<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n StateType extends object = InferStateType<T>,\n SubagentStates = InferSubagentStates<T>,\n> {\n // ----- always-on root projections -----\n /**\n * The most recent `values`-channel snapshot emitted at the root\n * namespace — i.e. the thread-level state as the server sees it\n * after each superstep. Updated on every root `values` event, not\n * on token-level deltas: if you render `stream.values.value.messages`\n * directly you'll see full turns appear at once instead of\n * streaming token-by-token. Use {@link messages} (or\n * `useMessages`) for the token-streamed view.\n *\n * Equivalent to calling `useValues(stream)`.\n */\n readonly values: Readonly<ShallowRef<StateType>>;\n /**\n * The root message projection. Assembled from two sources and\n * merged in real time:\n *\n * 1. `messages`-channel deltas — token-level streaming events\n * (`message-start`, `content-block-delta`, `message-finish`)\n * emitted by the runtime. These drive live, token-by-token\n * updates.\n * 2. `values.messages` snapshots — the authoritative ordering\n * and any messages the agent produces without token streaming\n * (human turns, tool results, echoes from subagents).\n *\n * If the backend only emits `values` events (no `messages`\n * channel), every message will appear fully-formed on each\n * values update rather than streaming. This is a backend/runtime\n * concern — the Vue layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: Readonly<ShallowRef<BaseMessage[]>>;\n /**\n * Root-namespace tool calls assembled from the `tools` channel.\n * Each entry is a fully parsed {@link AssembledToolCall} with\n * name, args, and id — suitable for rendering approval UIs or\n * forwarding to headless tool handlers.\n *\n * When the stream is typed with an agent brand or tool list,\n * entries are narrowed via {@link InferToolCalls}. Equivalent to\n * calling `useToolCalls(stream)` with no target.\n */\n readonly toolCalls: Readonly<ShallowRef<InferToolCalls<T>[]>>;\n /**\n * All unresolved protocol interrupts observed on the root\n * namespace during the active thread. Populated from lifecycle /\n * input events and seeded on hydration from `thread.getState()`.\n * Cleared optimistically when a new run starts or an interrupt is\n * resolved via {@link respond}.\n */\n readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;\n /**\n * Convenience alias for {@link interrupts}[0] — the primary\n * interrupt most UIs should act on when only one is pending.\n * `undefined` when no interrupt is active.\n */\n readonly interrupt: ComputedRef<Interrupt<InterruptType> | undefined>;\n /**\n * `true` while a run is active or being started on the current\n * thread. Driven by root-namespace lifecycle events (`running` →\n * `true`, terminal phases → `false`). Use this to disable submit\n * buttons and show in-flight spinners.\n */\n readonly isLoading: ComputedRef<boolean>;\n /**\n * `true` while the initial `thread.getState()` hydration for the\n * active thread is in flight. Distinct from {@link isLoading} —\n * thread loading covers the one-time fetch that seeds\n * {@link values} / {@link messages} before any user submit.\n */\n readonly isThreadLoading: ComputedRef<boolean>;\n /**\n * The last error observed on the active run or hydration attempt.\n * `undefined` when no error has occurred. Cleared optimistically\n * when a new {@link submit} starts.\n */\n readonly error: ComputedRef<unknown>;\n /**\n * Id of the thread the controller is bound to. `null` until the\n * first {@link submit} creates or selects a thread (or until an\n * explicit `threadId` option is provided and hydrated).\n */\n readonly threadId: ComputedRef<string | null>;\n /**\n * Promise that settles when the active thread's initial hydration\n * completes. Exposed so `async setup()` sites can\n * `await stream.hydrationPromise.value` to implement a\n * Suspense-like boundary. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: ComputedRef<Promise<void>>;\n\n // ----- always-on discovery -----\n /**\n * Subagents discovered on the root run. For DeepAgent-typed\n * streams the key set is narrowed to the subagent names declared\n * on the agent brand (`keyof InferSubagentStates<T>`).\n */\n readonly subagents: Readonly<\n ShallowRef<\n ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >\n >\n >;\n /**\n * Subgraphs discovered on the root run.\n *\n * A namespace is classified as a subgraph iff at least one\n * strictly-deeper namespace has been observed with it as a prefix.\n * This is inferred from the lifecycle event stream — plain function\n * nodes (`orchestrator`, `writer` in the nested-stategraph example)\n * never appear here even though the server emits namespaced\n * lifecycle events for them. Promotion is monotonic and retroactive;\n * an entry appears as soon as the first descendant event lands.\n */\n readonly subgraphs: Readonly<\n ShallowRef<ReadonlyMap<string, SubgraphDiscoverySnapshot>>\n >;\n /**\n * Subgraphs indexed by the graph node that produced them\n * (`addNode(\"visualizer_0\", …)`). Each value is an array because\n * parallel fan-outs and loops can spawn multiple invocations of\n * the same node; arrays preserve insertion order. Updates in\n * lock-step with {@link subgraphs}.\n */\n readonly subgraphsByNode: Readonly<\n ShallowRef<ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>>\n >;\n\n // ----- imperatives -----\n /**\n * Dispatch a new run on the bound thread.\n *\n * `input` is typed as `Partial<StateType>` so IDE autocompletion\n * surfaces the state keys declared on the root composable.\n */\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n /**\n * Stop the active run on the current thread. By default cancels the\n * run server-side and disconnects the client; pass `{ cancel: false }`\n * or use {@link disconnect} for join/rejoin. Sets {@link isLoading} to\n * `false` immediately; {@link values} and {@link messages} are preserved.\n */\n stop(options?: StreamStopOptions): Promise<void>;\n /**\n * Disconnect the client without cancelling the run server-side.\n * Alias for `stop({ cancel: false })`.\n */\n disconnect(): Promise<void>;\n /**\n * Resume a pending protocol interrupt by sending a response payload\n * back to the interrupted namespace.\n *\n * When `options.interruptId` is omitted, walks `getThread()?.interrupts`\n * from newest to oldest and resumes the first not yet resolved by a prior\n * `respond()` call. That may be a root or subgraph interrupt and is\n * **not** necessarily {@link interrupt} (`interrupts[0]`, root-only).\n * Safe when exactly one interrupt is pending; otherwise pass an explicit\n * `options.interruptId` (and `options.namespace` for subgraph\n * interrupts).\n *\n * The server validates `namespace` against the pending interrupt. Root\n * interrupts use `namespace: []` (default when omitted). For subgraph\n * interrupts, copy `namespace` from `getThread()?.interrupts`.\n *\n * @example\n * ```ts\n * // Single pending interrupt\n * await stream.respond({ approved: true });\n * ```\n *\n * @example\n * ```tsx\n * // Multiple root interrupts\n * for (const intr of stream.interrupts.value) {\n * await stream.respond(decide(intr.value), { interruptId: intr.id! });\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Subgraph interrupt — namespace from `getThread()`\n * const thread = stream.getThread();\n * for (const entry of thread?.interrupts ?? []) {\n * await stream.respond(buildResponse(entry.payload), {\n * interruptId: entry.interruptId,\n * namespace: entry.namespace,\n * });\n * }\n * ```\n *\n * To resume several interrupts pending at the same checkpoint in one\n * command, use {@link respondAll}.\n */\n respond(\n response: unknown,\n options?: StreamRespondOptions<ConfigurableType>\n ): Promise<void>;\n\n /**\n * Resume several pending interrupts at the same checkpoint in a single\n * command — required when a run pauses on multiple interrupts at once\n * (e.g. parallel tool-authorization prompts), which sequential\n * {@link respond} calls cannot handle. `responsesById` maps each pending\n * `interruptId` to its response, so different interrupts can receive\n * different payloads. Pass `options.config` / `options.metadata` to fold\n * run-level config and metadata into the resumed run, mirroring\n * `submit()`.\n *\n * @example\n * ```ts\n * await stream.respondAll({\n * [interruptA.id]: { approved: true },\n * [interruptB.id]: { approved: false },\n * });\n * ```\n */\n respondAll(\n responsesById: Record<string, unknown>,\n options?: StreamRespondAllOptions<ConfigurableType>\n ): Promise<void>;\n\n // ----- identity -----\n /** LangGraph SDK client used to construct thread streams. */\n readonly client: Client;\n /** Assistant id the thread is bound to for its lifetime. */\n readonly assistantId: string;\n\n /**\n * Returns the bound {@link ThreadStream}, if one exists (`undefined`\n * until the thread is hydrated or the first submit completes). Prefer\n * the projections and selector composables for UI work; use this for\n * low-level protocol access (raw subscriptions, state commands, etc.).\n */\n getThread(): ThreadStream | undefined;\n\n /** @internal Used by selector composables. */\n readonly [STREAM_CONTROLLER]: StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >;\n}\n\n/**\n * Erased handle useful as a parameter type for helpers and wrapper\n * components that pass a `stream` through to selector composables\n * without reading `values` directly. Mirrors the React\n * `AnyStream` alias.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyStream = UseStreamReturn<any, any, any>;\n\n/** Convenience alias for the fully-resolved stream handle type. */\nexport type UseStreamResult<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n> = UseStreamReturn<T, InterruptType, ConfigurableType>;\n\n/**\n * Vue Composition API binding for the v2-native stream runtime.\n *\n * Returns a handle whose projections are Vue refs so templates\n * auto-unwrap and scripts can feed them into `computed`/`watch`.\n * Scoped views (subagents, subgraphs, any namespaced projection) are\n * surfaced via the companion selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, `useMessageMetadata`,\n * `useSubmissionQueue`, `useExtension`, `useChannel`, plus media\n * composables).\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useStream } from \"@langchain/vue\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"msg in stream.messages.value\" :key=\"msg.id\">\n * {{ msg.content }}\n * </div>\n * <button @click=\"stream.submit({ messages: [{ type: 'human', content: 'Hi' }] })\">\n * Send\n * </button>\n * </template>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at setup time.\n * To bind a new assistant/transport, remount the component. Reactive\n * inputs (`threadId`, `apiUrl`, `apiKey`) trigger in-place behaviour\n * changes on the active controller.\n */\nexport function useStream<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n>(\n options: UseStreamOptions<InferStateType<T>>\n): UseStreamReturn<T, InterruptType, ConfigurableType> {\n type StateType = InferStateType<T>;\n\n interface OptionsBag {\n assistantId?: string;\n threadId?: MaybeRefOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: MaybeRefOrGetter<string | undefined>;\n apiKey?: MaybeRefOrGetter<string | undefined>;\n callerOptions?: ClientConfig[\"callerOptions\"];\n defaultHeaders?: ClientConfig[\"defaultHeaders\"];\n transport?: \"sse\" | \"websocket\" | AgentServerAdapter;\n fetch?: typeof fetch;\n webSocketFactory?: (url: string) => WebSocket;\n onThreadId?: (threadId: string) => void;\n onCreated?: (info: RunExecutionInfo) => void;\n onCompleted?: (info: RunCompletedInfo) => void;\n initialValues?: StateType;\n messagesKey?: string;\n tools?: AnyHeadlessToolImplementation[];\n onTool?: OnToolCallback;\n }\n const asBag = options as OptionsBag;\n\n // Inherit missing apiUrl / apiKey / client from any LangChainPlugin\n // installed on the app. Vue's `inject` returns `undefined` if the\n // key was never provided; that's fine — we only merge when the\n // caller didn't set a value.\n const pluginOptions =\n inject(LANGCHAIN_OPTIONS, undefined) ?? ({} as Record<string, unknown>);\n\n const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // ─── Client construction ────────────────────────────────────────────\n //\n // Identity-stable per setup. Watches apiUrl/apiKey refs so callers\n // that flip a backend at runtime get a fresh client without a full\n // remount — the controller is swapped in lock-step below.\n const resolveApiUrl = () =>\n toValue(asBag.apiUrl) ?? (pluginOptions as { apiUrl?: string }).apiUrl;\n const resolveApiKey = () =>\n toValue(asBag.apiKey) ?? (pluginOptions as { apiKey?: string }).apiKey;\n const explicitClient =\n asBag.client ?? (pluginOptions as { client?: Client }).client;\n\n const clientRef = shallowRef<Client>(\n explicitClient ??\n (new ClientCtor({\n apiUrl: resolveApiUrl(),\n apiKey: resolveApiKey(),\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client)\n );\n\n // Note: we intentionally bind the controller to the *initial* client\n // instance. A dynamic client swap would require tearing the\n // controller down (in-flight subscriptions, queue, hydration), so we\n // keep the rule simple: client is captured at setup. Mirrors React\n // v1 which bakes `useMemo` on `[client, assistantId, transport]`.\n const client = clientRef.value;\n\n // Custom adapters may omit `assistantId`; the controller still\n // requires one so it has something to forward to `threads.stream`.\n const sentinel = \"_\";\n const assistantId =\n \"assistantId\" in options ? (options.assistantId ?? sentinel) : sentinel;\n\n const initialThreadId = toValue(asBag.threadId) ?? null;\n\n // ─── Controller construction ────────────────────────────────────────\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n client: client as unknown as Client<StateType>,\n threadId: initialThreadId,\n transport,\n fetch: hasCustomAdapter ? undefined : asBag.fetch,\n webSocketFactory: hasCustomAdapter ? undefined : asBag.webSocketFactory,\n onThreadId: options.onThreadId,\n onCreated: options.onCreated,\n onCompleted: options.onCompleted,\n initialValues: options.initialValues,\n messagesKey: options.messagesKey,\n });\n\n // Deferred dispose: on the next microtask after the owning scope\n // disappears. Mirrors React's StrictMode-safe activate/deactivate\n // pattern — HMR and other scope-reuse scenarios stay clean because\n // `activate()` cancels the pending dispose if the scope survives.\n const deactivate = controller.activate();\n onScopeDispose(deactivate);\n\n // ─── Reactivity adapters — StreamStore → shallowRef ─────────────────\n function bindStore<S>(\n subscribe: (listener: () => void) => () => void,\n getSnapshot: () => S\n ): Readonly<ShallowRef<S>> {\n const ref = shallowRef<S>(getSnapshot());\n const unsubscribe = subscribe(() => {\n ref.value = getSnapshot();\n });\n onScopeDispose(unsubscribe);\n return readonly(ref) as Readonly<ShallowRef<S>>;\n }\n\n const rootRef = bindStore<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.subscribe,\n controller.rootStore.getSnapshot\n );\n const subagentRef = bindStore<SubagentMap>(\n controller.subagentStore.subscribe,\n controller.subagentStore.getSnapshot\n );\n const subgraphRef = bindStore<SubgraphMap>(\n controller.subgraphStore.subscribe,\n controller.subgraphStore.getSnapshot\n );\n const subgraphByNodeRef = bindStore<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.subscribe,\n controller.subgraphByNodeStore.getSnapshot\n );\n\n // Derived refs for individual root-snapshot fields. Using computed\n // means templates that read `values.value` only retrigger when the\n // root snapshot's identity actually changes — we can't split further\n // because `StreamStore` fans the whole snapshot out on every update.\n const values = computed(() => rootRef.value.values);\n const messages = computed(() => rootRef.value.messages);\n const toolCalls = computed(\n () => rootRef.value.toolCalls as InferToolCalls<T>[]\n );\n const interrupts = computed(() =>\n filterOutHeadlessToolInterrupts(rootRef.value.interrupts)\n );\n const interrupt = computed(() => interrupts.value[0]);\n const isLoading = computed(() => rootRef.value.isLoading);\n const isThreadLoading = computed(() => rootRef.value.isThreadLoading);\n const error = computed(() => rootRef.value.error);\n const threadId = computed(() => rootRef.value.threadId);\n const hydrationPromise = computed(() => controller.hydrationPromise);\n\n // Expose the derived refs through a `readonly(shallowRef)` shape to\n // match the rest of the public surface. `computed` already gives us\n // read-only semantics but templates type-check more cleanly when the\n // fully-typed return claims `Readonly<ShallowRef<T>>` everywhere.\n // The cast is safe — a ComputedRef<T> is structurally a\n // Readonly<Ref<T>>.\n const asShallow = <V>(c: ComputedRef<V>): Readonly<ShallowRef<V>> =>\n c as unknown as Readonly<ShallowRef<V>>;\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Re-hydrate whenever the caller's threadId input changes post-setup.\n // The initial hydrate already fired synchronously in the controller\n // constructor, so we skip that first tick; otherwise we'd double-fetch\n // `thread.state.get()`.\n let skipFirstThreadIdWatch = true;\n watch(\n () => toValue(asBag.threadId) ?? null,\n (next) => {\n if (skipFirstThreadIdWatch) {\n skipFirstThreadIdWatch = false;\n return;\n }\n void controller.hydrate(next);\n }\n );\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch root values + protocol interrupts for items targeting a\n // registered tool, invoke the handler, and resume the run with the\n // handler's return value. Dedup via an id set so StrictMode /\n // rerenders don't replay a tool call twice.\n const handledTools = new Set<string>();\n watch(\n () => toValue(asBag.threadId) ?? null,\n () => handledTools.clear()\n );\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n watch(\n () => [rootRef.value.values, rootRef.value.interrupts] as const,\n () => {\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const rootValues = rootRef.value.values;\n const rootInterrupts = rootRef.value.interrupts;\n const bag = rootValues as unknown as Record<string, unknown>;\n const protocolInterrupts = rootInterrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(bag?.__interrupt__)\n ? (bag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0\n ? protocolInterrupts\n : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...bag, __interrupt__: headlessInterrupts },\n tools,\n handledTools,\n {\n onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n controller.submit(null, {\n command,\n } as StreamSubmitOptions<StateType, ConfigurableType>),\n }\n );\n });\n },\n { immediate: true }\n );\n }\n\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n values: asShallow(values) as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"values\"],\n messages: asShallow(messages),\n toolCalls: asShallow(toolCalls),\n interrupts: asShallow(interrupts),\n interrupt,\n isLoading,\n isThreadLoading,\n error,\n threadId,\n hydrationPromise,\n subagents: subagentRef as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"],\n subgraphs: subgraphRef,\n subgraphsByNode: subgraphByNodeRef,\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: (options) => controller.stop(options),\n disconnect: () => controller.disconnect(),\n respond: (response, options) => controller.respond(response, options),\n respondAll: (responsesById, options) =>\n controller.respondAll(responsesById, options),\n getThread: () => controller.getThread(),\n client,\n assistantId,\n [STREAM_CONTROLLER]: controller,\n };\n\n return handle;\n}\n\n/**\n * Helper used by the selector composables to reach the underlying\n * {@link ChannelRegistry} from a stream handle. Kept internal —\n * application code should call `useMessages`, `useToolCalls`, etc.\n *\n * @internal\n */\nexport function getRegistry(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream: UseStreamReturn<any, any, any>\n): ChannelRegistry {\n return stream[STREAM_CONTROLLER].registry;\n}\n\nexport type { ThreadStream };\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { ComputedRef, MaybeRefOrGetter, ShallowRef } from "vue";
2
2
  import { BaseMessage } from "@langchain/core/messages";
3
3
  import { Client, Interrupt } from "@langchain/langgraph-sdk";
4
4
  import { ThreadStream } from "@langchain/langgraph-sdk/client";
5
- import { AgentServerOptions, ChannelRegistry, CustomAdapterOptions, InferStateType, InferSubagentStates, InferToolCalls, StreamController, StreamStopOptions, StreamSubmitOptions, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, UseStreamOptions, WidenUpdateMessages } from "@langchain/langgraph-sdk/stream";
5
+ import { AgentServerOptions, ChannelRegistry, CustomAdapterOptions, InferStateType, InferSubagentStates, InferToolCalls, StreamController, StreamRespondAllOptions, StreamRespondOptions, StreamStopOptions, StreamSubmitOptions, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, UseStreamOptions, WidenUpdateMessages } from "@langchain/langgraph-sdk/stream";
6
6
 
7
7
  //#region src/use-stream.d.ts
8
8
  type VueThreadId = MaybeRefOrGetter<string | null | undefined>;
@@ -81,7 +81,7 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
81
81
  * namespace during the active thread. Populated from lifecycle /
82
82
  * input events and seeded on hydration from `thread.getState()`.
83
83
  * Cleared optimistically when a new run starts or an interrupt is
84
- * resolved via {@link respond} / `submit({ command: { resume } })`.
84
+ * resolved via {@link respond}.
85
85
  */
86
86
  readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;
87
87
  /**
@@ -154,10 +154,7 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
154
154
  * Dispatch a new run on the bound thread.
155
155
  *
156
156
  * `input` is typed as `Partial<StateType>` so IDE autocompletion
157
- * surfaces the state keys declared on the root composable. Pass
158
- * `null` (or omit fields) when resuming an interrupt via
159
- * `options.command.resume` — the server accepts a null payload
160
- * in that case.
157
+ * surfaces the state keys declared on the root composable.
161
158
  */
162
159
  submit(input: WidenUpdateMessages<Partial<StateType>> | null | undefined, options?: StreamSubmitOptions<StateType, ConfigurableType>): Promise<void>;
163
160
  /**
@@ -176,15 +173,67 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
176
173
  * Resume a pending protocol interrupt by sending a response payload
177
174
  * back to the interrupted namespace.
178
175
  *
179
- * When `target` is omitted, responds to the latest unresolved
180
- * interrupt in {@link interrupts}. Pass an explicit
181
- * `{ interruptId, namespace? }` when multiple interrupts are
182
- * pending or the interrupt lives in a subgraph namespace.
183
- */
184
- respond(response: unknown, target?: {
185
- interruptId: string;
186
- namespace?: string[];
187
- }): Promise<void>;
176
+ * When `options.interruptId` is omitted, walks `getThread()?.interrupts`
177
+ * from newest to oldest and resumes the first not yet resolved by a prior
178
+ * `respond()` call. That may be a root or subgraph interrupt and is
179
+ * **not** necessarily {@link interrupt} (`interrupts[0]`, root-only).
180
+ * Safe when exactly one interrupt is pending; otherwise pass an explicit
181
+ * `options.interruptId` (and `options.namespace` for subgraph
182
+ * interrupts).
183
+ *
184
+ * The server validates `namespace` against the pending interrupt. Root
185
+ * interrupts use `namespace: []` (default when omitted). For subgraph
186
+ * interrupts, copy `namespace` from `getThread()?.interrupts`.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * // Single pending interrupt
191
+ * await stream.respond({ approved: true });
192
+ * ```
193
+ *
194
+ * @example
195
+ * ```tsx
196
+ * // Multiple root interrupts
197
+ * for (const intr of stream.interrupts.value) {
198
+ * await stream.respond(decide(intr.value), { interruptId: intr.id! });
199
+ * }
200
+ * ```
201
+ *
202
+ * @example
203
+ * ```tsx
204
+ * // Subgraph interrupt — namespace from `getThread()`
205
+ * const thread = stream.getThread();
206
+ * for (const entry of thread?.interrupts ?? []) {
207
+ * await stream.respond(buildResponse(entry.payload), {
208
+ * interruptId: entry.interruptId,
209
+ * namespace: entry.namespace,
210
+ * });
211
+ * }
212
+ * ```
213
+ *
214
+ * To resume several interrupts pending at the same checkpoint in one
215
+ * command, use {@link respondAll}.
216
+ */
217
+ respond(response: unknown, options?: StreamRespondOptions<ConfigurableType>): Promise<void>;
218
+ /**
219
+ * Resume several pending interrupts at the same checkpoint in a single
220
+ * command — required when a run pauses on multiple interrupts at once
221
+ * (e.g. parallel tool-authorization prompts), which sequential
222
+ * {@link respond} calls cannot handle. `responsesById` maps each pending
223
+ * `interruptId` to its response, so different interrupts can receive
224
+ * different payloads. Pass `options.config` / `options.metadata` to fold
225
+ * run-level config and metadata into the resumed run, mirroring
226
+ * `submit()`.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * await stream.respondAll({
231
+ * [interruptA.id]: { approved: true },
232
+ * [interruptB.id]: { approved: false },
233
+ * });
234
+ * ```
235
+ */
236
+ respondAll(responsesById: Record<string, unknown>, options?: StreamRespondAllOptions<ConfigurableType>): Promise<void>;
188
237
  /** LangGraph SDK client used to construct thread streams. */
189
238
  readonly client: Client;
190
239
  /** Assistant id the thread is bound to for its lifetime. */
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.d.cts","names":[],"sources":["../src/use-stream.ts"],"mappings":";;;;;;;KAkDK,WAAA,GAAc,gBAAA;AAAA,KACd,YAAA,GAAe,gBAAA;AAAA,KAER,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,WAAA,EAAa,YAAA,EAAc,YAAA;AAAA,KAErD,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,WAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,WAAA,EACA,YAAA,EACA,YAAA;;;AAfiC;;;;cAyBtB,iBAAA;AAtBb;;;;;;;;;;;;;;AAAA,UAwCiB,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EA5C0B;;;AAEjE;;;;;;;;EAFiE,SA0DtD,MAAA,EAAQ,QAAA,CAAS,UAAA,CAAW,SAAA;EAvDrC;;;;;AAEF;;;;;;;;;;;;;;;EAFE,SA4ES,QAAA,EAAU,QAAA,CAAS,UAAA,CAAW,WAAA;EArEvC;;;;AAWF;;;;;AAkBA;EA7BE,SAgFS,SAAA,EAAW,QAAA,CAAS,UAAA,CAAW,cAAA,CAAe,CAAA;EAnDzB;;;;;;;EAAA,SA2DrB,UAAA,EAAY,QAAA,CAAS,UAAA,CAAW,SAAA,CAAU,aAAA;EAxCzB;;;;;EAAA,SA8CjB,SAAA,EAAW,WAAA,CAAY,SAAA,CAAU,aAAA;EAdF;;;;;;EAAA,SAqB/B,SAAA,EAAW,WAAA;EAPsB;;;;;;EAAA,SAcjC,eAAA,EAAiB,WAAA;EAoBa;;;;;EAAA,SAd9B,KAAA,EAAO,WAAA;EAuBd;;;;;EAAA,SAjBO,QAAA,EAAU,WAAA;EAgDuB;;;;;;;EAAA,SAxCjC,gBAAA,EAAkB,WAAA,CAAY,OAAA;EAuDI;;;;;EAAA,SA/ClC,SAAA,EAAW,QAAA,CAClB,UAAA,CACE,WAAA,OACQ,cAAA,yCAEI,cAAA,WACV,yBAAA;EAmEH;;;;;;;;;;;EAAA,SApDM,SAAA,EAAW,QAAA,CAClB,UAAA,CAAW,WAAA,SAAoB,yBAAA;EA/HjC;;;;;;;EAAA,SAwIS,eAAA,EAAiB,QAAA,CACxB,UAAA,CAAW,WAAA,kBAA6B,yBAAA;EAtIL;;;;;;;;;EAmJrC,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAxGiB;;;;;;EA+GpB,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EAvGM;;;;EA4GzC,UAAA,IAAc,OAAA;EAtG4B;;;;;;;;;EAgH1C,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAzEiB;EAAA,SA6EX,MAAA,EAAQ,MAAA;EA3Eb;EAAA,SA6EK,WAAA;EA1EO;;;;;;EAkFhB,SAAA,IAAa,YAAA;EAxDJ;EAAA,UA2DC,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;;;;KAWQ,SAAA,GAAY,eAAA;;KAGZ,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAPtC;;;;;AAGA;;;;;iBA2CgB,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
1
+ {"version":3,"file":"use-stream.d.cts","names":[],"sources":["../src/use-stream.ts"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ComputedRef, MaybeRefOrGetter, ShallowRef } from "vue";
2
2
  import { Client, Interrupt } from "@langchain/langgraph-sdk";
3
3
  import { ThreadStream } from "@langchain/langgraph-sdk/client";
4
- import { AgentServerOptions, ChannelRegistry, CustomAdapterOptions, InferStateType, InferSubagentStates, InferToolCalls, StreamController, StreamStopOptions, StreamSubmitOptions, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, UseStreamOptions, WidenUpdateMessages } from "@langchain/langgraph-sdk/stream";
4
+ import { AgentServerOptions, ChannelRegistry, CustomAdapterOptions, InferStateType, InferSubagentStates, InferToolCalls, StreamController, StreamRespondAllOptions, StreamRespondOptions, StreamStopOptions, StreamSubmitOptions, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, UseStreamOptions, WidenUpdateMessages } from "@langchain/langgraph-sdk/stream";
5
5
  import { BaseMessage } from "@langchain/core/messages";
6
6
 
7
7
  //#region src/use-stream.d.ts
@@ -81,7 +81,7 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
81
81
  * namespace during the active thread. Populated from lifecycle /
82
82
  * input events and seeded on hydration from `thread.getState()`.
83
83
  * Cleared optimistically when a new run starts or an interrupt is
84
- * resolved via {@link respond} / `submit({ command: { resume } })`.
84
+ * resolved via {@link respond}.
85
85
  */
86
86
  readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;
87
87
  /**
@@ -154,10 +154,7 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
154
154
  * Dispatch a new run on the bound thread.
155
155
  *
156
156
  * `input` is typed as `Partial<StateType>` so IDE autocompletion
157
- * surfaces the state keys declared on the root composable. Pass
158
- * `null` (or omit fields) when resuming an interrupt via
159
- * `options.command.resume` — the server accepts a null payload
160
- * in that case.
157
+ * surfaces the state keys declared on the root composable.
161
158
  */
162
159
  submit(input: WidenUpdateMessages<Partial<StateType>> | null | undefined, options?: StreamSubmitOptions<StateType, ConfigurableType>): Promise<void>;
163
160
  /**
@@ -176,15 +173,67 @@ interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown,
176
173
  * Resume a pending protocol interrupt by sending a response payload
177
174
  * back to the interrupted namespace.
178
175
  *
179
- * When `target` is omitted, responds to the latest unresolved
180
- * interrupt in {@link interrupts}. Pass an explicit
181
- * `{ interruptId, namespace? }` when multiple interrupts are
182
- * pending or the interrupt lives in a subgraph namespace.
183
- */
184
- respond(response: unknown, target?: {
185
- interruptId: string;
186
- namespace?: string[];
187
- }): Promise<void>;
176
+ * When `options.interruptId` is omitted, walks `getThread()?.interrupts`
177
+ * from newest to oldest and resumes the first not yet resolved by a prior
178
+ * `respond()` call. That may be a root or subgraph interrupt and is
179
+ * **not** necessarily {@link interrupt} (`interrupts[0]`, root-only).
180
+ * Safe when exactly one interrupt is pending; otherwise pass an explicit
181
+ * `options.interruptId` (and `options.namespace` for subgraph
182
+ * interrupts).
183
+ *
184
+ * The server validates `namespace` against the pending interrupt. Root
185
+ * interrupts use `namespace: []` (default when omitted). For subgraph
186
+ * interrupts, copy `namespace` from `getThread()?.interrupts`.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * // Single pending interrupt
191
+ * await stream.respond({ approved: true });
192
+ * ```
193
+ *
194
+ * @example
195
+ * ```tsx
196
+ * // Multiple root interrupts
197
+ * for (const intr of stream.interrupts.value) {
198
+ * await stream.respond(decide(intr.value), { interruptId: intr.id! });
199
+ * }
200
+ * ```
201
+ *
202
+ * @example
203
+ * ```tsx
204
+ * // Subgraph interrupt — namespace from `getThread()`
205
+ * const thread = stream.getThread();
206
+ * for (const entry of thread?.interrupts ?? []) {
207
+ * await stream.respond(buildResponse(entry.payload), {
208
+ * interruptId: entry.interruptId,
209
+ * namespace: entry.namespace,
210
+ * });
211
+ * }
212
+ * ```
213
+ *
214
+ * To resume several interrupts pending at the same checkpoint in one
215
+ * command, use {@link respondAll}.
216
+ */
217
+ respond(response: unknown, options?: StreamRespondOptions<ConfigurableType>): Promise<void>;
218
+ /**
219
+ * Resume several pending interrupts at the same checkpoint in a single
220
+ * command — required when a run pauses on multiple interrupts at once
221
+ * (e.g. parallel tool-authorization prompts), which sequential
222
+ * {@link respond} calls cannot handle. `responsesById` maps each pending
223
+ * `interruptId` to its response, so different interrupts can receive
224
+ * different payloads. Pass `options.config` / `options.metadata` to fold
225
+ * run-level config and metadata into the resumed run, mirroring
226
+ * `submit()`.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * await stream.respondAll({
231
+ * [interruptA.id]: { approved: true },
232
+ * [interruptB.id]: { approved: false },
233
+ * });
234
+ * ```
235
+ */
236
+ respondAll(responsesById: Record<string, unknown>, options?: StreamRespondAllOptions<ConfigurableType>): Promise<void>;
188
237
  /** LangGraph SDK client used to construct thread streams. */
189
238
  readonly client: Client;
190
239
  /** Assistant id the thread is bound to for its lifetime. */
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.d.ts","names":[],"sources":["../src/use-stream.ts"],"mappings":";;;;;;;KAkDK,WAAA,GAAc,gBAAA;AAAA,KACd,YAAA,GAAe,gBAAA;AAAA,KAER,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,WAAA,EAAa,YAAA,EAAc,YAAA;AAAA,KAErD,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,WAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,WAAA,EACA,YAAA,EACA,YAAA;;;AAfiC;;;;cAyBtB,iBAAA;AAtBb;;;;;;;;;;;;;;AAAA,UAwCiB,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EA5C0B;;;AAEjE;;;;;;;;EAFiE,SA0DtD,MAAA,EAAQ,QAAA,CAAS,UAAA,CAAW,SAAA;EAvDrC;;;;;AAEF;;;;;;;;;;;;;;;EAFE,SA4ES,QAAA,EAAU,QAAA,CAAS,UAAA,CAAW,WAAA;EArEvC;;;;AAWF;;;;;AAkBA;EA7BE,SAgFS,SAAA,EAAW,QAAA,CAAS,UAAA,CAAW,cAAA,CAAe,CAAA;EAnDzB;;;;;;;EAAA,SA2DrB,UAAA,EAAY,QAAA,CAAS,UAAA,CAAW,SAAA,CAAU,aAAA;EAxCzB;;;;;EAAA,SA8CjB,SAAA,EAAW,WAAA,CAAY,SAAA,CAAU,aAAA;EAdF;;;;;;EAAA,SAqB/B,SAAA,EAAW,WAAA;EAPsB;;;;;;EAAA,SAcjC,eAAA,EAAiB,WAAA;EAoBa;;;;;EAAA,SAd9B,KAAA,EAAO,WAAA;EAuBd;;;;;EAAA,SAjBO,QAAA,EAAU,WAAA;EAgDuB;;;;;;;EAAA,SAxCjC,gBAAA,EAAkB,WAAA,CAAY,OAAA;EAuDI;;;;;EAAA,SA/ClC,SAAA,EAAW,QAAA,CAClB,UAAA,CACE,WAAA,OACQ,cAAA,yCAEI,cAAA,WACV,yBAAA;EAmEH;;;;;;;;;;;EAAA,SApDM,SAAA,EAAW,QAAA,CAClB,UAAA,CAAW,WAAA,SAAoB,yBAAA;EA/HjC;;;;;;;EAAA,SAwIS,eAAA,EAAiB,QAAA,CACxB,UAAA,CAAW,WAAA,kBAA6B,yBAAA;EAtIL;;;;;;;;;EAmJrC,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAxGiB;;;;;;EA+GpB,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EAvGM;;;;EA4GzC,UAAA,IAAc,OAAA;EAtG4B;;;;;;;;;EAgH1C,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAzEiB;EAAA,SA6EX,MAAA,EAAQ,MAAA;EA3Eb;EAAA,SA6EK,WAAA;EA1EO;;;;;;EAkFhB,SAAA,IAAa,YAAA;EAxDJ;EAAA,UA2DC,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;;;;KAWQ,SAAA,GAAY,eAAA;;KAGZ,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAPtC;;;;;AAGA;;;;;iBA2CgB,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
1
+ {"version":3,"file":"use-stream.d.ts","names":[],"sources":["../src/use-stream.ts"],"mappings":"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"}
@@ -149,7 +149,8 @@ function useStream(options) {
149
149
  submit: (input, submitOptions) => controller.submit(input, submitOptions),
150
150
  stop: (options) => controller.stop(options),
151
151
  disconnect: () => controller.disconnect(),
152
- respond: (response, target) => controller.respond(response, target),
152
+ respond: (response, options) => controller.respond(response, options),
153
+ respondAll: (responsesById, options) => controller.respondAll(responsesById, options),
153
154
  getThread: () => controller.getThread(),
154
155
  client,
155
156
  assistantId,
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.js","names":["ClientCtor"],"sources":["../src/use-stream.ts"],"sourcesContent":["import {\n computed,\n onScopeDispose,\n readonly,\n shallowRef,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from \"vue\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n filterOutHeadlessToolInterrupts,\n flushPendingHeadlessToolInterrupts,\n scheduleCoalescedHeadlessToolFlush,\n type AnyHeadlessToolImplementation,\n type OnToolCallback,\n} from \"@langchain/langgraph-sdk\";\nimport {\n Client as ClientCtor,\n type ClientConfig,\n type ThreadStream,\n} from \"@langchain/langgraph-sdk/client\";\nimport {\n StreamController,\n type AgentServerAdapter,\n type AgentServerOptions as StreamAgentServerOptions,\n type ChannelRegistry,\n type CustomAdapterOptions as StreamCustomAdapterOptions,\n type InferStateType,\n type InferSubagentStates,\n type InferToolCalls,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\n type StreamStopOptions,\n type StreamSubmitOptions,\n type SubagentDiscoverySnapshot,\n type SubagentMap,\n type SubgraphByNodeMap,\n type SubgraphDiscoverySnapshot,\n type SubgraphMap,\n type UseStreamOptions as StreamUseStreamOptions,\n type WidenUpdateMessages,\n} from \"@langchain/langgraph-sdk/stream\";\nimport { inject } from \"vue\";\nimport { LANGCHAIN_OPTIONS } from \"./context.js\";\n\ntype VueThreadId = MaybeRefOrGetter<string | null | undefined>;\ntype VueApiString = MaybeRefOrGetter<string | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, VueThreadId, VueApiString, VueApiString>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, VueThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n VueThreadId,\n VueApiString,\n VueApiString,\n string\n>;\n\n/**\n * Private field on the handle that carries the {@link StreamController}\n * reference. Selector composables read this to reach the shared\n * {@link ChannelRegistry}. Use the selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, …) instead of reading this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/vue/controller\"\n);\n\n/**\n * Vue binding return type for {@link useStream}.\n *\n * Reactive primitives follow Vue conventions:\n *\n * - Data projections are `Readonly<ShallowRef<T>>` / `ComputedRef<T>`\n * so templates auto-unwrap via `msg.value` in `<script setup>`\n * and directly in templates. They are snapshots — never mutate.\n * - Imperative methods (`submit` / `stop` / `respond`) are plain\n * functions — no refs involved.\n * - Identity values captured at setup time (`client` / `assistantId`)\n * are exposed as plain values; if you need to swap the bound agent\n * or client, remount the composable.\n */\nexport interface UseStreamReturn<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n StateType extends object = InferStateType<T>,\n SubagentStates = InferSubagentStates<T>,\n> {\n // ----- always-on root projections -----\n /**\n * The most recent `values`-channel snapshot emitted at the root\n * namespace — i.e. the thread-level state as the server sees it\n * after each superstep. Updated on every root `values` event, not\n * on token-level deltas: if you render `stream.values.value.messages`\n * directly you'll see full turns appear at once instead of\n * streaming token-by-token. Use {@link messages} (or\n * `useMessages`) for the token-streamed view.\n *\n * Equivalent to calling `useValues(stream)`.\n */\n readonly values: Readonly<ShallowRef<StateType>>;\n /**\n * The root message projection. Assembled from two sources and\n * merged in real time:\n *\n * 1. `messages`-channel deltas — token-level streaming events\n * (`message-start`, `content-block-delta`, `message-finish`)\n * emitted by the runtime. These drive live, token-by-token\n * updates.\n * 2. `values.messages` snapshots — the authoritative ordering\n * and any messages the agent produces without token streaming\n * (human turns, tool results, echoes from subagents).\n *\n * If the backend only emits `values` events (no `messages`\n * channel), every message will appear fully-formed on each\n * values update rather than streaming. This is a backend/runtime\n * concern — the Vue layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: Readonly<ShallowRef<BaseMessage[]>>;\n /**\n * Root-namespace tool calls assembled from the `tools` channel.\n * Each entry is a fully parsed {@link AssembledToolCall} with\n * name, args, and id — suitable for rendering approval UIs or\n * forwarding to headless tool handlers.\n *\n * When the stream is typed with an agent brand or tool list,\n * entries are narrowed via {@link InferToolCalls}. Equivalent to\n * calling `useToolCalls(stream)` with no target.\n */\n readonly toolCalls: Readonly<ShallowRef<InferToolCalls<T>[]>>;\n /**\n * All unresolved protocol interrupts observed on the root\n * namespace during the active thread. Populated from lifecycle /\n * input events and seeded on hydration from `thread.getState()`.\n * Cleared optimistically when a new run starts or an interrupt is\n * resolved via {@link respond} / `submit({ command: { resume } })`.\n */\n readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;\n /**\n * Convenience alias for {@link interrupts}[0] — the primary\n * interrupt most UIs should act on when only one is pending.\n * `undefined` when no interrupt is active.\n */\n readonly interrupt: ComputedRef<Interrupt<InterruptType> | undefined>;\n /**\n * `true` while a run is active or being started on the current\n * thread. Driven by root-namespace lifecycle events (`running` →\n * `true`, terminal phases → `false`). Use this to disable submit\n * buttons and show in-flight spinners.\n */\n readonly isLoading: ComputedRef<boolean>;\n /**\n * `true` while the initial `thread.getState()` hydration for the\n * active thread is in flight. Distinct from {@link isLoading} —\n * thread loading covers the one-time fetch that seeds\n * {@link values} / {@link messages} before any user submit.\n */\n readonly isThreadLoading: ComputedRef<boolean>;\n /**\n * The last error observed on the active run or hydration attempt.\n * `undefined` when no error has occurred. Cleared optimistically\n * when a new {@link submit} starts.\n */\n readonly error: ComputedRef<unknown>;\n /**\n * Id of the thread the controller is bound to. `null` until the\n * first {@link submit} creates or selects a thread (or until an\n * explicit `threadId` option is provided and hydrated).\n */\n readonly threadId: ComputedRef<string | null>;\n /**\n * Promise that settles when the active thread's initial hydration\n * completes. Exposed so `async setup()` sites can\n * `await stream.hydrationPromise.value` to implement a\n * Suspense-like boundary. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: ComputedRef<Promise<void>>;\n\n // ----- always-on discovery -----\n /**\n * Subagents discovered on the root run. For DeepAgent-typed\n * streams the key set is narrowed to the subagent names declared\n * on the agent brand (`keyof InferSubagentStates<T>`).\n */\n readonly subagents: Readonly<\n ShallowRef<\n ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >\n >\n >;\n /**\n * Subgraphs discovered on the root run.\n *\n * A namespace is classified as a subgraph iff at least one\n * strictly-deeper namespace has been observed with it as a prefix.\n * This is inferred from the lifecycle event stream — plain function\n * nodes (`orchestrator`, `writer` in the nested-stategraph example)\n * never appear here even though the server emits namespaced\n * lifecycle events for them. Promotion is monotonic and retroactive;\n * an entry appears as soon as the first descendant event lands.\n */\n readonly subgraphs: Readonly<\n ShallowRef<ReadonlyMap<string, SubgraphDiscoverySnapshot>>\n >;\n /**\n * Subgraphs indexed by the graph node that produced them\n * (`addNode(\"visualizer_0\", …)`). Each value is an array because\n * parallel fan-outs and loops can spawn multiple invocations of\n * the same node; arrays preserve insertion order. Updates in\n * lock-step with {@link subgraphs}.\n */\n readonly subgraphsByNode: Readonly<\n ShallowRef<ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>>\n >;\n\n // ----- imperatives -----\n /**\n * Dispatch a new run on the bound thread.\n *\n * `input` is typed as `Partial<StateType>` so IDE autocompletion\n * surfaces the state keys declared on the root composable. Pass\n * `null` (or omit fields) when resuming an interrupt via\n * `options.command.resume` — the server accepts a null payload\n * in that case.\n */\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n /**\n * Stop the active run on the current thread. By default cancels the\n * run server-side and disconnects the client; pass `{ cancel: false }`\n * or use {@link disconnect} for join/rejoin. Sets {@link isLoading} to\n * `false` immediately; {@link values} and {@link messages} are preserved.\n */\n stop(options?: StreamStopOptions): Promise<void>;\n /**\n * Disconnect the client without cancelling the run server-side.\n * Alias for `stop({ cancel: false })`.\n */\n disconnect(): Promise<void>;\n /**\n * Resume a pending protocol interrupt by sending a response payload\n * back to the interrupted namespace.\n *\n * When `target` is omitted, responds to the latest unresolved\n * interrupt in {@link interrupts}. Pass an explicit\n * `{ interruptId, namespace? }` when multiple interrupts are\n * pending or the interrupt lives in a subgraph namespace.\n */\n respond(\n response: unknown,\n target?: { interruptId: string; namespace?: string[] }\n ): Promise<void>;\n\n // ----- identity -----\n /** LangGraph SDK client used to construct thread streams. */\n readonly client: Client;\n /** Assistant id the thread is bound to for its lifetime. */\n readonly assistantId: string;\n\n /**\n * Returns the bound {@link ThreadStream}, if one exists (`undefined`\n * until the thread is hydrated or the first submit completes). Prefer\n * the projections and selector composables for UI work; use this for\n * low-level protocol access (raw subscriptions, state commands, etc.).\n */\n getThread(): ThreadStream | undefined;\n\n /** @internal Used by selector composables. */\n readonly [STREAM_CONTROLLER]: StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >;\n}\n\n/**\n * Erased handle useful as a parameter type for helpers and wrapper\n * components that pass a `stream` through to selector composables\n * without reading `values` directly. Mirrors the React\n * `AnyStream` alias.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyStream = UseStreamReturn<any, any, any>;\n\n/** Convenience alias for the fully-resolved stream handle type. */\nexport type UseStreamResult<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n> = UseStreamReturn<T, InterruptType, ConfigurableType>;\n\n/**\n * Vue Composition API binding for the v2-native stream runtime.\n *\n * Returns a handle whose projections are Vue refs so templates\n * auto-unwrap and scripts can feed them into `computed`/`watch`.\n * Scoped views (subagents, subgraphs, any namespaced projection) are\n * surfaced via the companion selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, `useMessageMetadata`,\n * `useSubmissionQueue`, `useExtension`, `useChannel`, plus media\n * composables).\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useStream } from \"@langchain/vue\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"msg in stream.messages.value\" :key=\"msg.id\">\n * {{ msg.content }}\n * </div>\n * <button @click=\"stream.submit({ messages: [{ type: 'human', content: 'Hi' }] })\">\n * Send\n * </button>\n * </template>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at setup time.\n * To bind a new assistant/transport, remount the component. Reactive\n * inputs (`threadId`, `apiUrl`, `apiKey`) trigger in-place behaviour\n * changes on the active controller.\n */\nexport function useStream<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n>(\n options: UseStreamOptions<InferStateType<T>>\n): UseStreamReturn<T, InterruptType, ConfigurableType> {\n type StateType = InferStateType<T>;\n\n interface OptionsBag {\n assistantId?: string;\n threadId?: MaybeRefOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: MaybeRefOrGetter<string | undefined>;\n apiKey?: MaybeRefOrGetter<string | undefined>;\n callerOptions?: ClientConfig[\"callerOptions\"];\n defaultHeaders?: ClientConfig[\"defaultHeaders\"];\n transport?: \"sse\" | \"websocket\" | AgentServerAdapter;\n fetch?: typeof fetch;\n webSocketFactory?: (url: string) => WebSocket;\n onThreadId?: (threadId: string) => void;\n onCreated?: (info: RunExecutionInfo) => void;\n onCompleted?: (info: RunCompletedInfo) => void;\n initialValues?: StateType;\n messagesKey?: string;\n tools?: AnyHeadlessToolImplementation[];\n onTool?: OnToolCallback;\n }\n const asBag = options as OptionsBag;\n\n // Inherit missing apiUrl / apiKey / client from any LangChainPlugin\n // installed on the app. Vue's `inject` returns `undefined` if the\n // key was never provided; that's fine — we only merge when the\n // caller didn't set a value.\n const pluginOptions =\n inject(LANGCHAIN_OPTIONS, undefined) ?? ({} as Record<string, unknown>);\n\n const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // ─── Client construction ────────────────────────────────────────────\n //\n // Identity-stable per setup. Watches apiUrl/apiKey refs so callers\n // that flip a backend at runtime get a fresh client without a full\n // remount — the controller is swapped in lock-step below.\n const resolveApiUrl = () =>\n toValue(asBag.apiUrl) ?? (pluginOptions as { apiUrl?: string }).apiUrl;\n const resolveApiKey = () =>\n toValue(asBag.apiKey) ?? (pluginOptions as { apiKey?: string }).apiKey;\n const explicitClient =\n asBag.client ?? (pluginOptions as { client?: Client }).client;\n\n const clientRef = shallowRef<Client>(\n explicitClient ??\n (new ClientCtor({\n apiUrl: resolveApiUrl(),\n apiKey: resolveApiKey(),\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client)\n );\n\n // Note: we intentionally bind the controller to the *initial* client\n // instance. A dynamic client swap would require tearing the\n // controller down (in-flight subscriptions, queue, hydration), so we\n // keep the rule simple: client is captured at setup. Mirrors React\n // v1 which bakes `useMemo` on `[client, assistantId, transport]`.\n const client = clientRef.value;\n\n // Custom adapters may omit `assistantId`; the controller still\n // requires one so it has something to forward to `threads.stream`.\n const sentinel = \"_\";\n const assistantId =\n \"assistantId\" in options ? (options.assistantId ?? sentinel) : sentinel;\n\n const initialThreadId = toValue(asBag.threadId) ?? null;\n\n // ─── Controller construction ────────────────────────────────────────\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n client: client as unknown as Client<StateType>,\n threadId: initialThreadId,\n transport,\n fetch: hasCustomAdapter ? undefined : asBag.fetch,\n webSocketFactory: hasCustomAdapter ? undefined : asBag.webSocketFactory,\n onThreadId: options.onThreadId,\n onCreated: options.onCreated,\n onCompleted: options.onCompleted,\n initialValues: options.initialValues,\n messagesKey: options.messagesKey,\n });\n\n // Deferred dispose: on the next microtask after the owning scope\n // disappears. Mirrors React's StrictMode-safe activate/deactivate\n // pattern — HMR and other scope-reuse scenarios stay clean because\n // `activate()` cancels the pending dispose if the scope survives.\n const deactivate = controller.activate();\n onScopeDispose(deactivate);\n\n // ─── Reactivity adapters — StreamStore → shallowRef ─────────────────\n function bindStore<S>(\n subscribe: (listener: () => void) => () => void,\n getSnapshot: () => S\n ): Readonly<ShallowRef<S>> {\n const ref = shallowRef<S>(getSnapshot());\n const unsubscribe = subscribe(() => {\n ref.value = getSnapshot();\n });\n onScopeDispose(unsubscribe);\n return readonly(ref) as Readonly<ShallowRef<S>>;\n }\n\n const rootRef = bindStore<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.subscribe,\n controller.rootStore.getSnapshot\n );\n const subagentRef = bindStore<SubagentMap>(\n controller.subagentStore.subscribe,\n controller.subagentStore.getSnapshot\n );\n const subgraphRef = bindStore<SubgraphMap>(\n controller.subgraphStore.subscribe,\n controller.subgraphStore.getSnapshot\n );\n const subgraphByNodeRef = bindStore<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.subscribe,\n controller.subgraphByNodeStore.getSnapshot\n );\n\n // Derived refs for individual root-snapshot fields. Using computed\n // means templates that read `values.value` only retrigger when the\n // root snapshot's identity actually changes — we can't split further\n // because `StreamStore` fans the whole snapshot out on every update.\n const values = computed(() => rootRef.value.values);\n const messages = computed(() => rootRef.value.messages);\n const toolCalls = computed(\n () => rootRef.value.toolCalls as InferToolCalls<T>[]\n );\n const interrupts = computed(() =>\n filterOutHeadlessToolInterrupts(rootRef.value.interrupts)\n );\n const interrupt = computed(() => interrupts.value[0]);\n const isLoading = computed(() => rootRef.value.isLoading);\n const isThreadLoading = computed(() => rootRef.value.isThreadLoading);\n const error = computed(() => rootRef.value.error);\n const threadId = computed(() => rootRef.value.threadId);\n const hydrationPromise = computed(() => controller.hydrationPromise);\n\n // Expose the derived refs through a `readonly(shallowRef)` shape to\n // match the rest of the public surface. `computed` already gives us\n // read-only semantics but templates type-check more cleanly when the\n // fully-typed return claims `Readonly<ShallowRef<T>>` everywhere.\n // The cast is safe — a ComputedRef<T> is structurally a\n // Readonly<Ref<T>>.\n const asShallow = <V>(c: ComputedRef<V>): Readonly<ShallowRef<V>> =>\n c as unknown as Readonly<ShallowRef<V>>;\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Re-hydrate whenever the caller's threadId input changes post-setup.\n // The initial hydrate already fired synchronously in the controller\n // constructor, so we skip that first tick; otherwise we'd double-fetch\n // `thread.state.get()`.\n let skipFirstThreadIdWatch = true;\n watch(\n () => toValue(asBag.threadId) ?? null,\n (next) => {\n if (skipFirstThreadIdWatch) {\n skipFirstThreadIdWatch = false;\n return;\n }\n void controller.hydrate(next);\n }\n );\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch root values + protocol interrupts for items targeting a\n // registered tool, invoke the handler, and resume the run with the\n // handler's return value. Dedup via an id set so StrictMode /\n // rerenders don't replay a tool call twice.\n const handledTools = new Set<string>();\n watch(\n () => toValue(asBag.threadId) ?? null,\n () => handledTools.clear()\n );\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n watch(\n () => [rootRef.value.values, rootRef.value.interrupts] as const,\n () => {\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const rootValues = rootRef.value.values;\n const rootInterrupts = rootRef.value.interrupts;\n const bag = rootValues as unknown as Record<string, unknown>;\n const protocolInterrupts = rootInterrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(bag?.__interrupt__)\n ? (bag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0\n ? protocolInterrupts\n : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...bag, __interrupt__: headlessInterrupts },\n tools,\n handledTools,\n {\n onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n controller.submit(null, {\n command,\n } as StreamSubmitOptions<StateType, ConfigurableType>),\n }\n );\n });\n },\n { immediate: true }\n );\n }\n\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n values: asShallow(values) as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"values\"],\n messages: asShallow(messages),\n toolCalls: asShallow(toolCalls),\n interrupts: asShallow(interrupts),\n interrupt,\n isLoading,\n isThreadLoading,\n error,\n threadId,\n hydrationPromise,\n subagents: subagentRef as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"],\n subgraphs: subgraphRef,\n subgraphsByNode: subgraphByNodeRef,\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: (options) => controller.stop(options),\n disconnect: () => controller.disconnect(),\n respond: (response, target) => controller.respond(response, target),\n getThread: () => controller.getThread(),\n client,\n assistantId,\n [STREAM_CONTROLLER]: controller,\n };\n\n return handle;\n}\n\n/**\n * Helper used by the selector composables to reach the underlying\n * {@link ChannelRegistry} from a stream handle. Kept internal —\n * application code should call `useMessages`, `useToolCalls`, etc.\n *\n * @internal\n */\nexport function getRegistry(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream: UseStreamReturn<any, any, any>\n): ChannelRegistry {\n return stream[STREAM_CONTROLLER].registry;\n}\n\nexport type { ThreadStream };\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-stream.js","names":["ClientCtor"],"sources":["../src/use-stream.ts"],"sourcesContent":["import {\n computed,\n onScopeDispose,\n readonly,\n shallowRef,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from \"vue\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n filterOutHeadlessToolInterrupts,\n flushPendingHeadlessToolInterrupts,\n scheduleCoalescedHeadlessToolFlush,\n type AnyHeadlessToolImplementation,\n type OnToolCallback,\n} from \"@langchain/langgraph-sdk\";\nimport {\n Client as ClientCtor,\n type ClientConfig,\n type ThreadStream,\n} from \"@langchain/langgraph-sdk/client\";\nimport {\n StreamController,\n type AgentServerAdapter,\n type AgentServerOptions as StreamAgentServerOptions,\n type ChannelRegistry,\n type CustomAdapterOptions as StreamCustomAdapterOptions,\n type InferStateType,\n type InferSubagentStates,\n type InferToolCalls,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\n type StreamRespondAllOptions,\n type StreamRespondOptions,\n type StreamStopOptions,\n type StreamSubmitOptions,\n type SubagentDiscoverySnapshot,\n type SubagentMap,\n type SubgraphByNodeMap,\n type SubgraphDiscoverySnapshot,\n type SubgraphMap,\n type UseStreamOptions as StreamUseStreamOptions,\n type WidenUpdateMessages,\n} from \"@langchain/langgraph-sdk/stream\";\nimport { inject } from \"vue\";\nimport { LANGCHAIN_OPTIONS } from \"./context.js\";\n\ntype VueThreadId = MaybeRefOrGetter<string | null | undefined>;\ntype VueApiString = MaybeRefOrGetter<string | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, VueThreadId, VueApiString, VueApiString>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, VueThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n VueThreadId,\n VueApiString,\n VueApiString,\n string\n>;\n\n/**\n * Private field on the handle that carries the {@link StreamController}\n * reference. Selector composables read this to reach the shared\n * {@link ChannelRegistry}. Use the selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, …) instead of reading this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/vue/controller\"\n);\n\n/**\n * Vue binding return type for {@link useStream}.\n *\n * Reactive primitives follow Vue conventions:\n *\n * - Data projections are `Readonly<ShallowRef<T>>` / `ComputedRef<T>`\n * so templates auto-unwrap via `msg.value` in `<script setup>`\n * and directly in templates. They are snapshots — never mutate.\n * - Imperative methods (`submit` / `stop` / `respond`) are plain\n * functions — no refs involved.\n * - Identity values captured at setup time (`client` / `assistantId`)\n * are exposed as plain values; if you need to swap the bound agent\n * or client, remount the composable.\n */\nexport interface UseStreamReturn<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n StateType extends object = InferStateType<T>,\n SubagentStates = InferSubagentStates<T>,\n> {\n // ----- always-on root projections -----\n /**\n * The most recent `values`-channel snapshot emitted at the root\n * namespace — i.e. the thread-level state as the server sees it\n * after each superstep. Updated on every root `values` event, not\n * on token-level deltas: if you render `stream.values.value.messages`\n * directly you'll see full turns appear at once instead of\n * streaming token-by-token. Use {@link messages} (or\n * `useMessages`) for the token-streamed view.\n *\n * Equivalent to calling `useValues(stream)`.\n */\n readonly values: Readonly<ShallowRef<StateType>>;\n /**\n * The root message projection. Assembled from two sources and\n * merged in real time:\n *\n * 1. `messages`-channel deltas — token-level streaming events\n * (`message-start`, `content-block-delta`, `message-finish`)\n * emitted by the runtime. These drive live, token-by-token\n * updates.\n * 2. `values.messages` snapshots — the authoritative ordering\n * and any messages the agent produces without token streaming\n * (human turns, tool results, echoes from subagents).\n *\n * If the backend only emits `values` events (no `messages`\n * channel), every message will appear fully-formed on each\n * values update rather than streaming. This is a backend/runtime\n * concern — the Vue layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: Readonly<ShallowRef<BaseMessage[]>>;\n /**\n * Root-namespace tool calls assembled from the `tools` channel.\n * Each entry is a fully parsed {@link AssembledToolCall} with\n * name, args, and id — suitable for rendering approval UIs or\n * forwarding to headless tool handlers.\n *\n * When the stream is typed with an agent brand or tool list,\n * entries are narrowed via {@link InferToolCalls}. Equivalent to\n * calling `useToolCalls(stream)` with no target.\n */\n readonly toolCalls: Readonly<ShallowRef<InferToolCalls<T>[]>>;\n /**\n * All unresolved protocol interrupts observed on the root\n * namespace during the active thread. Populated from lifecycle /\n * input events and seeded on hydration from `thread.getState()`.\n * Cleared optimistically when a new run starts or an interrupt is\n * resolved via {@link respond}.\n */\n readonly interrupts: Readonly<ShallowRef<Interrupt<InterruptType>[]>>;\n /**\n * Convenience alias for {@link interrupts}[0] — the primary\n * interrupt most UIs should act on when only one is pending.\n * `undefined` when no interrupt is active.\n */\n readonly interrupt: ComputedRef<Interrupt<InterruptType> | undefined>;\n /**\n * `true` while a run is active or being started on the current\n * thread. Driven by root-namespace lifecycle events (`running` →\n * `true`, terminal phases → `false`). Use this to disable submit\n * buttons and show in-flight spinners.\n */\n readonly isLoading: ComputedRef<boolean>;\n /**\n * `true` while the initial `thread.getState()` hydration for the\n * active thread is in flight. Distinct from {@link isLoading} —\n * thread loading covers the one-time fetch that seeds\n * {@link values} / {@link messages} before any user submit.\n */\n readonly isThreadLoading: ComputedRef<boolean>;\n /**\n * The last error observed on the active run or hydration attempt.\n * `undefined` when no error has occurred. Cleared optimistically\n * when a new {@link submit} starts.\n */\n readonly error: ComputedRef<unknown>;\n /**\n * Id of the thread the controller is bound to. `null` until the\n * first {@link submit} creates or selects a thread (or until an\n * explicit `threadId` option is provided and hydrated).\n */\n readonly threadId: ComputedRef<string | null>;\n /**\n * Promise that settles when the active thread's initial hydration\n * completes. Exposed so `async setup()` sites can\n * `await stream.hydrationPromise.value` to implement a\n * Suspense-like boundary. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: ComputedRef<Promise<void>>;\n\n // ----- always-on discovery -----\n /**\n * Subagents discovered on the root run. For DeepAgent-typed\n * streams the key set is narrowed to the subagent names declared\n * on the agent brand (`keyof InferSubagentStates<T>`).\n */\n readonly subagents: Readonly<\n ShallowRef<\n ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >\n >\n >;\n /**\n * Subgraphs discovered on the root run.\n *\n * A namespace is classified as a subgraph iff at least one\n * strictly-deeper namespace has been observed with it as a prefix.\n * This is inferred from the lifecycle event stream — plain function\n * nodes (`orchestrator`, `writer` in the nested-stategraph example)\n * never appear here even though the server emits namespaced\n * lifecycle events for them. Promotion is monotonic and retroactive;\n * an entry appears as soon as the first descendant event lands.\n */\n readonly subgraphs: Readonly<\n ShallowRef<ReadonlyMap<string, SubgraphDiscoverySnapshot>>\n >;\n /**\n * Subgraphs indexed by the graph node that produced them\n * (`addNode(\"visualizer_0\", …)`). Each value is an array because\n * parallel fan-outs and loops can spawn multiple invocations of\n * the same node; arrays preserve insertion order. Updates in\n * lock-step with {@link subgraphs}.\n */\n readonly subgraphsByNode: Readonly<\n ShallowRef<ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>>\n >;\n\n // ----- imperatives -----\n /**\n * Dispatch a new run on the bound thread.\n *\n * `input` is typed as `Partial<StateType>` so IDE autocompletion\n * surfaces the state keys declared on the root composable.\n */\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n /**\n * Stop the active run on the current thread. By default cancels the\n * run server-side and disconnects the client; pass `{ cancel: false }`\n * or use {@link disconnect} for join/rejoin. Sets {@link isLoading} to\n * `false` immediately; {@link values} and {@link messages} are preserved.\n */\n stop(options?: StreamStopOptions): Promise<void>;\n /**\n * Disconnect the client without cancelling the run server-side.\n * Alias for `stop({ cancel: false })`.\n */\n disconnect(): Promise<void>;\n /**\n * Resume a pending protocol interrupt by sending a response payload\n * back to the interrupted namespace.\n *\n * When `options.interruptId` is omitted, walks `getThread()?.interrupts`\n * from newest to oldest and resumes the first not yet resolved by a prior\n * `respond()` call. That may be a root or subgraph interrupt and is\n * **not** necessarily {@link interrupt} (`interrupts[0]`, root-only).\n * Safe when exactly one interrupt is pending; otherwise pass an explicit\n * `options.interruptId` (and `options.namespace` for subgraph\n * interrupts).\n *\n * The server validates `namespace` against the pending interrupt. Root\n * interrupts use `namespace: []` (default when omitted). For subgraph\n * interrupts, copy `namespace` from `getThread()?.interrupts`.\n *\n * @example\n * ```ts\n * // Single pending interrupt\n * await stream.respond({ approved: true });\n * ```\n *\n * @example\n * ```tsx\n * // Multiple root interrupts\n * for (const intr of stream.interrupts.value) {\n * await stream.respond(decide(intr.value), { interruptId: intr.id! });\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Subgraph interrupt — namespace from `getThread()`\n * const thread = stream.getThread();\n * for (const entry of thread?.interrupts ?? []) {\n * await stream.respond(buildResponse(entry.payload), {\n * interruptId: entry.interruptId,\n * namespace: entry.namespace,\n * });\n * }\n * ```\n *\n * To resume several interrupts pending at the same checkpoint in one\n * command, use {@link respondAll}.\n */\n respond(\n response: unknown,\n options?: StreamRespondOptions<ConfigurableType>\n ): Promise<void>;\n\n /**\n * Resume several pending interrupts at the same checkpoint in a single\n * command — required when a run pauses on multiple interrupts at once\n * (e.g. parallel tool-authorization prompts), which sequential\n * {@link respond} calls cannot handle. `responsesById` maps each pending\n * `interruptId` to its response, so different interrupts can receive\n * different payloads. Pass `options.config` / `options.metadata` to fold\n * run-level config and metadata into the resumed run, mirroring\n * `submit()`.\n *\n * @example\n * ```ts\n * await stream.respondAll({\n * [interruptA.id]: { approved: true },\n * [interruptB.id]: { approved: false },\n * });\n * ```\n */\n respondAll(\n responsesById: Record<string, unknown>,\n options?: StreamRespondAllOptions<ConfigurableType>\n ): Promise<void>;\n\n // ----- identity -----\n /** LangGraph SDK client used to construct thread streams. */\n readonly client: Client;\n /** Assistant id the thread is bound to for its lifetime. */\n readonly assistantId: string;\n\n /**\n * Returns the bound {@link ThreadStream}, if one exists (`undefined`\n * until the thread is hydrated or the first submit completes). Prefer\n * the projections and selector composables for UI work; use this for\n * low-level protocol access (raw subscriptions, state commands, etc.).\n */\n getThread(): ThreadStream | undefined;\n\n /** @internal Used by selector composables. */\n readonly [STREAM_CONTROLLER]: StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >;\n}\n\n/**\n * Erased handle useful as a parameter type for helpers and wrapper\n * components that pass a `stream` through to selector composables\n * without reading `values` directly. Mirrors the React\n * `AnyStream` alias.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyStream = UseStreamReturn<any, any, any>;\n\n/** Convenience alias for the fully-resolved stream handle type. */\nexport type UseStreamResult<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n> = UseStreamReturn<T, InterruptType, ConfigurableType>;\n\n/**\n * Vue Composition API binding for the v2-native stream runtime.\n *\n * Returns a handle whose projections are Vue refs so templates\n * auto-unwrap and scripts can feed them into `computed`/`watch`.\n * Scoped views (subagents, subgraphs, any namespaced projection) are\n * surfaced via the companion selector composables (`useMessages`,\n * `useToolCalls`, `useValues`, `useMessageMetadata`,\n * `useSubmissionQueue`, `useExtension`, `useChannel`, plus media\n * composables).\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useStream } from \"@langchain/vue\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"msg in stream.messages.value\" :key=\"msg.id\">\n * {{ msg.content }}\n * </div>\n * <button @click=\"stream.submit({ messages: [{ type: 'human', content: 'Hi' }] })\">\n * Send\n * </button>\n * </template>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at setup time.\n * To bind a new assistant/transport, remount the component. Reactive\n * inputs (`threadId`, `apiUrl`, `apiKey`) trigger in-place behaviour\n * changes on the active controller.\n */\nexport function useStream<\n T = Record<string, unknown>,\n InterruptType = unknown,\n ConfigurableType extends object = Record<string, unknown>,\n>(\n options: UseStreamOptions<InferStateType<T>>\n): UseStreamReturn<T, InterruptType, ConfigurableType> {\n type StateType = InferStateType<T>;\n\n interface OptionsBag {\n assistantId?: string;\n threadId?: MaybeRefOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: MaybeRefOrGetter<string | undefined>;\n apiKey?: MaybeRefOrGetter<string | undefined>;\n callerOptions?: ClientConfig[\"callerOptions\"];\n defaultHeaders?: ClientConfig[\"defaultHeaders\"];\n transport?: \"sse\" | \"websocket\" | AgentServerAdapter;\n fetch?: typeof fetch;\n webSocketFactory?: (url: string) => WebSocket;\n onThreadId?: (threadId: string) => void;\n onCreated?: (info: RunExecutionInfo) => void;\n onCompleted?: (info: RunCompletedInfo) => void;\n initialValues?: StateType;\n messagesKey?: string;\n tools?: AnyHeadlessToolImplementation[];\n onTool?: OnToolCallback;\n }\n const asBag = options as OptionsBag;\n\n // Inherit missing apiUrl / apiKey / client from any LangChainPlugin\n // installed on the app. Vue's `inject` returns `undefined` if the\n // key was never provided; that's fine — we only merge when the\n // caller didn't set a value.\n const pluginOptions =\n inject(LANGCHAIN_OPTIONS, undefined) ?? ({} as Record<string, unknown>);\n\n const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // ─── Client construction ────────────────────────────────────────────\n //\n // Identity-stable per setup. Watches apiUrl/apiKey refs so callers\n // that flip a backend at runtime get a fresh client without a full\n // remount — the controller is swapped in lock-step below.\n const resolveApiUrl = () =>\n toValue(asBag.apiUrl) ?? (pluginOptions as { apiUrl?: string }).apiUrl;\n const resolveApiKey = () =>\n toValue(asBag.apiKey) ?? (pluginOptions as { apiKey?: string }).apiKey;\n const explicitClient =\n asBag.client ?? (pluginOptions as { client?: Client }).client;\n\n const clientRef = shallowRef<Client>(\n explicitClient ??\n (new ClientCtor({\n apiUrl: resolveApiUrl(),\n apiKey: resolveApiKey(),\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client)\n );\n\n // Note: we intentionally bind the controller to the *initial* client\n // instance. A dynamic client swap would require tearing the\n // controller down (in-flight subscriptions, queue, hydration), so we\n // keep the rule simple: client is captured at setup. Mirrors React\n // v1 which bakes `useMemo` on `[client, assistantId, transport]`.\n const client = clientRef.value;\n\n // Custom adapters may omit `assistantId`; the controller still\n // requires one so it has something to forward to `threads.stream`.\n const sentinel = \"_\";\n const assistantId =\n \"assistantId\" in options ? (options.assistantId ?? sentinel) : sentinel;\n\n const initialThreadId = toValue(asBag.threadId) ?? null;\n\n // ─── Controller construction ────────────────────────────────────────\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n client: client as unknown as Client<StateType>,\n threadId: initialThreadId,\n transport,\n fetch: hasCustomAdapter ? undefined : asBag.fetch,\n webSocketFactory: hasCustomAdapter ? undefined : asBag.webSocketFactory,\n onThreadId: options.onThreadId,\n onCreated: options.onCreated,\n onCompleted: options.onCompleted,\n initialValues: options.initialValues,\n messagesKey: options.messagesKey,\n });\n\n // Deferred dispose: on the next microtask after the owning scope\n // disappears. Mirrors React's StrictMode-safe activate/deactivate\n // pattern — HMR and other scope-reuse scenarios stay clean because\n // `activate()` cancels the pending dispose if the scope survives.\n const deactivate = controller.activate();\n onScopeDispose(deactivate);\n\n // ─── Reactivity adapters — StreamStore → shallowRef ─────────────────\n function bindStore<S>(\n subscribe: (listener: () => void) => () => void,\n getSnapshot: () => S\n ): Readonly<ShallowRef<S>> {\n const ref = shallowRef<S>(getSnapshot());\n const unsubscribe = subscribe(() => {\n ref.value = getSnapshot();\n });\n onScopeDispose(unsubscribe);\n return readonly(ref) as Readonly<ShallowRef<S>>;\n }\n\n const rootRef = bindStore<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.subscribe,\n controller.rootStore.getSnapshot\n );\n const subagentRef = bindStore<SubagentMap>(\n controller.subagentStore.subscribe,\n controller.subagentStore.getSnapshot\n );\n const subgraphRef = bindStore<SubgraphMap>(\n controller.subgraphStore.subscribe,\n controller.subgraphStore.getSnapshot\n );\n const subgraphByNodeRef = bindStore<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.subscribe,\n controller.subgraphByNodeStore.getSnapshot\n );\n\n // Derived refs for individual root-snapshot fields. Using computed\n // means templates that read `values.value` only retrigger when the\n // root snapshot's identity actually changes — we can't split further\n // because `StreamStore` fans the whole snapshot out on every update.\n const values = computed(() => rootRef.value.values);\n const messages = computed(() => rootRef.value.messages);\n const toolCalls = computed(\n () => rootRef.value.toolCalls as InferToolCalls<T>[]\n );\n const interrupts = computed(() =>\n filterOutHeadlessToolInterrupts(rootRef.value.interrupts)\n );\n const interrupt = computed(() => interrupts.value[0]);\n const isLoading = computed(() => rootRef.value.isLoading);\n const isThreadLoading = computed(() => rootRef.value.isThreadLoading);\n const error = computed(() => rootRef.value.error);\n const threadId = computed(() => rootRef.value.threadId);\n const hydrationPromise = computed(() => controller.hydrationPromise);\n\n // Expose the derived refs through a `readonly(shallowRef)` shape to\n // match the rest of the public surface. `computed` already gives us\n // read-only semantics but templates type-check more cleanly when the\n // fully-typed return claims `Readonly<ShallowRef<T>>` everywhere.\n // The cast is safe — a ComputedRef<T> is structurally a\n // Readonly<Ref<T>>.\n const asShallow = <V>(c: ComputedRef<V>): Readonly<ShallowRef<V>> =>\n c as unknown as Readonly<ShallowRef<V>>;\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Re-hydrate whenever the caller's threadId input changes post-setup.\n // The initial hydrate already fired synchronously in the controller\n // constructor, so we skip that first tick; otherwise we'd double-fetch\n // `thread.state.get()`.\n let skipFirstThreadIdWatch = true;\n watch(\n () => toValue(asBag.threadId) ?? null,\n (next) => {\n if (skipFirstThreadIdWatch) {\n skipFirstThreadIdWatch = false;\n return;\n }\n void controller.hydrate(next);\n }\n );\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch root values + protocol interrupts for items targeting a\n // registered tool, invoke the handler, and resume the run with the\n // handler's return value. Dedup via an id set so StrictMode /\n // rerenders don't replay a tool call twice.\n const handledTools = new Set<string>();\n watch(\n () => toValue(asBag.threadId) ?? null,\n () => handledTools.clear()\n );\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n watch(\n () => [rootRef.value.values, rootRef.value.interrupts] as const,\n () => {\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const rootValues = rootRef.value.values;\n const rootInterrupts = rootRef.value.interrupts;\n const bag = rootValues as unknown as Record<string, unknown>;\n const protocolInterrupts = rootInterrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(bag?.__interrupt__)\n ? (bag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0\n ? protocolInterrupts\n : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...bag, __interrupt__: headlessInterrupts },\n tools,\n handledTools,\n {\n onTool,\n defer: (run) => {\n void Promise.resolve().then(run);\n },\n resumeSubmit: (command) =>\n controller.submit(null, {\n command,\n } as StreamSubmitOptions<StateType, ConfigurableType>),\n }\n );\n });\n },\n { immediate: true }\n );\n }\n\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n values: asShallow(values) as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"values\"],\n messages: asShallow(messages),\n toolCalls: asShallow(toolCalls),\n interrupts: asShallow(interrupts),\n interrupt,\n isLoading,\n isThreadLoading,\n error,\n threadId,\n hydrationPromise,\n subagents: subagentRef as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"],\n subgraphs: subgraphRef,\n subgraphsByNode: subgraphByNodeRef,\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: (options) => controller.stop(options),\n disconnect: () => controller.disconnect(),\n respond: (response, options) => controller.respond(response, options),\n respondAll: (responsesById, options) =>\n controller.respondAll(responsesById, options),\n getThread: () => controller.getThread(),\n client,\n assistantId,\n [STREAM_CONTROLLER]: controller,\n };\n\n return handle;\n}\n\n/**\n * Helper used by the selector composables to reach the underlying\n * {@link ChannelRegistry} from a stream handle. Kept internal —\n * application code should call `useMessages`, `useToolCalls`, etc.\n *\n * @internal\n */\nexport function getRegistry(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stream: UseStreamReturn<any, any, any>\n): ChannelRegistry {\n return stream[STREAM_CONTROLLER].registry;\n}\n\nexport type { ThreadStream };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/vue",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "Vue integration for LangGraph & LangChain",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,13 +10,13 @@
10
10
  "directory": "libs/sdk-vue"
11
11
  },
12
12
  "dependencies": {
13
- "@langchain/langgraph-sdk": "1.9.9"
13
+ "@langchain/langgraph-sdk": "1.9.10"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@hono/node-server": "^1.19.13",
17
17
  "@hono/node-ws": "^1.3.0",
18
18
  "@langchain/core": "^1.1.44",
19
- "@langchain/protocol": "^0.0.15",
19
+ "@langchain/protocol": "^0.0.16",
20
20
  "@types/node": "^25.4.0",
21
21
  "@vitejs/plugin-vue": "^6.0.6",
22
22
  "@vitejs/plugin-vue-jsx": "^5.1.5",
@@ -32,8 +32,8 @@
32
32
  "webdriverio": "^9.25.0",
33
33
  "zod": "^4.3.6",
34
34
  "@langchain/langgraph": "1.3.2",
35
- "@langchain/langgraph-api": "1.2.2",
36
- "@langchain/langgraph-checkpoint": "1.0.2"
35
+ "@langchain/langgraph-api": "1.2.3",
36
+ "@langchain/langgraph-checkpoint": "1.0.3"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@langchain/core": "^1.1.44",