React SDK for building AI-powered applications with Deep Agents, LangChain and LangGraph.
@langchain/react v1 ships a v2-native useStream hook together with a small family of companion selector hooks. The root hook gives you always-on access to thread state, messages, tool calls, and interrupts; the selector hooks open ref-counted subscriptions for the things that aren't needed on every view (per-subagent messages, media streams, submission queue, message metadata, raw channels, …).
reconnectOnMount / joinStream dance.values, messages, toolCalls, and interrupts are live at the root with zero per-subscription cost.useStream<typeof agent>() unwraps state, tool calls, and subagent state maps from an agent brand.useSuspenseStream hands the initial hydration phase to <Suspense> and non-streaming errors to Error Boundaries.npm install @langchain/react @langchain/core
Peer dependencies: react (^18 || ^19), @langchain/core (^1.1.27).
import { useStream } from "@langchain/react";
function Chat() {
const { messages, submit, isLoading } = useStream({
assistantId: "agent",
apiUrl: "http://localhost:2024",
});
return (
<div>
{messages.map((msg, i) => (
<div key={msg.id ?? i}>{String(msg.content)}</div>
))}
<button
disabled={isLoading}
onClick={() =>
void submit({
messages: [{ type: "human", content: "Hello!" }],
})
}
>
Send
</button>
</div>
);
}
@langchain/react v1 splits the surface into two layers:
useStream). Owns the thread lifecycle, the transport, and a handful of always-on projections (values, messages, toolCalls, interrupts, error, isLoading, discovery maps). Mount it once per thread.import {
useStream,
useMessages,
useToolCalls,
useSubmissionQueue,
} from "@langchain/react";
function Chat() {
const stream = useStream({ assistantId: "agent", apiUrl: "/api" });
// Root: free reads, no new subscription.
const messages = useMessages(stream); // same as stream.messages
// Scoped: opens a namespaced subscription on mount.
const queue = useSubmissionQueue(stream);
}
Detailed guides live in ./docs. Start with the two files most apps need first:
useStream — options, return shape, submit(), stop(), respond(), hydrationPromise.useValues, useMessages, useToolCalls, useMessageMetadata, useChannel, useExtension, and friends.Feature-specific guides:
HttpAgentServerAdapter, custom AgentServerAdapter.AgentServerAdapter against your own backend, with a worked walkthrough of examples/ui-react-transport.respond(), tools + onTool.useMessageMetadata + submit({ forkFrom }).multitaskStrategy: "enqueue" + useSubmissionQueue.useAudio / useImages / useVideo / useFiles, useMediaURL, players.useSuspenseStream — Suspense + Error Boundary integration.StreamProvider / useStreamContext — share one stream across a subtree.The useStream import name is unchanged, but the return shape, option bag, and protocol semantics all shifted. Most chat apps migrate in well under an hour — the full migration guide with line-by-line diffs lives in ./docs/v1-migration.md.
Legacy type aliases (UseStream, UseSuspenseStream, UseStreamOptions, UseStreamTransport, QueueEntry, GetToolCallsType, SubagentStream, …) and the legacy FetchStreamTransport class are no longer re-exported from @langchain/react. Apps still on the legacy surface can import directly from @langchain/langgraph-sdk/ui during their migration.
For complete end-to-end examples with full agentic UIs, visit the LangChain UI Playground.
MIT
Public v1 name for TransportAdapter plus optional high-level capabilities. Renamed to reflect that this interface now denotes the full agent-server protocol contract (not merely wire transport): any o
Typed error thrown through media.stream / rejected from
media.blob / media.objectURL when a handle fails before its
message completes. Carries the bytes accumulated up to the failure
point on `p
Resume a headless-tool batch on the v1 commands transport.
headlessToolsBatchResumeCommand still returns a legacy
{ resume } command shape for callers on the old runs/stream API.
On v1 `StreamContr
Strip headless-tool interrupts from a user-facing interrupt list.
Execute and resume all newly seen headless-tool interrupts from a values
payload. Callers own handledIds and should clear it when the thread changes.
Parses a headless-tool interrupt value from the graph. Accepts both
toolCall (LangChain JS) and tool_call (Python / JSON snake_case).
Provides a shared useStream instance to all descendants via React Context.
Use StreamProvider when multiple components in a subtree need
access to the same stream state (messages, loading status, e
Subscribe to a scoped audio-media stream. Returns an array of
AudioMedia handles, one per message containing at least one
AudioBlock in the target namespace.
Each handle is yielded on its first mat
Progressive audio playback for AudioMedia handles with a
uniform surface across PCM (streamed) and container (HTMLAudioElement)
strategies.
Behaviour
Raw-events escape hatch. Subscribes to one or more channels at a namespace and returns a bounded buffer of raw protocol events.
The buffer keeps accumulating across serial runs for the lifetime of th
Side-effect counterpart to useChannel. Instead of returning a
buffer of events that re-renders the component, it invokes onEvent
once per event for as long as the hook is mounted — the idiomatic
pla
Subscribe to a custom:<name> stream extension — the most-recent
payload emitted by the transformer, scoped to the target namespace.
Returns only the latest value and resumes across serial runs, so
Subscribe to a scoped file-media stream. See useAudio for
shared semantics; pair with useMediaURL for an
<a download href> target.
Subscribe to a scoped image-media stream. See useAudio for
shared semantics; pair with useMediaURL for <img src>.
Resolve the lazy MediaBase.objectURL promise into a string
suitable for direct use in <audio src> / <img src> /
<video src> / <a href download>. Returns undefined until the
URL is available.
Read metadata recorded for a specific message id — today exposes
parentCheckpointId, the checkpoint the message was first seen on.
Designed for fork / edit flows:
const { parentCheckpointId
Subscribe to a scoped messages stream. Pass stream and
optionally a subagent/subgraph snapshot (or any namespaced target).
Contract:
stream.messages direReact-side primitive that composes ChannelRegistry.acquire with useSyncExternalStore.
Contract:
key changes) this hook acquires a
ref-counted projection from the registry anReact binding for the v2-native stream runtime.
useStream exposes three always-on projections
(values / messages / toolCalls) at the thread root plus
cheap discovery maps for subagents / subg
Accesses the shared stream instance from the nearest StreamProvider. Throws if called outside of one.
Subscribe to a scoped tools (tool-call) stream. Same target and
lifecycle rules as useMessages; at the root this just returns
stream.toolCalls.
The optional generic T can be passed to narrow th
Subscribe to a scoped values stream — most-recent state payload
for a namespace. Equivalent to reading stream.values at the root.
When the payload carries a messages array, it is coerced to
`Ba
Subscribe to a scoped video-media stream. See useAudio for
shared semantics; pair with useMediaURL for <video src>.
Bind a VideoMedia handle to a caller-owned <video> element.
Contract
<video ref={videoRef}> and styles it however
they like; the hook never injects DOM nor overrides lPublic v1 name for TransportAdapter plus optional high-level capabilities. Renamed to reflect that this interface now denotes the full agent-server protocol contract (not merely wire transport): any o
Reactive tool handle for framework bindings (stream.toolCalls,
useToolCalls, injectToolCalls).
status, error, and output are plain values that the assembler updates in place as tool events arri
Shared surface across every media handle returned by MediaAssembler.
The handle is live while its parent message is active:
partialBytes is a snapshot of all bytes received so far.stream iPlayer controls + live state returned by useAudioPlayer.
Shape is shared with useVideoPlayer where possible — learn one surface, use it for both.
Shared surface across every media handle returned by MediaAssembler.
The handle is live while its parent message is active:
partialBytes is a snapshot of all bytes received so far.stream iClient-side implementation returned by headlessTool.implement(...).
Represents a headless tool interrupt payload emitted by LangChain's
schema-only tool({ ... }) overload.
Servers may serialize the nested tool call as toolCall (JS) or
tool_call (Python). Use pa
Shared surface across every media handle returned by MediaAssembler.
The handle is live while its parent message is active:
partialBytes is a snapshot of all bytes received so far.stream iShared surface across every media handle returned by MediaAssembler.
The handle is live while its parent message is active:
partialBytes is a snapshot of all bytes received so far.stream iMetadata tracked per message id. Surfaced to applications via
useMessageMetadata(stream, messageId).
Options for StreamController.stop / framework stop().
Lightweight discovery record for a subagent running inside the thread.
Populated eagerly from the root subscription (tools + lifecycle
channels). Content projections (messages, toolCalls, cus
Lightweight discovery record for a subgraph running inside the thread.
A single queued submission.
Options for useAudioPlayer.
All fields optional; defaults cover OpenAI gpt-4o-audio-preview
pcm16 streams (sampleRate: 24000, channels: 1) and any WAV
stream the upstream model emits.
Options for useChannelEffect. Extends the projection options
(bufferSize, replay) with the per-event callback, an optional
error sink, a target scope, and an enabled gate.
Reactive handle on the server-side submission queue.
Populated when submit() is invoked with multitaskStrategy: "enqueue" while another run is in flight. The returned object is
stable per snapsho
Options for useVideoPlayer.
Shared surface across every media handle returned by MediaAssembler.
The handle is live while its parent message is active:
partialBytes is a snapshot of all bytes received so far.stream iControls + live state returned by useVideoPlayer. Mirrors AudioPlayerHandle on the shared subset so callers only ever learn one shape.
Erased stream handle useful as a parameter type for helpers and
wrapper components that pass a stream through to selector hooks
(useMessages, useChannel, …) without reading values directly.
A
Default tool call type when no specific tool definitions are provided.
Unwrap the state shape from a compiled graph, a create-agent brand,
or a plain type. Used by useStream<T>() to resolve T = typeof agent into the state the values/messages projections observe.
Infer the subagent → state map from a DeepAgent brand. Non-brands collapse to DefaultSubagentStates.
Infer the discriminated union of AssembledToolCall handles from an agent brand, an array of LangChain tools, or fall back to the untyped default handle.
Pass typeof agent or typeof tools and narr
Infer the successful return type of a LangChain tool.
Resolution order mirrors InferToolInput: func, then
invoke, then _call, so inference survives cross-package
boundaries where _call is `pr
Kinds of failure that can terminate a media handle prematurely.
"message-error" — the upstream message emitted an error event
before completion."stream-closed" — the transport stream cloBlock types this assembler knows how to reassemble into media handles.
Read-only map exposed via MessageMetadataTracker.store.
Lifecycle state of an audio or video player returned by useAudioPlayer and useVideoPlayer.
Single-enum design (vs. multiple booleans) eliminates impossible
states and gives callers a clean switch t
What a selector hook can be targeted at. Callers can pass any of:
undefined — root namespace (cheap: served by the always-on root store)Props for StreamProvider when wiring a custom
AgentServerAdapter. Mirrors CustomAdapterOptions
plus children.
Props for StreamProvider when talking to the default
LangGraph Platform agent server. Mirrors AgentServerOptions
plus children.
Read-only snapshot of the queue. The queue store hands this out directly; consumers must not mutate the array.
Infer the streaming AssembledToolCall handle for a single LangChain tool.
Parallel to ToolCallFromTool for message-level tool calls — use this when a component receives one entry from `stream.toolCal
Infer a union of tool call types from an array of tools.
Works with tools created via tool() from @langchain/core/tools.
The lifecycle state of a tool call.
pending: Tool call received, awaiting resultcompleted: Tool execution finished successfullyerror: Tool execution failed (result.status === "error")High-level outcome of a single tool call.
Convenience alias for the fully-resolved stream handle type.
Return shape of useSuspenseStream. Identical to the UseStreamReturn surface except:
isLoading / isThreadLoading / hydrationPromise are removed
(Suspense and Error Boundaries handle those phWiden an update type so its messages field also accepts
@langchain/core BaseMessage class instances (single or
array). Framework bindings apply this to submit() so callers can
write `stream.subm