Angular SDK for building AI-powered applications with Deep Agents, LangChain and LangGraph.
The package ships a Signals-first API built on top of the v2 streaming
protocol. injectStream returns a small, always-on root handle
(values, messages, isLoading, error, …) and pushes anything
namespaced (subagents, subgraphs, media, submission queue, per-message
metadata) behind ref-counted inject* selectors so components
only pay for data they actually consume.
Upgrading from
0.x? Seedocs/v1-migration.mdfor the complete matrix of option, return-shape, and transport changes.
npm install @langchain/angular @langchain/core
Peer dependencies: @angular/core (^18.0.0 – ^21.0.0),
@langchain/core (^1.1.27).
import { Component } from "@angular/core";
import { injectStream } from "@langchain/angular";
@Component({
standalone: true,
template: `
<div>
@for (msg of stream.messages(); track msg.id ?? $index) {
<div>{{ str(msg.content) }}</div>
}
<button
[disabled]="stream.isLoading()"
(click)="onSubmit()"
>
Send
</button>
</div>
`,
})
export class ChatComponent {
readonly stream = injectStream({
assistantId: "agent",
apiUrl: "http://localhost:2024",
});
str(v: unknown) {
return typeof v === "string" ? v : JSON.stringify(v);
}
onSubmit() {
void this.stream.submit({
messages: [{ type: "human", content: "Hello!" }],
});
}
}
injectStream must be called from an Angular injection context —
the host's DestroyRef owns the stream, so navigating away destroys
the controller automatically.
Signal<T>s you call as
functions in templates.transport: "websocket"
opt-in) or a custom backend through an AgentServerAdapter.injectMessages, injectValues,
injectToolCalls, media selectors, submission queue — the first
consumer opens a subscription, the last one's DestroyRef closes
it. Components pay only for what they render.submit({ forkFrom }) replaces the legacy branch /
fetchStateHistory trio.provideStream for subtree sharing,
provideStreamDefaults for app-wide config, StreamService for
class-based wrappers.typeof agent as the first generic —
state, tool args, and per-subagent state flow through to every
selector.Use StreamApi<T> when you need to name the return type of
injectStream, useStream, provideStream, or StreamService in
Angular code. It is the Angular-facing alias for the Signals-first
handle.
UseStreamResult<T> is also exported as a React-compatible alias for
the same shape. Prefer it only in shared utilities that are designed to
accept stream handles from multiple framework packages.
In-depth guides live under docs/:
inject-stream.md — options + return-shape referencetransports.md — SSE, WebSocket, and custom AgentServerAdaptercustom-transport.md — implementing AgentServerAdapter against your own backend, with a worked walkthrough of examples/ui-react-transportselectors.md — scoped reads (injectMessages, injectValues, media, channels, …)interrupts.md — handling and responding to interruptsbranching.md — forking via injectMessageMetadata + submit({ forkFrom })submission-queue.md — injectSubmissionQueue and multitaskStrategy: "enqueue"headless-tools.md — browser-side tool implementationssubagents-subgraphs.md — discovery snapshots and scoped contentdependency-injection.md — provideStream, provideStreamDefaults, StreamServicetype-safety.md — generics, agent inference, and public stream aliasestesting.md — STREAM_INSTANCE fakes and service overridesv1-migration.md — migrating from 0.xFor complete end-to-end examples, 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
@Injectable() wrapper around useStream. Extend this class
with your own service when you want a DI-scoped, shareable
StreamApi:
@Injectable({ providedIn: "root" })
export class ChatStream ext
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.
Subscribe to a scoped audio-media stream. Each handle is yielded
on its first matching content-block-start, exposes
.partialBytes for live access, settles .blob / .objectURL /
.transcript on
Side-effect counterpart to injectChannel. Instead of
returning a signal of buffered events, it invokes onEvent once per
event for as long as the owning component / service is alive — the
idiomatic p
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. Pair with
injectMediaUrl for an <a download href> target.
Subscribe to a scoped image-media stream. Pair with
injectMediaUrl 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:
readonly meta = injectMessag
Subscribe to a scoped messages stream.
Contract:
target) this returns stream.messages — the
always-on root projection; no extra subscription is opened.Angular-side primitive that composes ChannelRegistry.acquire with Angular Signals + DestroyRef.
Contract (mirrors the React useProjection hook and the Vue
useProjection composable, but adapted to
Angular entry point for the v2-native stream runtime.
Call from a component, directive, or service field initializer to attach an StreamApi bound to the current DestroyRef:
@Component({ templa
Subscribe to a scoped tools (tool-call) stream. Same target and
lifecycle rules as injectMessages; at the root this returns
stream.toolCalls directly.
Subscribe to a scoped values stream — the most recent state
payload for a namespace. At the root returns stream.values.
Typing:
injectValues(stream)): returns the StateType
deSubscribe to a scoped video-media stream. Pair with
injectMediaUrl for <video src>.
Parses a headless-tool interrupt value from the graph. Accepts both
toolCall (LangChain JS) and tool_call (Python / JSON snake_case).
Creates a provider for a shared useStream instance at the component level.
Add the returned provider to a component's providers array so that all
child components can access the same stream via `
Provides default LangGraph configuration at the application level.
Use this in your application's providers array to set defaults like
apiUrl that will be used by all useStream and `injectStrea
Framework-free factory that constructs a StreamController and wraps its stores in Angular Signals. Callers must supply the DestroyRef that owns the controller's lifetime — it's already captured by the
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
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 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 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 iOptions for injectChannelEffect. 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 entries signal is stable p
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 iMetadata tracked per message id. Surfaced to applications via
useMessageMetadata(stream, messageId).
Configuration defaults for useStream and injectStream calls.
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.
High-level wrapper around a protocol connection to a specific thread.
In the thread-centric protocol, threads are durable (backed by
checkpoints) and connections are ephemeral. A ThreadStream is th
Return shape of useStream — the Angular StreamApi.
Reactivity primitives follow Angular conventions:
Signal<T>; call them as functions in
templates (`stream.messages()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 iErased handle useful as a parameter type for helper components that
pass a stream through to selector primitives without reading
values directly. Mirrors the React/Vue AnyStream alias.
Widening
Default tool call type when no specific tool definitions are provided.
Infer the state type from an agent, graph, or direct state type.
Detection order:
~agentTypes) → InferAgentState~RunOutput) → Extract RunOutputInfer subagent state map from a DeepAgent.
For DeepAgent, creates a map of subagent names to their state types. For non-DeepAgent, returns 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
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.
What a selector primitive can be targeted at. Callers can pass:
undefined / null — root namespace (served by the always-on
root store — no extra subscription);Convenience alias — the fully-resolved return type of
useStream for a given source type T.
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.
React-compatible alias for the fully-resolved stream handle type. Angular docs prefer StreamApi, but shared libraries can use this name across framework bindings.
Widens an update type so that its messages field also accepts
@langchain/core BaseMessage class instances (single or array).
Framework SDKs apply this to submit so callers can write:
stre