LangChain Reference home pageLangChain ReferenceLangChain Reference
  • GitHub
  • Main Docs
Deep Agents
LangChain
LangGraph
Integrations
LangSmith
  • Overview
  • Getting started
  • useStream
  • Selectors
  • Interrupts & headless tools
  • Subagents & subgraphs
  • Fork & edit from a checkpoint
  • Submission queue
  • Multimodal media
  • Transports
  • provideStream & context
  • Type safety
  • Migrating to v1
LangGraph SDK
  • Client
  • Auth
  • React
  • Logging
  • React Ui
  • Server
LangGraph Checkpoint
LangGraph Checkpoint MongoDB
LangGraph Checkpoint Postgres
LangGraph Checkpoint Redis
  • Shallow
  • Store
LangGraph Checkpoint SQLite
LangGraph Checkpoint Validation
  • Cli
LangGraph API
LangGraph CLI
LangGraph CUA
  • Utils
LangGraph Supervisor
LangGraph Swarm
⌘I

LangChain Assistant

Ask a question to get started

Enter to send•Shift+Enter new line

Menu

OverviewGetting starteduseStreamSelectorsInterrupts & headless toolsSubagents & subgraphsFork & edit from a checkpointSubmission queueMultimodal mediaTransportsprovideStream & contextType safetyMigrating to v1
LangGraph SDK
ClientAuthReactLoggingReact UiServer
LangGraph Checkpoint
LangGraph Checkpoint MongoDB
LangGraph Checkpoint Postgres
LangGraph Checkpoint Redis
ShallowStore
LangGraph Checkpoint SQLite
LangGraph Checkpoint Validation
Cli
LangGraph API
LangGraph CLI
LangGraph CUA
Utils
LangGraph Supervisor
LangGraph Swarm
Language
Theme
JavaScript@langchain/svelteSelectors

Selectors

The root useStream hook exposes always-on projections (values, messages, toolCalls, interrupts, error, isLoading, discovery maps). Anything else — scoped subagent state, message metadata, the submission queue, raw channels, media — is available through the companion selector hooks.

Selector hooks return small reactive handles shaped like { get current(): T }. Read .current in templates, $derived, $effect, or another selector argument so Svelte can track the live value.

Each selector hook opens a ref-counted subscription when the first component mounts it and releases it when the last consumer unmounts. Root calls (no target) are free — they read the already-mounted root projection directly.

How targeting works

All scoped selectors accept a target argument. Valid targets are:

  • undefined (or omitted) — the root namespace. Free read.
  • A SubagentDiscoverySnapshot — as exposed via stream.subagents.values().
  • A SubgraphDiscoverySnapshot — as exposed via stream.subgraphs / stream.subgraphsByNode.
  • { namespace: string[] } (or a raw string[]) — an explicit namespace, useful for custom routing.
  • A getter (() => target) — useful when the target comes from $state and should re-bind reactively.

Subscriptions open on mount and close when the last consumer for a given (channel, namespace) tuple unmounts. Components that don't render a subagent's content never pay for its wire traffic.

Full hook list

Hook Returns Use for
useValues(stream, target?) { current: StateType } (root) / { current: T \| undefined } (scoped) Arbitrary state / scoped snapshot.
useMessages(stream, target?) { current: BaseMessage[] } Message stream, root or scoped.
useToolCalls(stream, target?) { current: AssembledToolCall[] } Tool-call stream, with per-call status.
useMessageMetadata(stream, msgId) { current: { parentCheckpointId } \| undefined } Powers fork / edit flows. See Fork & edit.
useSubmissionQueue(stream) { entries, size, cancel, clear } Reactive client-side submission queue. See Queue.
useExtension(stream, name, target?) { current: T \| undefined } Read a named custom:<name> extension.
useChannel(stream, channels, target?, options?) { current: Event[] } Low-level raw-events escape hatch.
useChannelEffect(stream, channels, options) void Per-event side-effect callback.
useAudio / useImages / useVideo / useFiles Media arrays in { current } Assembled multimodal streams. See Multimodal.
useMediaURL(handle) { current: string \| undefined } Turns a media handle into an <img/audio/video src>.
useAudioPlayer(handle, options?) / useVideoPlayer(handle, options?) Player handles Opinionated playback helpers on top of the media hooks.

Root vs. scoped example

<script lang="ts">
  import { useMessages, useStream, useToolCalls, useValues } from "@langchain/svelte";

  const stream = useStream({ assistantId: "agent", apiUrl: "/api" });

  // Root projections — identical to `stream.messages` / `stream.values`.
  // These calls are free: no new subscription is opened.
  const rootMessages = useMessages(stream);
  const rootValues = useValues(stream);
</script>

