LangChain Reference home pageLangChain ReferenceLangChain Reference
  • GitHub
  • Main Docs
Deep Agents
LangChain
LangGraph
Integrations
LangSmith
LangGraph
  • Web
  • Channels
  • Pregel
  • Prebuilt
  • Remote
  • Stream
  • Overview
  • Getting started
  • injectStream
  • Selectors
  • Interrupts & headless tools
  • Subagents & subgraphs
  • Fork & edit from a checkpoint
  • Submission queue
  • Multimodal media
  • Transports
  • Dependency injection
  • Type safety
  • Migrating to v1
LangGraph SDK
  • Ui
  • Client
  • Auth
  • React
  • Logging
  • React Ui
  • Utils
  • Server
  • Stream
LangGraph Checkpoint
LangGraph Checkpoint MongoDB
LangGraph Checkpoint Postgres
  • Store
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

LangGraph
WebChannelsPregelPrebuiltRemoteStream
OverviewGetting startedinjectStreamSelectorsInterrupts & headless toolsSubagents & subgraphsFork & edit from a checkpointSubmission queueMultimodal mediaTransportsDependency injectionType safetyMigrating to v1
LangGraph SDK
UiClientAuthReactLoggingReact UiUtilsServerStream
LangGraph Checkpoint
LangGraph Checkpoint MongoDB
LangGraph Checkpoint Postgres
Store
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/angularSelectors

Selectors

The root injectStream injector 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 injectors.

Each selector injector opens a ref-counted subscription when the first component calls it and releases it when the last consumer's DestroyRef is destroyed. 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 Signal or factory returning any target above — projections rebind automatically when the target changes.

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 selector list

Selector Returns Use for
injectValues(stream, target?) Signal<StateType> (root) / Signal<T \| undefined> (scoped) Arbitrary state / scoped snapshot.
injectMessages(stream, target?) Signal<BaseMessage[]> Message stream, root or scoped.
injectToolCalls(stream, target?) Signal<AssembledToolCall[]> Tool-call stream, with per-call status.
injectMessageMetadata(stream, msgId) Signal<{ parentCheckpointId } \| undefined> Powers fork / edit flows. See Fork & edit.
injectSubmissionQueue(stream) { entries, size, cancel, clear } Reactive client-side submission queue. See Queue.
injectExtension(stream, name, target?) Signal<T \| undefined> Read a named custom:<name> extension.
injectChannel(stream, channels, target?, options?) Signal<Event[]> Low-level raw-events escape hatch.
injectChannelEffect(stream, channels, options) void Per-event side effects like analytics or logs.
injectAudio / injectImages / injectVideo / injectFiles Signal<AudioMedia[]> / Signal<ImageMedia[]> / Signal<VideoMedia[]> / Signal<FileMedia[]> Assembled multimodal streams. See Multimodal.
injectMediaUrl(handle) Signal<string \| undefined> Turns a media handle into an <img/audio/video src>.

Root vs. scoped example

import { Component, Input } from "@angular/core";
import {
  injectMessages,
  injectStream,
  injectToolCalls,
  injectValues,
  type AnyStream,
  type SubagentDiscoverySnapshot,
} from "@langchain/angular";

@Component({
  standalone: true,
  template: `
    <app-thread-view [messages]="rootMessages()" />
    @for (sub of stream.subagents() | keyvalue; track sub.key) {
      <app-subagent-card [stream]="stream" [subagent]="sub.value" />
    }
  `,
})
export class ChatComponent {
  readonly stream = injectStream({
    assistantId: "agent",
    apiUrl: "/api",
  });

  readonly rootMessages = injectMessages(this.stream);
  readonly rootValues = injectValues(this.stream);
}

@Component({
  standalone: true,
  selector: "app-subagent-card",
  template: `
    <section>
      <header>{{ subagent.name }} - {{ subagent.status }}</header>
      @for (msg of messages(); track msg.id ?? $index) {
        <app-bubble [msg]="msg" />
      }
    </section>
  `,
})
export class SubagentCardComponent {
  @Input({ required: true }) stream!: AnyStream;
  @Input({ required: true }) subagent!: SubagentDiscoverySnapshot;

