@langchain/svelte 1.0.5 → 1.0.7

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.
@@ -112,18 +112,22 @@ function useStream(options) {
112
112
  handledTools.clear();
113
113
  handledForThreadId = currentThreadId;
114
114
  }
115
- const valuesBag = rootSnapshot.values;
116
- const combined = [...Array.isArray(valuesBag?.__interrupt__) ? valuesBag.__interrupt__ : [], ...rootSnapshot.interrupts];
117
- if (combined.length === 0) return;
118
- (0, _langchain_langgraph_sdk.flushPendingHeadlessToolInterrupts)({
119
- ...valuesBag,
120
- __interrupt__: combined
121
- }, tools, handledTools, {
122
- onTool,
123
- defer: (run) => {
124
- Promise.resolve().then(run);
125
- },
126
- resumeSubmit: (command) => controller.submit(null, { command })
115
+ (0, _langchain_langgraph_sdk.scheduleCoalescedHeadlessToolFlush)(handledTools, () => {
116
+ const valuesBag = rootSnapshot.values;
117
+ const protocolInterrupts = rootSnapshot.interrupts;
118
+ const valuesInterrupts = Array.isArray(valuesBag?.__interrupt__) ? valuesBag.__interrupt__ : [];
119
+ const headlessInterrupts = protocolInterrupts.length > 0 ? protocolInterrupts : valuesInterrupts;
120
+ if (headlessInterrupts.length === 0) return;
121
+ (0, _langchain_langgraph_sdk.flushPendingHeadlessToolInterrupts)({
122
+ ...valuesBag,
123
+ __interrupt__: headlessInterrupts
124
+ }, tools, handledTools, {
125
+ onTool,
126
+ defer: (run) => {
127
+ Promise.resolve().then(run);
128
+ },
129
+ resumeSubmit: (command) => controller.submit(null, { command })
130
+ });
127
131
  });
128
132
  });