{#each rootMessages.current as msg (msg.id)}
  <Bubble {msg} />
{/each}

{#each [...stream.subagents.values()] as subagent (subagent.namespace.join("/"))}
  {@const messages = useMessages(stream, subagent)}
  {@const toolCalls = useToolCalls(stream, subagent)}
  {@const values = useValues<ResearcherState>(stream, subagent)}

  <section>
    <header>{subagent.name} — {subagent.status}</header>
    {#each messages.current as msg (msg.id)}
      <Bubble {msg} />
    {/each}
    {#if values.current}
      <pre>{JSON.stringify(values.current)}</pre>
    {/if}
  </section>
{/each}

useMessageMetadata

Returns { parentCheckpointId } (and undefined while loading). Use it to drive fork / edit UIs:

<script lang="ts">
  import { useMessageMetadata } from "@langchain/svelte";

  const metadata = useMessageMetadata(stream, () => message.id);

  function editFromHere() {
    const forkFrom = metadata.current?.parentCheckpointId;
    if (!forkFrom) return;
    void stream.submit(
      { messages: [{ type: "human", content: "...revised prompt..." }] },
      { forkFrom },
    );
  }
</script>

<button disabled={!metadata.current?.parentCheckpointId} onclick={editFromHere}>
  Edit from here
</button>

See Fork & edit from a checkpoint for the full flow.

useChannel

Escape hatch to the raw protocol event stream. Subscribe to one or more channels and get the buffered events as an array:

<script lang="ts">
  import { useChannel } from "@langchain/svelte";

  const events = useChannel(stream, ["values", "updates"]);
</script>

{#each events.current as event}
  <pre>{JSON.stringify(event)}</pre>
{/each}

Pass target (subagent / subgraph / { namespace }) to scope. Useful for bespoke reducers that can't be expressed through useValues / useMessages.

The buffer keeps accumulating across serial runs for the lifetime of the thread, so useChannel is also the selector to use for an event log of a custom channel:

<script lang="ts">
  import { useChannel } from "@langchain/svelte";

  const statsEvents = useChannel(stream, ["custom:redaction-stats"]);
</script>

useExtension

Read a single custom extension (wire-level custom:<name> channel) as a reactive snapshot:

<script lang="ts">
  import { useExtension } from "@langchain/svelte";

  const telemetry = useExtension<Telemetry>(stream, "telemetry");
</script>

{#if telemetry.current}
  <TelemetryPanel value={telemetry.current} />
{/if}

Runnable example: The a2ui app in the streaming cookbook drives a generative UI with useExtension(stream, "a2ui"); the streaming package's custom-transformer:* scripts show the server side.

useChannel vs. useExtension

Both keep receiving events across serial runs on the same thread, but they expose different shapes for a custom:<name> channel:

  • useExtension — the latest payload only. Use it for current-state panels (progress, score, status).
  • useChannel — the full history of events as a bounded buffer. Use it when you need an event log or want to derive your own running totals.

useChannelEffect

useChannelEffect is for raw events you want to react to instead of render. It invokes onEvent once per event and returns nothing, so it never triggers rerenders by itself:

<script lang="ts">
  import { useChannelEffect } from "@langchain/svelte";

  useChannelEffect(stream, ["lifecycle", "tools"], {
    replay: false,
    onEvent(event) {
      sendAnalytics(event);
    },
    onError(error) {
      logger.error(error);
    },
  });
</script>

channels, target, and enabled accept getters so reactive $state re-binds the subscription. The subscription is shared (ref-counted) with any matching useChannel, so you only pay for one server subscription per channel set. replay defaults to false (live-only); events buffered before the effect attaches are not re-delivered. Call it from a component script or $effect.root.

useProjection — building your own selector

useProjection is the low-level primitive every built-in selector is composed from. Reach for it only when you need a custom projection that the built-in hooks don't express. It acquires a ref-counted projection from the stream's channel registry and exposes the projected value through the same .current handle shape:

import { useProjection } from "@langchain/svelte";
import { STREAM_CONTROLLER } from "@langchain/svelte"; // low-level access key
import { valuesProjection } from "@langchain/langgraph-sdk/stream";

function useScoredValues<T>(stream: AnyStream, namespace: readonly string[]) {
  const registry = stream[STREAM_CONTROLLER].registry;
  return useProjection<T | undefined>(
    registry,
    () => valuesProjection<T>(namespace, "messages"),
    `values|${namespace.join(">")}`,
    undefined,
  );
}

The first render (before the effect runs) returns initialValue. Subsequent renders read from the acquired store. When the last consumer of a given key unmounts, the underlying server subscription is released automatically. Most apps never need this — prefer useValues / useMessages / useToolCalls / useChannel.

API reference

Functions

Function

useValues

Subscribe to a scoped values stream — the most recent state

Function

useMessages

Subscribe to a scoped messages stream.

Function

useToolCalls

Subscribe to a scoped tools (tool-call) stream. Same target and

Function

useMessageMetadata

Read metadata recorded for a specific message id — today exposes

Function

useSubmissionQueue

Function

useExtension

Subscribe to a custom:<name> stream extension — the most-recent

Function

useChannel

Function

useChannelEffect

Side-effect counterpart to useChannel. Instead of returning a

Function

useProjection

Svelte binding over ChannelRegistry.acquire. Mirrors the

Interfaces

Interface

UseSubmissionQueueReturn

Reactive handle on the server-side submission queue.

Interface

SubmissionQueueEntry

Queued submission entry mirrored from the server-side run queue.

Types

Type

SelectorTarget

What a selector composable targets. Callers can pass:

Type

SubmissionQueueSnapshot

Read-only snapshot of the queue. The queue store hands this out