LangChain Reference home pageLangChain ReferenceLangChain Reference
  • GitHub
  • Main Docs
Deep Agents
LangChain
LangGraph
Integrations
LangSmith
  • 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
  • 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 startedinjectStreamSelectorsInterrupts & headless toolsSubagents & subgraphsFork & edit from a checkpointSubmission queueMultimodal mediaTransportsDependency injectionType 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/angularThreadStream
Interfaceā—Since v1.0

ThreadStream

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 the client-side handle for interacting with a thread: starting runs, subscribing to events, consuming assembled projections (messages, values, toolCalls, etc.), and responding to interrupts.

Construct via client.threads.stream(threadId?, { assistantId? }).

Copy
interface ThreadStream

Properties

property
agent: __type
property
assistantId: string
property
input: InputModule
property
interrupted: boolean

Whether the run was interrupted (a lifecycle "interrupted" event was received). Mirrors the in-process run.interrupted.

property
interrupts: InterruptPayload<unknown>[]

Interrupt payloads collected during the run, if any. Mirrors the in-process run.interrupts.

property
ordering: SessionOrderingState
property
run: __type
property
state: StateModule
property
threadId: string
property
audio: AsyncIterable<AudioMedia>
property
extensions: ThreadExtensions<TExtensions>
property
files: AsyncIterable<FileMedia>
property
images: AsyncIterable<ImageMedia>
property
messages: AsyncIterable<StreamingMessageHandle>
property
output: Promise<unknown>
property
subagents: AsyncIterable<SubagentHandle>
property
subgraphs: AsyncIterable<SubgraphHandle>
property
toolCalls: AsyncIterable<ClientAssembledToolCall<string, unknown, unknown>>
property
values: AsyncIterable<unknown, any, any> & PromiseLike<unknown>
property
video: AsyncIterable<VideoMedia>

Methods

method
close→ Promise<void>
method
onError→ () => void

Register a listener for stream-level failures: an unsolicited server error frame, or the transport giving up on reconnecting. Returns an unsubscribe function.

method
onEvent→ () => void

Register a listener for every globally-unique event on the thread.

Fires exactly once per event_id across both the content pump (user subscribe() calls) and the lifecycle watcher. Events without an event_id always fire through (dedup is best-effort).

Returns an unsubscribe function. Primary consumer is StreamController, which uses the listener to feed discovery runners and pick up deeply-nested interrupts that the narrow content pump wouldn't deliver.

method
respondInput→ Promise<void>

Respond to an interrupt without the v1 eager lazy-getter shims. See submitRun for why this exists alongside input.respond.

method
startLifecycleWatcher

Public, idempotent entry point to start the wildcard lifecycle watcher.

The watcher is normally started lazily by submitRun / respondInput because for fresh (self-created) threads the SSE stream would 404 if opened before the server has the thread row. Callers that already know the thread exists server-side (StreamController.hydrate of an existing thread) can use this to start the watcher up front. The watcher subscribes to wildcard lifecycle events across every namespace, so it sees arbitrarily- nested subagent lifecycle messages that the narrow root content pump (running at depth: 1) wouldn't reach — that's what makes subagent discovery work for historical thread loads.

Idempotent — repeat calls reuse the in-flight start promise.

method
submitRun→ Promise<RunResult>

Start a run without the v1 eager lazy-getter shims.

run.start (the v1 entry point) eagerly opens a wildcard values projection so thread.output / thread.values resolve regardless of access order, and calls #ensureLifecycleTracking which opens another wildcard ["lifecycle", "input"] subscription. Both subscriptions widen #computeUnionFilter to wildcard, defeating the progressive-expansion rotation strategy.

submitRun skips those shims — callers that manage their own content subscriptions (such as StreamController) get the narrow union filter they asked for. Lifecycle / interrupt tracking is instead served by the dedicated #startLifecycleWatcher, which opens a wildcard ["lifecycle", "input"] stream alongside the narrow content pump on both SSE and WebSocket transports.

method
subscribe→ Promise<SubscriptionHandle<EventForChannel<TChannel>, YieldForChannel<TChannel>>>

Subscribe to raw wire channels and receive protocol events.

For assembled projections, use the lazy getters instead: thread.messages, thread.values, thread.toolCalls, thread.subgraphs, thread.subagents, thread.output.

View source on GitHub