129
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.svelte.cjs","names":["ClientCtor","StreamController"],"sources":["../src/use-stream.svelte.ts"],"sourcesContent":["import { onDestroy } from \"svelte\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n flushPendingHeadlessToolInterrupts,\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 InferToolCalls,\n type InferSubagentStates,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\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\";\n\n/**\n * A value that may be either a plain `T` or a getter `() => T`. Used\n * for reactive-capable option inputs (currently `threadId` only). When\n * a getter is passed the composable tracks it via `$effect` and\n * re-hydrates when the returned value changes.\n */\nexport type ValueOrGetter<T> = T | (() => T);\n\nfunction readValueOrGetter<T>(\n input: ValueOrGetter<T> | undefined\n): T | undefined {\n if (typeof input === \"function\") return (input as () => T)();\n return input;\n}\n\ntype SvelteThreadId = ValueOrGetter<string | null | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, SvelteThreadId>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, SvelteThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n SvelteThreadId,\n string | undefined,\n string | undefined,\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\n * (`useMessages`, `useToolCalls`, `useValues`, …) instead of reading\n * this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/svelte/controller\"\n);\n\n/**\n * Svelte binding return type for {@link useStream}. Reactive\n * projections are exposed as getters on a stable object so templates\n * can read `stream.messages` directly without a `.value` / `.current`\n * hop and `$derived` wrappers auto-track the getter read.\n *\n * Destructuring (`const { messages } = stream`) breaks reactivity —\n * this is a Svelte 5 constraint and applies to every getter-object\n * pattern. Access fields through the live `stream` handle instead.\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 readonly values: StateType;\n readonly messages: BaseMessage[];\n readonly toolCalls: InferToolCalls<T>[];\n readonly interrupts: Interrupt<InterruptType>[];\n readonly interrupt: Interrupt<InterruptType> | undefined;\n readonly isLoading: boolean;\n readonly isThreadLoading: boolean;\n readonly error: unknown;\n readonly threadId: string | null;\n /**\n * Promise that settles when the current thread's initial hydration\n * completes. Useful in SvelteKit `load()` handlers (or any\n * async-init site) to block until the controller has reconciled\n * with server-held state.\n */\n readonly hydrationPromise: Promise<void>;\n\n readonly subagents: ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >;\n readonly subgraphs: ReadonlyMap<string, SubgraphDiscoverySnapshot>;\n readonly subgraphsByNode: ReadonlyMap<\n string,\n readonly SubgraphDiscoverySnapshot[]\n >;\n\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n stop(): Promise<void>;\n respond(\n response: unknown,\n target?: { interruptId: string; namespace?: string[] }\n ): Promise<void>;\n\n readonly client: Client;\n readonly assistantId: string;\n\n /** v2 escape hatch — returns the bound {@link ThreadStream}. */\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/**\n * Svelte 5 binding for the v2-native stream runtime.\n *\n * Returns a handle whose reactive fields are plain getters on a\n * stable object — templates can read `stream.messages` directly and\n * `$derived(stream.isLoading)` auto-tracks the getter.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from \"@langchain/svelte\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * {#each stream.messages as msg (msg.id)}\n * <div>{msg.content}</div>\n * {/each}\n * <button onclick={() =>\n * stream.submit({ messages: [{ type: \"human\", content: \"Hi\" }] })\n * }>\n * Send\n * </button>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at composable\n * init. To bind a new assistant/transport, remount the component.\n * Only `threadId` is treated as reactive — pass it as a getter\n * (`threadId: () => active`) to drive an in-place thread swap.\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?: ValueOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: string;\n apiKey?: string;\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 const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // Client construction — captured once at init. Consumers that need\n // to swap `apiUrl`/`apiKey` at runtime remount the owning component.\n const client: Client =\n asBag.client ??\n (new ClientCtor({\n apiUrl: asBag.apiUrl,\n apiKey: asBag.apiKey,\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client);\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 = readValueOrGetter(asBag.threadId) ?? null;\n\n // Plain `let` binding, not `$state`: the controller holds maps of\n // listeners, Promises, and the live `ThreadStream`, none of which\n // survive Svelte's deep `$state` proxy wrapping.\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n // `Client` is state-shape agnostic at runtime; the controller\n // advertises `Client<StateType>` on its public type for ergonomics.\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: mirrors React's activate/dispose pattern so HMR\n // and other scope-reuse scenarios stay clean. `activate()` cancels\n // a pending dispose if the owning scope survives.\n const deactivate = controller.activate();\n onDestroy(deactivate);\n\n // ─── Reactive state bridges ─────────────────────────────────────────\n //\n // Each always-on `StreamStore` is wrapped in a runes `$state` slot\n // seeded from `getSnapshot()` and kept in sync via `store.subscribe`.\n // Subscriptions are torn down on component destroy.\n let rootSnapshot = $state<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.getSnapshot()\n );\n const unsubscribeRoot = controller.rootStore.subscribe(() => {\n rootSnapshot = controller.rootStore.getSnapshot();\n });\n onDestroy(unsubscribeRoot);\n\n let subagentSnapshot = $state<SubagentMap>(\n controller.subagentStore.getSnapshot()\n );\n const unsubscribeSubagents = controller.subagentStore.subscribe(() => {\n subagentSnapshot = controller.subagentStore.getSnapshot();\n });\n onDestroy(unsubscribeSubagents);\n\n let subgraphSnapshot = $state<SubgraphMap>(\n controller.subgraphStore.getSnapshot()\n );\n const unsubscribeSubgraphs = controller.subgraphStore.subscribe(() => {\n subgraphSnapshot = controller.subgraphStore.getSnapshot();\n });\n onDestroy(unsubscribeSubgraphs);\n\n let subgraphByNodeSnapshot = $state<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.getSnapshot()\n );\n const unsubscribeSubgraphByNode = controller.subgraphByNodeStore.subscribe(\n () => {\n subgraphByNodeSnapshot = controller.subgraphByNodeStore.getSnapshot();\n }\n );\n onDestroy(unsubscribeSubgraphByNode);\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Only matters when the caller passed a getter. The initial hydrate\n // already fired in the controller constructor, so skip the first\n // tick to avoid a redundant `thread.state.get()`.\n if (typeof asBag.threadId === \"function\") {\n const getThreadId = asBag.threadId;\n let previousThreadId = initialThreadId;\n $effect(() => {\n const next = (getThreadId() ?? null) as string | null;\n if (next === previousThreadId) return;\n previousThreadId = next;\n void controller.hydrate(next);\n });\n }\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch the root `values.__interrupt__` key plus the protocol-\n // surfaced interrupts for items targeting a registered tool, invoke\n // the handler, and resume the run with the handler's return value.\n // Dedup via an id set so rerenders don't replay a tool call twice.\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n const handledTools = new Set<string>();\n let handledForThreadId: string | null = initialThreadId;\n $effect(() => {\n // Reset dedup set when the active thread id changes — a fresh\n // thread may legitimately re-emit a tool-call id we've seen.\n const currentThreadId = rootSnapshot.threadId;\n if (currentThreadId !== handledForThreadId) {\n handledTools.clear();\n handledForThreadId = currentThreadId;\n }\n\n const valuesBag = rootSnapshot.values as unknown as Record<\n string,\n unknown\n >;\n const existing = Array.isArray(valuesBag?.__interrupt__)\n ? (valuesBag.__interrupt__ as Interrupt[])\n : [];\n const combined: Interrupt[] = [\n ...existing,\n ...(rootSnapshot.interrupts as unknown as Interrupt[]),\n ];\n if (combined.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...valuesBag, __interrupt__: combined },\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\n // ─── Public handle ──────────────────────────────────────────────────\n //\n // Single stable object with getters. Getters read the runes\n // `$state` slots, which drives template reactivity automatically.\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n get values() {\n return rootSnapshot.values;\n },\n get messages() {\n return rootSnapshot.messages;\n },\n get toolCalls() {\n return rootSnapshot.toolCalls as InferToolCalls<T>[];\n },\n get interrupts() {\n return rootSnapshot.interrupts;\n },\n get interrupt() {\n return rootSnapshot.interrupt;\n },\n get isLoading() {\n return rootSnapshot.isLoading;\n },\n get isThreadLoading() {\n return rootSnapshot.isThreadLoading;\n },\n get error() {\n return rootSnapshot.error;\n },\n get threadId() {\n return rootSnapshot.threadId;\n },\n get hydrationPromise() {\n return controller.hydrationPromise;\n },\n get subagents() {\n return subagentSnapshot as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"];\n },\n get subgraphs() {\n return subgraphSnapshot;\n },\n get subgraphsByNode() {\n return subgraphByNodeSnapshot;\n },\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: () => controller.stop(),\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/** 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 * 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.svelte.cjs","names":["ClientCtor","StreamController"],"sources":["../src/use-stream.svelte.ts"],"sourcesContent":["import { onDestroy } from \"svelte\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\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 InferToolCalls,\n type InferSubagentStates,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\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\";\n\n/**\n * A value that may be either a plain `T` or a getter `() => T`. Used\n * for reactive-capable option inputs (currently `threadId` only). When\n * a getter is passed the composable tracks it via `$effect` and\n * re-hydrates when the returned value changes.\n */\nexport type ValueOrGetter<T> = T | (() => T);\n\nfunction readValueOrGetter<T>(\n input: ValueOrGetter<T> | undefined\n): T | undefined {\n if (typeof input === \"function\") return (input as () => T)();\n return input;\n}\n\ntype SvelteThreadId = ValueOrGetter<string | null | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, SvelteThreadId>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, SvelteThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n SvelteThreadId,\n string | undefined,\n string | undefined,\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\n * (`useMessages`, `useToolCalls`, `useValues`, …) instead of reading\n * this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/svelte/controller\"\n);\n\n/**\n * Svelte binding return type for {@link useStream}. Reactive\n * projections are exposed as getters on a stable object so templates\n * can read `stream.messages` directly without a `.value` / `.current`\n * hop and `$derived` wrappers auto-track the getter read.\n *\n * Destructuring (`const { messages } = stream`) breaks reactivity —\n * this is a Svelte 5 constraint and applies to every getter-object\n * pattern. Access fields through the live `stream` handle instead.\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.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: 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 Svelte layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: 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: 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: 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: 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: 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: 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: 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: string | null;\n /**\n * Promise that settles when the current thread's initial hydration\n * completes. Useful in SvelteKit `load()` handlers (or any\n * async-init site) to block until the controller has reconciled\n * with server-held state. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: 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: ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\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: ReadonlyMap<string, SubgraphDiscoverySnapshot>;\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: ReadonlyMap<\n string,\n 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 * Abort the in-flight run on the current thread without clearing\n * accumulated state. Sets {@link isLoading} to `false` immediately;\n * {@link values} and {@link messages} are preserved.\n */\n stop(): 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/**\n * Svelte 5 binding for the v2-native stream runtime.\n *\n * Returns a handle whose reactive fields are plain getters on a\n * stable object — templates can read `stream.messages` directly and\n * `$derived(stream.isLoading)` auto-tracks the getter.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from \"@langchain/svelte\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * {#each stream.messages as msg (msg.id)}\n * <div>{msg.content}</div>\n * {/each}\n * <button onclick={() =>\n * stream.submit({ messages: [{ type: \"human\", content: \"Hi\" }] })\n * }>\n * Send\n * </button>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at composable\n * init. To bind a new assistant/transport, remount the component.\n * Only `threadId` is treated as reactive — pass it as a getter\n * (`threadId: () => active`) to drive an in-place thread swap.\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?: ValueOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: string;\n apiKey?: string;\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 const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // Client construction — captured once at init. Consumers that need\n // to swap `apiUrl`/`apiKey` at runtime remount the owning component.\n const client: Client =\n asBag.client ??\n (new ClientCtor({\n apiUrl: asBag.apiUrl,\n apiKey: asBag.apiKey,\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client);\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 = readValueOrGetter(asBag.threadId) ?? null;\n\n // Plain `let` binding, not `$state`: the controller holds maps of\n // listeners, Promises, and the live `ThreadStream`, none of which\n // survive Svelte's deep `$state` proxy wrapping.\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n // `Client` is state-shape agnostic at runtime; the controller\n // advertises `Client<StateType>` on its public type for ergonomics.\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: mirrors React's activate/dispose pattern so HMR\n // and other scope-reuse scenarios stay clean. `activate()` cancels\n // a pending dispose if the owning scope survives.\n const deactivate = controller.activate();\n onDestroy(deactivate);\n\n // ─── Reactive state bridges ─────────────────────────────────────────\n //\n // Each always-on `StreamStore` is wrapped in a runes `$state` slot\n // seeded from `getSnapshot()` and kept in sync via `store.subscribe`.\n // Subscriptions are torn down on component destroy.\n let rootSnapshot = $state<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.getSnapshot()\n );\n const unsubscribeRoot = controller.rootStore.subscribe(() => {\n rootSnapshot = controller.rootStore.getSnapshot();\n });\n onDestroy(unsubscribeRoot);\n\n let subagentSnapshot = $state<SubagentMap>(\n controller.subagentStore.getSnapshot()\n );\n const unsubscribeSubagents = controller.subagentStore.subscribe(() => {\n subagentSnapshot = controller.subagentStore.getSnapshot();\n });\n onDestroy(unsubscribeSubagents);\n\n let subgraphSnapshot = $state<SubgraphMap>(\n controller.subgraphStore.getSnapshot()\n );\n const unsubscribeSubgraphs = controller.subgraphStore.subscribe(() => {\n subgraphSnapshot = controller.subgraphStore.getSnapshot();\n });\n onDestroy(unsubscribeSubgraphs);\n\n let subgraphByNodeSnapshot = $state<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.getSnapshot()\n );\n const unsubscribeSubgraphByNode = controller.subgraphByNodeStore.subscribe(\n () => {\n subgraphByNodeSnapshot = controller.subgraphByNodeStore.getSnapshot();\n }\n );\n onDestroy(unsubscribeSubgraphByNode);\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Only matters when the caller passed a getter. The initial hydrate\n // already fired in the controller constructor, so skip the first\n // tick to avoid a redundant `thread.state.get()`.\n if (typeof asBag.threadId === \"function\") {\n const getThreadId = asBag.threadId;\n let previousThreadId = initialThreadId;\n $effect(() => {\n const next = (getThreadId() ?? null) as string | null;\n if (next === previousThreadId) return;\n previousThreadId = next;\n void controller.hydrate(next);\n });\n }\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch the root `values.__interrupt__` key plus the protocol-\n // surfaced interrupts for items targeting a registered tool, invoke\n // the handler, and resume the run with the handler's return value.\n // Dedup via an id set so rerenders don't replay a tool call twice.\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n const handledTools = new Set<string>();\n let handledForThreadId: string | null = initialThreadId;\n $effect(() => {\n // Reset dedup set when the active thread id changes — a fresh\n // thread may legitimately re-emit a tool-call id we've seen.\n const currentThreadId = rootSnapshot.threadId;\n if (currentThreadId !== handledForThreadId) {\n handledTools.clear();\n handledForThreadId = currentThreadId;\n }\n\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const valuesBag = rootSnapshot.values as unknown as Record<\n string,\n unknown\n >;\n const protocolInterrupts =\n rootSnapshot.interrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(valuesBag?.__interrupt__)\n ? (valuesBag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0 ? protocolInterrupts : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...valuesBag, __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 }\n\n // ─── Public handle ──────────────────────────────────────────────────\n //\n // Single stable object with getters. Getters read the runes\n // `$state` slots, which drives template reactivity automatically.\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n get values() {\n return rootSnapshot.values;\n },\n get messages() {\n return rootSnapshot.messages;\n },\n get toolCalls() {\n return rootSnapshot.toolCalls as InferToolCalls<T>[];\n },\n get interrupts() {\n return rootSnapshot.interrupts;\n },\n get interrupt() {\n return rootSnapshot.interrupt;\n },\n get isLoading() {\n return rootSnapshot.isLoading;\n },\n get isThreadLoading() {\n return rootSnapshot.isThreadLoading;\n },\n get error() {\n return rootSnapshot.error;\n },\n get threadId() {\n return rootSnapshot.threadId;\n },\n get hydrationPromise() {\n return controller.hydrationPromise;\n },\n get subagents() {\n return subagentSnapshot as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"];\n },\n get subgraphs() {\n return subgraphSnapshot;\n },\n get subgraphsByNode() {\n return subgraphByNodeSnapshot;\n },\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: () => controller.stop(),\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/** 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 * 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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"}
@@ -34,34 +34,163 @@ declare const STREAM_CONTROLLER: unique symbol;
34
34
  * pattern. Access fields through the live `stream` handle instead.
35
35
  */