  readonly messages = injectMessages(this.stream, () => this.subagent);
  readonly toolCalls = injectToolCalls(this.stream, () => this.subagent);
  readonly values = injectValues<ResearcherState>(this.stream, () => this.subagent);
}

Target rebinding

When target is a Signal or factory, the projection follows the current value. This is useful for detail panes that switch between subagents without recreating the host component:

@Component({
  /* ... */
})
export class InspectorComponent {
  readonly stream = injectStream();
  readonly selectedSubagent = signal<SubagentDiscoverySnapshot | undefined>(undefined);

  readonly messages = injectMessages(this.stream, this.selectedSubagent);
  readonly values = injectValues(this.stream, this.selectedSubagent);
}

injectMessageMetadata

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

import { Component, Input } from "@angular/core";
import { HumanMessage, type BaseMessage } from "@langchain/core/messages";
import { injectMessageMetadata, type AnyStream } from "@langchain/angular";

@Component({
  template: `
    <button [disabled]="!metadata()?.parentCheckpointId" (click)="editFromHere()">
      Edit from here
    </button>
  `,
})
export class EditButtonComponent {
  @Input({ required: true }) stream!: AnyStream;
  @Input({ required: true }) message!: BaseMessage;

  readonly metadata = injectMessageMetadata(this.stream, () => this.message.id);

  editFromHere() {
    const forkFrom = this.metadata()?.parentCheckpointId;
    if (!forkFrom) return;
    void this.stream.submit({ messages: [new HumanMessage("...revised prompt...")] }, { forkFrom });
  }
}

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

injectChannel

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

const events = injectChannel(stream, ["values", "updates"]);

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

injectExtension

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

const telemetry = injectExtension<Telemetry>(stream, "telemetry");

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

injectChannelEffect

injectChannel is for events you render. When you instead want to react to each event — fire analytics, write a log, increment a metric — use injectChannelEffect. It invokes onEvent once per event and returns nothing, so it does not trigger template updates:

import { Component } from "@angular/core";
import { injectChannelEffect, injectStream } from "@langchain/angular";

@Component({
  /* ... */
})
export class AnalyticsComponent {
  readonly stream = injectStream();

  constructor() {
    injectChannelEffect(this.stream, ["lifecycle", "tools"], {
      replay: false,
      onEvent: (event) => sendAnalytics(event),
      onError: (error) => logger.error(error),
    });
  }
}

channels, target, and enabled accept signals, so effects can rebind without rebuilding the component. replay defaults to false (live-only); buffered events are not re-delivered unless you opt in.

injectProjection — building your own selector

injectProjection 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 selectors don't express. It acquires a ref-counted projection from the stream's channel registry and subscribes to its store through Angular signals:

import { injectProjection, STREAM_CONTROLLER } from "@langchain/angular";
import { valuesProjection } from "@langchain/langgraph-sdk/stream";

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

The first read returns initialValue. Subsequent reads use 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 injectValues / injectMessages / injectToolCalls / injectChannel.

API reference

Functions

Function

injectValues

Subscribe to a scoped values stream — the most recent state

Function

injectMessages

Subscribe to a scoped messages stream.

Function

injectToolCalls

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

Function

injectMessageMetadata

Read metadata recorded for a specific message id — today exposes

Function

injectSubmissionQueue

Function

injectExtension

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

Function

injectChannel

Function

injectChannelEffect

Side-effect counterpart to injectChannel. Instead of

Function

injectProjection

Angular-side primitive that composes ChannelRegistry.acquire

Interfaces

Interface

SubmissionQueueEntry

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

Types

Type

SelectorTarget

What a selector primitive can be targeted at. Callers can pass:

Type

SubmissionQueueSnapshot

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