36
36
  interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown, ConfigurableType extends object = Record<string, unknown>, StateType extends object = InferStateType<T>, SubagentStates = InferSubagentStates<T>> {
37
+ /**
38
+ * The most recent `values`-channel snapshot emitted at the root
39
+ * namespace — i.e. the thread-level state as the server sees it
40
+ * after each superstep. Updated on every root `values` event, not
41
+ * on token-level deltas: if you render `stream.values.messages`
42
+ * directly you'll see full turns appear at once instead of
43
+ * streaming token-by-token. Use {@link messages} (or
44
+ * `useMessages`) for the token-streamed view.
45
+ *
46
+ * Equivalent to calling `useValues(stream)`.
47
+ */
37
48
  readonly values: StateType;
49
+ /**
50
+ * The root message projection. Assembled from two sources and
51
+ * merged in real time:
52
+ *
53
+ * 1. `messages`-channel deltas — token-level streaming events
54
+ * (`message-start`, `content-block-delta`, `message-finish`)
55
+ * emitted by the runtime. These drive live, token-by-token
56
+ * updates.
57
+ * 2. `values.messages` snapshots — the authoritative ordering
58
+ * and any messages the agent produces without token streaming
59
+ * (human turns, tool results, echoes from subagents).
60
+ *
61
+ * If the backend only emits `values` events (no `messages`
62
+ * channel), every message will appear fully-formed on each
63
+ * values update rather than streaming. This is a backend/runtime
64
+ * concern — the Svelte layer faithfully renders whatever the
65
+ * server sends.
66
+ *
67
+ * Equivalent to calling `useMessages(stream)` with no target.
68
+ */
38
69
  readonly messages: BaseMessage[];
70
+ /**
71
+ * Root-namespace tool calls assembled from the `tools` channel.
72
+ * Each entry is a fully parsed {@link AssembledToolCall} with
73
+ * name, args, and id — suitable for rendering approval UIs or
74
+ * forwarding to headless tool handlers.
75
+ *
76
+ * When the stream is typed with an agent brand or tool list,
77
+ * entries are narrowed via {@link InferToolCalls}. Equivalent to
78
+ * calling `useToolCalls(stream)` with no target.
79
+ */
39
80
  readonly toolCalls: InferToolCalls<T>[];
81
+ /**
82
+ * All unresolved protocol interrupts observed on the root
83
+ * namespace during the active thread. Populated from lifecycle /
84
+ * input events and seeded on hydration from `thread.getState()`.
85
+ * Cleared optimistically when a new run starts or an interrupt is
86
+ * resolved via {@link respond} / `submit({ command: { resume } })`.
87
+ */
40
88
  readonly interrupts: Interrupt<InterruptType>[];
89
+ /**
90
+ * Convenience alias for {@link interrupts}[0] — the primary
91
+ * interrupt most UIs should act on when only one is pending.
92
+ * `undefined` when no interrupt is active.
93
+ */
41
94
  readonly interrupt: Interrupt<InterruptType> | undefined;
95
+ /**
96
+ * `true` while a run is active or being started on the current
97
+ * thread. Driven by root-namespace lifecycle events (`running` →
98
+ * `true`, terminal phases → `false`). Use this to disable submit
99
+ * buttons and show in-flight spinners.
100
+ */
42
101
  readonly isLoading: boolean;
102
+ /**
103
+ * `true` while the initial `thread.getState()` hydration for the
104
+ * active thread is in flight. Distinct from {@link isLoading} —
105
+ * thread loading covers the one-time fetch that seeds
106
+ * {@link values} / {@link messages} before any user submit.
107
+ */
43
108
  readonly isThreadLoading: boolean;
109
+ /**
110
+ * The last error observed on the active run or hydration attempt.
111
+ * `undefined` when no error has occurred. Cleared optimistically
112
+ * when a new {@link submit} starts.
113
+ */
44
114
  readonly error: unknown;
115
+ /**
116
+ * Id of the thread the controller is bound to. `null` until the
117
+ * first {@link submit} creates or selects a thread (or until an
118
+ * explicit `threadId` option is provided and hydrated).
119
+ */
45
120
  readonly threadId: string | null;
46
121
  /**
47
122
  * Promise that settles when the current thread's initial hydration
48
123
  * completes. Useful in SvelteKit `load()` handlers (or any
49
124
  * async-init site) to block until the controller has reconciled
50
- * with server-held state.
125
+ * with server-held state. A fresh promise is installed on every
126
+ * `threadId` change.
51
127
  */
52
128
  readonly hydrationPromise: Promise<void>;
129
+ /**
130
+ * Subagents discovered on the root run. For DeepAgent-typed
131
+ * streams the key set is narrowed to the subagent names declared
132
+ * on the agent brand (`keyof InferSubagentStates<T>`).
133
+ */
53
134
  readonly subagents: ReadonlyMap<keyof SubagentStates & string extends never ? string : keyof SubagentStates & string, SubagentDiscoverySnapshot>;
135
+ /**
136
+ * Subgraphs discovered on the root run.
137
+ *
138
+ * A namespace is classified as a subgraph iff at least one
139
+ * strictly-deeper namespace has been observed with it as a prefix.
140
+ * This is inferred from the lifecycle event stream — plain function
141
+ * nodes (`orchestrator`, `writer` in the nested-stategraph example)
142
+ * never appear here even though the server emits namespaced
143
+ * lifecycle events for them. Promotion is monotonic and retroactive;
144
+ * an entry appears as soon as the first descendant event lands.
145
+ */
54
146
  readonly subgraphs: ReadonlyMap<string, SubgraphDiscoverySnapshot>;
147
+ /**
148
+ * Subgraphs indexed by the graph node that produced them
149
+ * (`addNode("visualizer_0", …)`). Each value is an array because
150
+ * parallel fan-outs and loops can spawn multiple invocations of
151
+ * the same node; arrays preserve insertion order. Updates in
152
+ * lock-step with {@link subgraphs}.
153
+ */
55
154
  readonly subgraphsByNode: ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>;
155
+ /**
156
+ * Dispatch a new run on the bound thread.
157
+ *
158
+ * `input` is typed as `Partial<StateType>` so IDE autocompletion
159
+ * surfaces the state keys declared on the root composable. Pass
160
+ * `null` (or omit fields) when resuming an interrupt via
161
+ * `options.command.resume` — the server accepts a null payload
162
+ * in that case.
163
+ */
56
164
  submit(input: WidenUpdateMessages<Partial<StateType>> | null | undefined, options?: StreamSubmitOptions<StateType, ConfigurableType>): Promise<void>;
165
+ /**
166
+ * Abort the in-flight run on the current thread without clearing
167
+ * accumulated state. Sets {@link isLoading} to `false` immediately;
168
+ * {@link values} and {@link messages} are preserved.
169
+ */
57
170
  stop(): Promise<void>;
171
+ /**
172
+ * Resume a pending protocol interrupt by sending a response payload
173
+ * back to the interrupted namespace.
174
+ *
175
+ * When `target` is omitted, responds to the latest unresolved
176
+ * interrupt in {@link interrupts}. Pass an explicit
177
+ * `{ interruptId, namespace? }` when multiple interrupts are
178
+ * pending or the interrupt lives in a subgraph namespace.
179
+ */
58
180
  respond(response: unknown, target?: {
59
181
  interruptId: string;
60
182
  namespace?: string[];
61
183
  }): Promise<void>;
184
+ /** LangGraph SDK client used to construct thread streams. */
62
185
  readonly client: Client;
186
+ /** Assistant id the thread is bound to for its lifetime. */
63
187
  readonly assistantId: string;
64
- /** v2 escape hatch — returns the bound {@link ThreadStream}. */
188
+ /**
189
+ * Returns the bound {@link ThreadStream}, if one exists (`undefined`
190
+ * until the thread is hydrated or the first submit completes). Prefer
191
+ * the projections and selector composables for UI work; use this for
192
+ * low-level protocol access (raw subscriptions, state commands, etc.).
193
+ */
65
194
  getThread(): ThreadStream | undefined;
66
195
  /** @internal Used by selector composables. */
67
196
  readonly [STREAM_CONTROLLER]: StreamController<StateType, InterruptType, ConfigurableType>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.svelte.d.cts","names":[],"sources":["../src/use-stream.svelte.ts"],"mappings":";;;;;;;;AAyCA;;;;KAAY,aAAA,MAAmB,CAAA,UAAW,CAAA;AAAA,KASrC,cAAA,GAAiB,aAAA;AAAA,KAEV,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,cAAA;AAAA,KAE1B,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,cAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,cAAA;AArB2C;;;;;AAW7C;;AAX6C,cAkChC,iBAAA;;;;;;;;;;;UAcI,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EAAA,SAE5B,MAAA,EAAQ,SAAA;EAAA,SACR,QAAA,EAAU,WAAA;EAAA,SACV,SAAA,EAAW,cAAA,CAAe,CAAA;EAAA,SAC1B,UAAA,EAAY,SAAA,CAAU,aAAA;EAAA,SACtB,SAAA,EAAW,SAAA,CAAU,aAAA;EAAA,SACrB,SAAA;EAAA,SACA,eAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;EAhDT;;;;;AAEF;EAFE,SAuDS,gBAAA,EAAkB,OAAA;EAAA,SAElB,SAAA,EAAW,WAAA,OACZ,cAAA,yCAEI,cAAA,WACV,yBAAA;EAAA,SAEO,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAAA,SAC/B,eAAA,EAAiB,WAAA,kBAEf,yBAAA;EAGX,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EACH,IAAA,IAAQ,OAAA;EACR,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAAA,SAEM,MAAA,EAAQ,MAAA;EAAA,SACR,WAAA;EA1ET;EA6EA,SAAA,IAAa,YAAA;EA7EC;EAAA,UAgFJ,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;AAxDJ;;;KAmEY,SAAA,GAAY,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCR,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;KAkPzB,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
1
+ {"version":3,"file":"use-stream.svelte.d.cts","names":[],"sources":["../src/use-stream.svelte.ts"],"mappings":";;;;;;;;AA0CA;;;;KAAY,aAAA,MAAmB,CAAA,UAAW,CAAA;AAAA,KASrC,cAAA,GAAiB,aAAA;AAAA,KAEV,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,cAAA;AAAA,KAE1B,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,cAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,cAAA;AArB2C;;;;;AAW7C;;AAX6C,cAkChC,iBAAA;;;;;;;;;;;UAcI,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EAvC3B;;;;;;;;;;;EAAA,SAqDD,MAAA,EAAQ,SAAA;EApDmC;;AAEtD;;;;;;;;;;;;;;;;AAiBA;;EAnBsD,SAyE3C,QAAA,EAAU,WAAA;EApDpB;;AAYD;;;;;;;;EAZC,SA+DU,SAAA,EAAW,cAAA,CAAe,CAAA;EAhClB;;;;;;;EAAA,SAwCR,UAAA,EAAY,SAAA,CAAU,aAAA;EAwCJ;;;;;EAAA,SAlClB,SAAA,EAAW,SAAA,CAAU,aAAA;EA2DV;;;;;;EAAA,SApDX,SAAA;EA6EkC;;;;;;EAAA,SAtElC,eAAA;EA4GP;;;;;EAAA,SAtGO,KAAA;EAqGkB;;;;;EAAA,SA/FlB,QAAA;EAvFT;;;;;;;EAAA,SA+FS,gBAAA,EAAkB,OAAA;EA3DlB;;;;;EAAA,SAmEA,SAAA,EAAW,WAAA,OACZ,cAAA,yCAEI,cAAA,WACV,yBAAA;EApDmB;;;;;;;;;;;EAAA,SAiEZ,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAjBpB;;;;;;;EAAA,SAyBX,eAAA,EAAiB,WAAA,kBAEf,yBAAA;EAFe;;;;;;;;;EAe1B,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EADD;;;;;EAOF,IAAA,IAAQ,OAAA;EAYK;;;;;;;;;EAFb,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAoBD;EAAA,SAhBO,MAAA,EAAQ,MAAA;EAgBC;EAAA,SAdT,WAAA;EAyBU;;;;AAmCrB;;EApDE,SAAA,IAAa,YAAA;EAqDT;EAAA,UAlDM,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;;;;KAWQ,SAAA,GAAY,eAAA;;;;;;;;;;;;;;;;;AA6RxB;;;;;;;;;;;;;;;;;iBA1PgB,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;KAoPzB,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
@@ -34,34 +34,163 @@ declare const STREAM_CONTROLLER: unique symbol;
34
34
  * pattern. Access fields through the live `stream` handle instead.
35
35
  */
36
36
  interface UseStreamReturn<T = Record<string, unknown>, InterruptType = unknown, ConfigurableType extends object = Record<string, unknown>, StateType extends object = InferStateType<T>, SubagentStates = InferSubagentStates<T>> {
37
+ /**
38
+ * The most recent `values`-channel snapshot emitted at the root
39
+ * namespace — i.e. the thread-level state as the server sees it
40
+ * after each superstep. Updated on every root `values` event, not
41
+ * on token-level deltas: if you render `stream.values.messages`
42
+ * directly you'll see full turns appear at once instead of
43
+ * streaming token-by-token. Use {@link messages} (or
44
+ * `useMessages`) for the token-streamed view.
45
+ *
46
+ * Equivalent to calling `useValues(stream)`.
47
+ */
37
48
  readonly values: StateType;
49
+ /**
50
+ * The root message projection. Assembled from two sources and
51
+ * merged in real time:
52
+ *
53
+ * 1. `messages`-channel deltas — token-level streaming events
54
+ * (`message-start`, `content-block-delta`, `message-finish`)
55
+ * emitted by the runtime. These drive live, token-by-token
56
+ * updates.
57
+ * 2. `values.messages` snapshots — the authoritative ordering
58
+ * and any messages the agent produces without token streaming
59
+ * (human turns, tool results, echoes from subagents).
60
+ *
61
+ * If the backend only emits `values` events (no `messages`
62
+ * channel), every message will appear fully-formed on each
63
+ * values update rather than streaming. This is a backend/runtime
64
+ * concern — the Svelte layer faithfully renders whatever the
65
+ * server sends.
66
+ *
67
+ * Equivalent to calling `useMessages(stream)` with no target.
68
+ */
38
69
  readonly messages: BaseMessage[];
70
+ /**
71
+ * Root-namespace tool calls assembled from the `tools` channel.
72
+ * Each entry is a fully parsed {@link AssembledToolCall} with
73
+ * name, args, and id — suitable for rendering approval UIs or
74
+ * forwarding to headless tool handlers.
75
+ *
76
+ * When the stream is typed with an agent brand or tool list,
77
+ * entries are narrowed via {@link InferToolCalls}. Equivalent to
78
+ * calling `useToolCalls(stream)` with no target.
79
+ */
39
80
  readonly toolCalls: InferToolCalls<T>[];
81
+ /**
82
+ * All unresolved protocol interrupts observed on the root
83
+ * namespace during the active thread. Populated from lifecycle /
84
+ * input events and seeded on hydration from `thread.getState()`.
85
+ * Cleared optimistically when a new run starts or an interrupt is
86
+ * resolved via {@link respond} / `submit({ command: { resume } })`.
87
+ */
40
88
  readonly interrupts: Interrupt<InterruptType>[];
89
+ /**
90
+ * Convenience alias for {@link interrupts}[0] — the primary
91
+ * interrupt most UIs should act on when only one is pending.
92
+ * `undefined` when no interrupt is active.
93
+ */
41
94
  readonly interrupt: Interrupt<InterruptType> | undefined;
95
+ /**
96
+ * `true` while a run is active or being started on the current
97
+ * thread. Driven by root-namespace lifecycle events (`running` →
98
+ * `true`, terminal phases → `false`). Use this to disable submit
99
+ * buttons and show in-flight spinners.
100
+ */
42
101
  readonly isLoading: boolean;
102
+ /**
103
+ * `true` while the initial `thread.getState()` hydration for the
104
+ * active thread is in flight. Distinct from {@link isLoading} —
105
+ * thread loading covers the one-time fetch that seeds
106
+ * {@link values} / {@link messages} before any user submit.
107
+ */
43
108
  readonly isThreadLoading: boolean;
109
+ /**
110
+ * The last error observed on the active run or hydration attempt.
111
+ * `undefined` when no error has occurred. Cleared optimistically
112
+ * when a new {@link submit} starts.
113
+ */
44
114
  readonly error: unknown;
115
+ /**
116
+ * Id of the thread the controller is bound to. `null` until the
117
+ * first {@link submit} creates or selects a thread (or until an
118
+ * explicit `threadId` option is provided and hydrated).
119
+ */
45
120
  readonly threadId: string | null;
46
121
  /**
47
122
  * Promise that settles when the current thread's initial hydration
48
123
  * completes. Useful in SvelteKit `load()` handlers (or any
49
124
  * async-init site) to block until the controller has reconciled
50
- * with server-held state.
125
+ * with server-held state. A fresh promise is installed on every
126
+ * `threadId` change.
51
127
  */
52
128
  readonly hydrationPromise: Promise<void>;
129
+ /**
130
+ * Subagents discovered on the root run. For DeepAgent-typed
131
+ * streams the key set is narrowed to the subagent names declared
132
+ * on the agent brand (`keyof InferSubagentStates<T>`).
133
+ */
53
134
  readonly subagents: ReadonlyMap<keyof SubagentStates & string extends never ? string : keyof SubagentStates & string, SubagentDiscoverySnapshot>;
135
+ /**
136
+ * Subgraphs discovered on the root run.
137
+ *
138
+ * A namespace is classified as a subgraph iff at least one
139
+ * strictly-deeper namespace has been observed with it as a prefix.
140
+ * This is inferred from the lifecycle event stream — plain function
141
+ * nodes (`orchestrator`, `writer` in the nested-stategraph example)
142
+ * never appear here even though the server emits namespaced
143
+ * lifecycle events for them. Promotion is monotonic and retroactive;
144
+ * an entry appears as soon as the first descendant event lands.
145
+ */
54
146
  readonly subgraphs: ReadonlyMap<string, SubgraphDiscoverySnapshot>;
147
+ /**
148
+ * Subgraphs indexed by the graph node that produced them
149
+ * (`addNode("visualizer_0", …)`). Each value is an array because
150
+ * parallel fan-outs and loops can spawn multiple invocations of
151
+ * the same node; arrays preserve insertion order. Updates in
152
+ * lock-step with {@link subgraphs}.
153
+ */
55
154
  readonly subgraphsByNode: ReadonlyMap<string, readonly SubgraphDiscoverySnapshot[]>;
155
+ /**
156
+ * Dispatch a new run on the bound thread.
157
+ *
158
+ * `input` is typed as `Partial<StateType>` so IDE autocompletion
159
+ * surfaces the state keys declared on the root composable. Pass
160
+ * `null` (or omit fields) when resuming an interrupt via
161
+ * `options.command.resume` — the server accepts a null payload
162
+ * in that case.
163
+ */
56
164
  submit(input: WidenUpdateMessages<Partial<StateType>> | null | undefined, options?: StreamSubmitOptions<StateType, ConfigurableType>): Promise<void>;
165
+ /**
166
+ * Abort the in-flight run on the current thread without clearing
167
+ * accumulated state. Sets {@link isLoading} to `false` immediately;
168
+ * {@link values} and {@link messages} are preserved.
169
+ */
57
170
  stop(): Promise<void>;
171
+ /**
172
+ * Resume a pending protocol interrupt by sending a response payload
173
+ * back to the interrupted namespace.
174
+ *
175
+ * When `target` is omitted, responds to the latest unresolved
176
+ * interrupt in {@link interrupts}. Pass an explicit
177
+ * `{ interruptId, namespace? }` when multiple interrupts are
178
+ * pending or the interrupt lives in a subgraph namespace.
179
+ */
58
180
  respond(response: unknown, target?: {
59
181
  interruptId: string;
60
182
  namespace?: string[];
61
183
  }): Promise<void>;
184
+ /** LangGraph SDK client used to construct thread streams. */
62
185
  readonly client: Client;
186
+ /** Assistant id the thread is bound to for its lifetime. */
63
187
  readonly assistantId: string;
64
- /** v2 escape hatch — returns the bound {@link ThreadStream}. */
188
+ /**
189
+ * Returns the bound {@link ThreadStream}, if one exists (`undefined`
190
+ * until the thread is hydrated or the first submit completes). Prefer
191
+ * the projections and selector composables for UI work; use this for
192
+ * low-level protocol access (raw subscriptions, state commands, etc.).
193
+ */
65
194
  getThread(): ThreadStream | undefined;
66
195
  /** @internal Used by selector composables. */
67
196
  readonly [STREAM_CONTROLLER]: StreamController<StateType, InterruptType, ConfigurableType>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.svelte.d.ts","names":[],"sources":["../src/use-stream.svelte.ts"],"mappings":";;;;;;;;AAyCA;;;;KAAY,aAAA,MAAmB,CAAA,UAAW,CAAA;AAAA,KASrC,cAAA,GAAiB,aAAA;AAAA,KAEV,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,cAAA;AAAA,KAE1B,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,cAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,cAAA;AArB2C;;;;;AAW7C;;AAX6C,cAkChC,iBAAA;;;;;;;;;;;UAcI,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EAAA,SAE5B,MAAA,EAAQ,SAAA;EAAA,SACR,QAAA,EAAU,WAAA;EAAA,SACV,SAAA,EAAW,cAAA,CAAe,CAAA;EAAA,SAC1B,UAAA,EAAY,SAAA,CAAU,aAAA;EAAA,SACtB,SAAA,EAAW,SAAA,CAAU,aAAA;EAAA,SACrB,SAAA;EAAA,SACA,eAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;EAhDT;;;;;AAEF;EAFE,SAuDS,gBAAA,EAAkB,OAAA;EAAA,SAElB,SAAA,EAAW,WAAA,OACZ,cAAA,yCAEI,cAAA,WACV,yBAAA;EAAA,SAEO,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAAA,SAC/B,eAAA,EAAiB,WAAA,kBAEf,yBAAA;EAGX,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EACH,IAAA,IAAQ,OAAA;EACR,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAAA,SAEM,MAAA,EAAQ,MAAA;EAAA,SACR,WAAA;EA1ET;EA6EA,SAAA,IAAa,YAAA;EA7EC;EAAA,UAgFJ,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;AAxDJ;;;KAmEY,SAAA,GAAY,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCR,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;KAkPzB,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
1
+ {"version":3,"file":"use-stream.svelte.d.ts","names":[],"sources":["../src/use-stream.svelte.ts"],"mappings":";;;;;;;;AA0CA;;;;KAAY,aAAA,MAAmB,CAAA,UAAW,CAAA;AAAA,KASrC,cAAA,GAAiB,aAAA;AAAA,KAEV,oBAAA,6BACV,kBAAA,CAAyB,SAAA,EAAW,cAAA;AAAA,KAE1B,sBAAA,6BACV,oBAAA,CAA2B,SAAA,EAAW,cAAA;AAAA,KAE5B,kBAAA,4BACiB,MAAA,qBACzB,gBAAA,CACF,SAAA,EACA,cAAA;AArB2C;;;;;AAW7C;;AAX6C,cAkChC,iBAAA;;;;;;;;;;;UAcI,eAAA,KACX,MAAA,8EAE8B,MAAA,8CACP,cAAA,CAAe,CAAA,oBACzB,mBAAA,CAAoB,CAAA;EAvC3B;;;;;;;;;;;EAAA,SAqDD,MAAA,EAAQ,SAAA;EApDmC;;AAEtD;;;;;;;;;;;;;;;;AAiBA;;EAnBsD,SAyE3C,QAAA,EAAU,WAAA;EApDpB;;AAYD;;;;;;;;EAZC,SA+DU,SAAA,EAAW,cAAA,CAAe,CAAA;EAhClB;;;;;;;EAAA,SAwCR,UAAA,EAAY,SAAA,CAAU,aAAA;EAwCJ;;;;;EAAA,SAlClB,SAAA,EAAW,SAAA,CAAU,aAAA;EA2DV;;;;;;EAAA,SApDX,SAAA;EA6EkC;;;;;;EAAA,SAtElC,eAAA;EA4GP;;;;;EAAA,SAtGO,KAAA;EAqGkB;;;;;EAAA,SA/FlB,QAAA;EAvFT;;;;;;;EAAA,SA+FS,gBAAA,EAAkB,OAAA;EA3DlB;;;;;EAAA,SAmEA,SAAA,EAAW,WAAA,OACZ,cAAA,yCAEI,cAAA,WACV,yBAAA;EApDmB;;;;;;;;;;;EAAA,SAiEZ,SAAA,EAAW,WAAA,SAAoB,yBAAA;EAjBpB;;;;;;;EAAA,SAyBX,eAAA,EAAiB,WAAA,kBAEf,yBAAA;EAFe;;;;;;;;;EAe1B,MAAA,CACE,KAAA,EAAO,mBAAA,CAAoB,OAAA,CAAQ,SAAA,uBACnC,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EADD;;;;;EAOF,IAAA,IAAQ,OAAA;EAYK;;;;;;;;;EAFb,OAAA,CACE,QAAA,WACA,MAAA;IAAW,WAAA;IAAqB,SAAA;EAAA,IAC/B,OAAA;EAoBD;EAAA,SAhBO,MAAA,EAAQ,MAAA;EAgBC;EAAA,SAdT,WAAA;EAyBU;;;;AAmCrB;;EApDE,SAAA,IAAa,YAAA;EAqDT;EAAA,UAlDM,iBAAA,GAAoB,gBAAA,CAC5B,SAAA,EACA,aAAA,EACA,gBAAA;AAAA;;;;;;;KAWQ,SAAA,GAAY,eAAA;;;;;;;;;;;;;;;;;AA6RxB;;;;;;;;;;;;;;;;;iBA1PgB,SAAA,KACV,MAAA,8EAE8B,MAAA,kBAAA,CAElC,OAAA,EAAS,kBAAA,CAAiB,cAAA,CAAe,CAAA,KACxC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA;;KAoPzB,eAAA,KACN,MAAA,8EAE8B,MAAA,qBAChC,eAAA,CAAgB,CAAA,EAAG,aAAA,EAAe,gBAAA"}
@@ -1,5 +1,5 @@
1
1
  import { onDestroy } from "svelte";
2
- import { flushPendingHeadlessToolInterrupts } from "@langchain/langgraph-sdk";
2
+ import { flushPendingHeadlessToolInterrupts, scheduleCoalescedHeadlessToolFlush } from "@langchain/langgraph-sdk";
3
3
  import { Client as Client$1 } from "@langchain/langgraph-sdk/client";
4
4
  import { StreamController } from "@langchain/langgraph-sdk/stream";
5
5
  //#region src/use-stream.svelte.ts
@@ -112,18 +112,22 @@ function useStream(options) {
112
112
  handledTools.clear();
113
113
  handledForThreadId = currentThreadId;
114
114
  }
115
- const valuesBag = rootSnapshot.values;
116
- const combined = [...Array.isArray(valuesBag?.__interrupt__) ? valuesBag.__interrupt__ : [], ...rootSnapshot.interrupts];
117
- if (combined.length === 0) return;
118
- flushPendingHeadlessToolInterrupts({
119
- ...valuesBag,
120
- __interrupt__: combined
121
- }, tools, handledTools, {
122
- onTool,
123
- defer: (run) => {
124
- Promise.resolve().then(run);
125
- },
126
- resumeSubmit: (command) => controller.submit(null, { command })
115
+ scheduleCoalescedHeadlessToolFlush(handledTools, () => {
116
+ const valuesBag = rootSnapshot.values;
117
+ const protocolInterrupts = rootSnapshot.interrupts;
118
+ const valuesInterrupts = Array.isArray(valuesBag?.__interrupt__) ? valuesBag.__interrupt__ : [];
119
+ const headlessInterrupts = protocolInterrupts.length > 0 ? protocolInterrupts : valuesInterrupts;
120
+ if (headlessInterrupts.length === 0) return;
121
+ flushPendingHeadlessToolInterrupts({
122
+ ...valuesBag,
123
+ __interrupt__: headlessInterrupts
124
+ }, tools, handledTools, {
125
+ onTool,
126
+ defer: (run) => {
127
+ Promise.resolve().then(run);
128
+ },
129
+ resumeSubmit: (command) => controller.submit(null, { command })
130
+ });
127
131
  });
128
132
  });
129
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-stream.svelte.js","names":["ClientCtor"],"sources":["../src/use-stream.svelte.ts"],"sourcesContent":["import { onDestroy } from \"svelte\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\n flushPendingHeadlessToolInterrupts,\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 InferToolCalls,\n type InferSubagentStates,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\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\";\n\n/**\n * A value that may be either a plain `T` or a getter `() => T`. Used\n * for reactive-capable option inputs (currently `threadId` only). When\n * a getter is passed the composable tracks it via `$effect` and\n * re-hydrates when the returned value changes.\n */\nexport type ValueOrGetter<T> = T | (() => T);\n\nfunction readValueOrGetter<T>(\n input: ValueOrGetter<T> | undefined\n): T | undefined {\n if (typeof input === \"function\") return (input as () => T)();\n return input;\n}\n\ntype SvelteThreadId = ValueOrGetter<string | null | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, SvelteThreadId>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, SvelteThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n SvelteThreadId,\n string | undefined,\n string | undefined,\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\n * (`useMessages`, `useToolCalls`, `useValues`, …) instead of reading\n * this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/svelte/controller\"\n);\n\n/**\n * Svelte binding return type for {@link useStream}. Reactive\n * projections are exposed as getters on a stable object so templates\n * can read `stream.messages` directly without a `.value` / `.current`\n * hop and `$derived` wrappers auto-track the getter read.\n *\n * Destructuring (`const { messages } = stream`) breaks reactivity —\n * this is a Svelte 5 constraint and applies to every getter-object\n * pattern. Access fields through the live `stream` handle instead.\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 readonly values: StateType;\n readonly messages: BaseMessage[];\n readonly toolCalls: InferToolCalls<T>[];\n readonly interrupts: Interrupt<InterruptType>[];\n readonly interrupt: Interrupt<InterruptType> | undefined;\n readonly isLoading: boolean;\n readonly isThreadLoading: boolean;\n readonly error: unknown;\n readonly threadId: string | null;\n /**\n * Promise that settles when the current thread's initial hydration\n * completes. Useful in SvelteKit `load()` handlers (or any\n * async-init site) to block until the controller has reconciled\n * with server-held state.\n */\n readonly hydrationPromise: Promise<void>;\n\n readonly subagents: ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\n >;\n readonly subgraphs: ReadonlyMap<string, SubgraphDiscoverySnapshot>;\n readonly subgraphsByNode: ReadonlyMap<\n string,\n readonly SubgraphDiscoverySnapshot[]\n >;\n\n submit(\n input: WidenUpdateMessages<Partial<StateType>> | null | undefined,\n options?: StreamSubmitOptions<StateType, ConfigurableType>\n ): Promise<void>;\n stop(): Promise<void>;\n respond(\n response: unknown,\n target?: { interruptId: string; namespace?: string[] }\n ): Promise<void>;\n\n readonly client: Client;\n readonly assistantId: string;\n\n /** v2 escape hatch — returns the bound {@link ThreadStream}. */\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/**\n * Svelte 5 binding for the v2-native stream runtime.\n *\n * Returns a handle whose reactive fields are plain getters on a\n * stable object — templates can read `stream.messages` directly and\n * `$derived(stream.isLoading)` auto-tracks the getter.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from \"@langchain/svelte\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * {#each stream.messages as msg (msg.id)}\n * <div>{msg.content}</div>\n * {/each}\n * <button onclick={() =>\n * stream.submit({ messages: [{ type: \"human\", content: \"Hi\" }] })\n * }>\n * Send\n * </button>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at composable\n * init. To bind a new assistant/transport, remount the component.\n * Only `threadId` is treated as reactive — pass it as a getter\n * (`threadId: () => active`) to drive an in-place thread swap.\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?: ValueOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: string;\n apiKey?: string;\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 const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // Client construction — captured once at init. Consumers that need\n // to swap `apiUrl`/`apiKey` at runtime remount the owning component.\n const client: Client =\n asBag.client ??\n (new ClientCtor({\n apiUrl: asBag.apiUrl,\n apiKey: asBag.apiKey,\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client);\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 = readValueOrGetter(asBag.threadId) ?? null;\n\n // Plain `let` binding, not `$state`: the controller holds maps of\n // listeners, Promises, and the live `ThreadStream`, none of which\n // survive Svelte's deep `$state` proxy wrapping.\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n // `Client` is state-shape agnostic at runtime; the controller\n // advertises `Client<StateType>` on its public type for ergonomics.\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: mirrors React's activate/dispose pattern so HMR\n // and other scope-reuse scenarios stay clean. `activate()` cancels\n // a pending dispose if the owning scope survives.\n const deactivate = controller.activate();\n onDestroy(deactivate);\n\n // ─── Reactive state bridges ─────────────────────────────────────────\n //\n // Each always-on `StreamStore` is wrapped in a runes `$state` slot\n // seeded from `getSnapshot()` and kept in sync via `store.subscribe`.\n // Subscriptions are torn down on component destroy.\n let rootSnapshot = $state<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.getSnapshot()\n );\n const unsubscribeRoot = controller.rootStore.subscribe(() => {\n rootSnapshot = controller.rootStore.getSnapshot();\n });\n onDestroy(unsubscribeRoot);\n\n let subagentSnapshot = $state<SubagentMap>(\n controller.subagentStore.getSnapshot()\n );\n const unsubscribeSubagents = controller.subagentStore.subscribe(() => {\n subagentSnapshot = controller.subagentStore.getSnapshot();\n });\n onDestroy(unsubscribeSubagents);\n\n let subgraphSnapshot = $state<SubgraphMap>(\n controller.subgraphStore.getSnapshot()\n );\n const unsubscribeSubgraphs = controller.subgraphStore.subscribe(() => {\n subgraphSnapshot = controller.subgraphStore.getSnapshot();\n });\n onDestroy(unsubscribeSubgraphs);\n\n let subgraphByNodeSnapshot = $state<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.getSnapshot()\n );\n const unsubscribeSubgraphByNode = controller.subgraphByNodeStore.subscribe(\n () => {\n subgraphByNodeSnapshot = controller.subgraphByNodeStore.getSnapshot();\n }\n );\n onDestroy(unsubscribeSubgraphByNode);\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Only matters when the caller passed a getter. The initial hydrate\n // already fired in the controller constructor, so skip the first\n // tick to avoid a redundant `thread.state.get()`.\n if (typeof asBag.threadId === \"function\") {\n const getThreadId = asBag.threadId;\n let previousThreadId = initialThreadId;\n $effect(() => {\n const next = (getThreadId() ?? null) as string | null;\n if (next === previousThreadId) return;\n previousThreadId = next;\n void controller.hydrate(next);\n });\n }\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch the root `values.__interrupt__` key plus the protocol-\n // surfaced interrupts for items targeting a registered tool, invoke\n // the handler, and resume the run with the handler's return value.\n // Dedup via an id set so rerenders don't replay a tool call twice.\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n const handledTools = new Set<string>();\n let handledForThreadId: string | null = initialThreadId;\n $effect(() => {\n // Reset dedup set when the active thread id changes — a fresh\n // thread may legitimately re-emit a tool-call id we've seen.\n const currentThreadId = rootSnapshot.threadId;\n if (currentThreadId !== handledForThreadId) {\n handledTools.clear();\n handledForThreadId = currentThreadId;\n }\n\n const valuesBag = rootSnapshot.values as unknown as Record<\n string,\n unknown\n >;\n const existing = Array.isArray(valuesBag?.__interrupt__)\n ? (valuesBag.__interrupt__ as Interrupt[])\n : [];\n const combined: Interrupt[] = [\n ...existing,\n ...(rootSnapshot.interrupts as unknown as Interrupt[]),\n ];\n if (combined.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...valuesBag, __interrupt__: combined },\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\n // ─── Public handle ──────────────────────────────────────────────────\n //\n // Single stable object with getters. Getters read the runes\n // `$state` slots, which drives template reactivity automatically.\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n get values() {\n return rootSnapshot.values;\n },\n get messages() {\n return rootSnapshot.messages;\n },\n get toolCalls() {\n return rootSnapshot.toolCalls as InferToolCalls<T>[];\n },\n get interrupts() {\n return rootSnapshot.interrupts;\n },\n get interrupt() {\n return rootSnapshot.interrupt;\n },\n get isLoading() {\n return rootSnapshot.isLoading;\n },\n get isThreadLoading() {\n return rootSnapshot.isThreadLoading;\n },\n get error() {\n return rootSnapshot.error;\n },\n get threadId() {\n return rootSnapshot.threadId;\n },\n get hydrationPromise() {\n return controller.hydrationPromise;\n },\n get subagents() {\n return subagentSnapshot as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"];\n },\n get subgraphs() {\n return subgraphSnapshot;\n },\n get subgraphsByNode() {\n return subgraphByNodeSnapshot;\n },\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: () => controller.stop(),\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/** 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 * 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.svelte.js","names":["ClientCtor"],"sources":["../src/use-stream.svelte.ts"],"sourcesContent":["import { onDestroy } from \"svelte\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type { Client, Interrupt } from \"@langchain/langgraph-sdk\";\nimport {\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 InferToolCalls,\n type InferSubagentStates,\n type RootSnapshot,\n type RunCompletedInfo,\n type RunExecutionInfo,\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\";\n\n/**\n * A value that may be either a plain `T` or a getter `() => T`. Used\n * for reactive-capable option inputs (currently `threadId` only). When\n * a getter is passed the composable tracks it via `$effect` and\n * re-hydrates when the returned value changes.\n */\nexport type ValueOrGetter<T> = T | (() => T);\n\nfunction readValueOrGetter<T>(\n input: ValueOrGetter<T> | undefined\n): T | undefined {\n if (typeof input === \"function\") return (input as () => T)();\n return input;\n}\n\ntype SvelteThreadId = ValueOrGetter<string | null | undefined>;\n\nexport type AgentServerOptions<StateType extends object> =\n StreamAgentServerOptions<StateType, SvelteThreadId>;\n\nexport type CustomAdapterOptions<StateType extends object> =\n StreamCustomAdapterOptions<StateType, SvelteThreadId, string>;\n\nexport type UseStreamOptions<\n StateType extends object = Record<string, unknown>,\n> = StreamUseStreamOptions<\n StateType,\n SvelteThreadId,\n string | undefined,\n string | undefined,\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\n * (`useMessages`, `useToolCalls`, `useValues`, …) instead of reading\n * this directly.\n */\nexport const STREAM_CONTROLLER: unique symbol = Symbol.for(\n \"@langchain/svelte/controller\"\n);\n\n/**\n * Svelte binding return type for {@link useStream}. Reactive\n * projections are exposed as getters on a stable object so templates\n * can read `stream.messages` directly without a `.value` / `.current`\n * hop and `$derived` wrappers auto-track the getter read.\n *\n * Destructuring (`const { messages } = stream`) breaks reactivity —\n * this is a Svelte 5 constraint and applies to every getter-object\n * pattern. Access fields through the live `stream` handle instead.\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.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: 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 Svelte layer faithfully renders whatever the\n * server sends.\n *\n * Equivalent to calling `useMessages(stream)` with no target.\n */\n readonly messages: 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: 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: 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: 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: 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: 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: 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: string | null;\n /**\n * Promise that settles when the current thread's initial hydration\n * completes. Useful in SvelteKit `load()` handlers (or any\n * async-init site) to block until the controller has reconciled\n * with server-held state. A fresh promise is installed on every\n * `threadId` change.\n */\n readonly hydrationPromise: 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: ReadonlyMap<\n keyof SubagentStates & string extends never\n ? string\n : keyof SubagentStates & string,\n SubagentDiscoverySnapshot\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: ReadonlyMap<string, SubgraphDiscoverySnapshot>;\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: ReadonlyMap<\n string,\n 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 * Abort the in-flight run on the current thread without clearing\n * accumulated state. Sets {@link isLoading} to `false` immediately;\n * {@link values} and {@link messages} are preserved.\n */\n stop(): 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/**\n * Svelte 5 binding for the v2-native stream runtime.\n *\n * Returns a handle whose reactive fields are plain getters on a\n * stable object — templates can read `stream.messages` directly and\n * `$derived(stream.isLoading)` auto-tracks the getter.\n *\n * @example\n * ```svelte\n * <script lang=\"ts\">\n * import { useStream } from \"@langchain/svelte\";\n *\n * const stream = useStream({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n * </script>\n *\n * {#each stream.messages as msg (msg.id)}\n * <div>{msg.content}</div>\n * {/each}\n * <button onclick={() =>\n * stream.submit({ messages: [{ type: \"human\", content: \"Hi\" }] })\n * }>\n * Send\n * </button>\n * ```\n *\n * `assistantId`, `client`, and `transport` are captured at composable\n * init. To bind a new assistant/transport, remount the component.\n * Only `threadId` is treated as reactive — pass it as a getter\n * (`threadId: () => active`) to drive an in-place thread swap.\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?: ValueOrGetter<string | null | undefined>;\n client?: Client;\n apiUrl?: string;\n apiKey?: string;\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 const hasCustomAdapter =\n asBag.transport != null && typeof asBag.transport !== \"string\";\n const transport = asBag.transport;\n\n // Client construction — captured once at init. Consumers that need\n // to swap `apiUrl`/`apiKey` at runtime remount the owning component.\n const client: Client =\n asBag.client ??\n (new ClientCtor({\n apiUrl: asBag.apiUrl,\n apiKey: asBag.apiKey,\n callerOptions: asBag.callerOptions,\n defaultHeaders: asBag.defaultHeaders,\n }) as unknown as Client);\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 = readValueOrGetter(asBag.threadId) ?? null;\n\n // Plain `let` binding, not `$state`: the controller holds maps of\n // listeners, Promises, and the live `ThreadStream`, none of which\n // survive Svelte's deep `$state` proxy wrapping.\n const controller = new StreamController<\n StateType,\n InterruptType,\n ConfigurableType\n >({\n assistantId,\n // `Client` is state-shape agnostic at runtime; the controller\n // advertises `Client<StateType>` on its public type for ergonomics.\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: mirrors React's activate/dispose pattern so HMR\n // and other scope-reuse scenarios stay clean. `activate()` cancels\n // a pending dispose if the owning scope survives.\n const deactivate = controller.activate();\n onDestroy(deactivate);\n\n // ─── Reactive state bridges ─────────────────────────────────────────\n //\n // Each always-on `StreamStore` is wrapped in a runes `$state` slot\n // seeded from `getSnapshot()` and kept in sync via `store.subscribe`.\n // Subscriptions are torn down on component destroy.\n let rootSnapshot = $state<RootSnapshot<StateType, InterruptType>>(\n controller.rootStore.getSnapshot()\n );\n const unsubscribeRoot = controller.rootStore.subscribe(() => {\n rootSnapshot = controller.rootStore.getSnapshot();\n });\n onDestroy(unsubscribeRoot);\n\n let subagentSnapshot = $state<SubagentMap>(\n controller.subagentStore.getSnapshot()\n );\n const unsubscribeSubagents = controller.subagentStore.subscribe(() => {\n subagentSnapshot = controller.subagentStore.getSnapshot();\n });\n onDestroy(unsubscribeSubagents);\n\n let subgraphSnapshot = $state<SubgraphMap>(\n controller.subgraphStore.getSnapshot()\n );\n const unsubscribeSubgraphs = controller.subgraphStore.subscribe(() => {\n subgraphSnapshot = controller.subgraphStore.getSnapshot();\n });\n onDestroy(unsubscribeSubgraphs);\n\n let subgraphByNodeSnapshot = $state<SubgraphByNodeMap>(\n controller.subgraphByNodeStore.getSnapshot()\n );\n const unsubscribeSubgraphByNode = controller.subgraphByNodeStore.subscribe(\n () => {\n subgraphByNodeSnapshot = controller.subgraphByNodeStore.getSnapshot();\n }\n );\n onDestroy(unsubscribeSubgraphByNode);\n\n // ─── threadId reactivity ────────────────────────────────────────────\n //\n // Only matters when the caller passed a getter. The initial hydrate\n // already fired in the controller constructor, so skip the first\n // tick to avoid a redundant `thread.state.get()`.\n if (typeof asBag.threadId === \"function\") {\n const getThreadId = asBag.threadId;\n let previousThreadId = initialThreadId;\n $effect(() => {\n const next = (getThreadId() ?? null) as string | null;\n if (next === previousThreadId) return;\n previousThreadId = next;\n void controller.hydrate(next);\n });\n }\n\n // ─── Headless-tool handling ─────────────────────────────────────────\n //\n // Watch the root `values.__interrupt__` key plus the protocol-\n // surfaced interrupts for items targeting a registered tool, invoke\n // the handler, and resume the run with the handler's return value.\n // Dedup via an id set so rerenders don't replay a tool call twice.\n const tools = options.tools;\n const onTool = options.onTool;\n if (tools?.length) {\n const handledTools = new Set<string>();\n let handledForThreadId: string | null = initialThreadId;\n $effect(() => {\n // Reset dedup set when the active thread id changes — a fresh\n // thread may legitimately re-emit a tool-call id we've seen.\n const currentThreadId = rootSnapshot.threadId;\n if (currentThreadId !== handledForThreadId) {\n handledTools.clear();\n handledForThreadId = currentThreadId;\n }\n\n scheduleCoalescedHeadlessToolFlush(handledTools, () => {\n const valuesBag = rootSnapshot.values as unknown as Record<\n string,\n unknown\n >;\n const protocolInterrupts =\n rootSnapshot.interrupts as unknown as Interrupt[];\n const valuesInterrupts = Array.isArray(valuesBag?.__interrupt__)\n ? (valuesBag.__interrupt__ as Interrupt[])\n : [];\n const headlessInterrupts =\n protocolInterrupts.length > 0 ? protocolInterrupts : valuesInterrupts;\n if (headlessInterrupts.length === 0) return;\n flushPendingHeadlessToolInterrupts(\n { ...valuesBag, __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 }\n\n // ─── Public handle ──────────────────────────────────────────────────\n //\n // Single stable object with getters. Getters read the runes\n // `$state` slots, which drives template reactivity automatically.\n const handle: UseStreamReturn<T, InterruptType, ConfigurableType> = {\n get values() {\n return rootSnapshot.values;\n },\n get messages() {\n return rootSnapshot.messages;\n },\n get toolCalls() {\n return rootSnapshot.toolCalls as InferToolCalls<T>[];\n },\n get interrupts() {\n return rootSnapshot.interrupts;\n },\n get interrupt() {\n return rootSnapshot.interrupt;\n },\n get isLoading() {\n return rootSnapshot.isLoading;\n },\n get isThreadLoading() {\n return rootSnapshot.isThreadLoading;\n },\n get error() {\n return rootSnapshot.error;\n },\n get threadId() {\n return rootSnapshot.threadId;\n },\n get hydrationPromise() {\n return controller.hydrationPromise;\n },\n get subagents() {\n return subagentSnapshot as UseStreamReturn<\n T,\n InterruptType,\n ConfigurableType\n >[\"subagents\"];\n },\n get subgraphs() {\n return subgraphSnapshot;\n },\n get subgraphsByNode() {\n return subgraphByNodeSnapshot;\n },\n submit: (input, submitOptions) => controller.submit(input, submitOptions),\n stop: () => controller.stop(),\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/** 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 * 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/svelte",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Svelte integration for LangGraph & LangChain",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,7 +10,7 @@
10
10
  "directory": "libs/sdk-svelte"
11
11
  },
12
12
  "dependencies": {
13
- "@langchain/langgraph-sdk": "1.9.5"
13
+ "@langchain/langgraph-sdk": "1.9.7"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@hono/node-server": "^1.19.13",