@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
255 lines (254 loc) • 11.7 kB
text/typescript
import { ClientAssembledToolCall, ToolCallStatus } from "./handles/tools.cjs";
import { AssembledMessage, MessageAssembler, MessageAssemblyUpdate, StreamingMessage, StreamingMessageHandle } from "./messages.cjs";
import { AnyMediaHandle, AudioMedia, FileMedia, ImageMedia, MediaAssembler, MediaAssemblerCallbacks, MediaAssemblerOptions, MediaAssemblyError, MediaAssemblyErrorKind, MediaBase, MediaBlockType, VideoMedia } from "./media.cjs";
import { AgentServerAdapter, TransportAdapter } from "./transport.cjs";
import { EventForChannel, EventForChannels, EventMethodByChannel, EventSubscription, ExtendedRunStartParams, InputModule, InterruptPayload, MessageSubscription, SessionOrderingState, StateModule, SubscribeOptions, ThreadExtension, ThreadExtensions, ThreadModules, ThreadStreamOptions, ThreadStreamTransport, ThreadStreamTransportKind, UnwrapExtension, YieldForChannel, YieldForChannels } from "./types.cjs";
import { SubagentHandle } from "./handles/subagents.cjs";
import { SubgraphHandle, Subscribable } from "./handles/subgraphs.cjs";
import { inferChannel, matchesSubscription } from "./subscription.cjs";
import { ProtocolError } from "./error.cjs";
import { Channel, Event, InputRespondParams, RunResult, SubscribeParams } from "@langchain/protocol";
//#region src/client/stream/index.d.ts
/**
* Async iterable handle for raw event subscriptions.
*
* An optional `transform` maps each incoming event before it is queued
* or delivered to a waiting consumer. This is used by named custom
* channel subscriptions (e.g. `"custom:a2a"`) to unwrap the payload
* so callers receive the raw emitted data instead of the protocol
* event envelope.
*/
declare class SubscriptionHandle<TEvent extends Event = Event, TYield = TEvent> implements AsyncIterable<TYield>, EventSubscription<TYield> {
subscriptionId: string;
readonly params: SubscribeParams;
private readonly queue;
private readonly waiters;
private closed;
private paused;
private resumeResolve?;
private readonly onUnsubscribe;
private readonly transform;
constructor(subscriptionId: string, params: SubscribeParams, onUnsubscribe: (id: string) => Promise<void>, transform?: (event: TEvent) => TYield);
push(event: TEvent): void;
/**
* Pause the subscription: resolve all waiting iterators with `done: true`
* so `for await` loops exit, but keep the subscription alive. New events
* arriving while paused are still buffered. Call `resume()` to allow
* iterators to consume again.
*/
pause(): void;
/**
* Resume a paused subscription so new `for await` loops can consume
* buffered and future events.
*/
resume(): void;
/**
* Returns a promise that resolves when `resume()` is called. Resolves
* immediately if not currently paused.
*/
waitForResume(): Promise<void>;
get isPaused(): boolean;
close(): void;
unsubscribe(): Promise<void>;
[Symbol.asyncIterator](): AsyncIterator<TYield>;
}
/**
* 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? })`.
*
* @typeParam TExtensions - Optional map of `{ name: payload }` pairs
* describing the transformer projections the bound assistant exposes
* on `custom:<name>` channels. Narrows `thread.extensions.<name>` to
* `ThreadExtension<payload>`. Defaults to `Record<string, unknown>`.
*/
declare class ThreadStream<TExtensions extends Record<string, unknown> = Record<string, unknown>> {
#private;
readonly threadId: string;
readonly ordering: SessionOrderingState;
readonly run: ThreadModules["run"];
readonly agent: ThreadModules["agent"];
readonly input: ThreadModules["input"];
readonly state: ThreadModules["state"];
/**
* Whether the run was interrupted (a lifecycle "interrupted" event
* was received). Mirrors the in-process `run.interrupted`.
*/
interrupted: boolean;
/**
* Interrupt payloads collected during the run, if any.
* Mirrors the in-process `run.interrupts`.
*/
readonly interrupts: InterruptPayload[];
readonly assistantId: string;
constructor(transportAdapter: TransportAdapter, options: ThreadStreamOptions);
/**
* Streaming messages. Each `for await` loop gets an independent cursor
* over the shared buffer; late consumers see all previously emitted
* messages. Mirrors the in-process `run.messages`.
*/
get messages(): AsyncIterable<StreamingMessageHandle>;
/**
* State values. Iterable for intermediate snapshots; also
* `PromiseLike` — `await thread.values` resolves with the final
* state. Mirrors the in-process `run.values`.
*/
get values(): AsyncIterable<unknown> & PromiseLike<unknown>;
/**
* Tool calls with a promise-based {@link output} for script consumers.
* Mirrors the in-process `run.toolCalls`.
*/
get toolCalls(): AsyncIterable<ClientAssembledToolCall>;
/**
* Discovered subgraphs. Mirrors the in-process `run.subgraphs`.
*/
get subgraphs(): AsyncIterable<SubgraphHandle>;
/**
* Discovered subagents.
*/
get subagents(): AsyncIterable<SubagentHandle>;
/**
* Audio media handles, one per message containing at least one
* `AudioBlock`. Each `for await` opens an independent cursor over
* the shared buffer; late consumers replay every previously emitted
* audio handle.
*
* Yields one item per message on the first matching
* `content-block-start` — messages with no audio blocks are skipped.
*/
get audio(): AsyncIterable<AudioMedia>;
/**
* Image media handles, one per message containing at least one
* `ImageBlock`. See {@link audio} for shared semantics.
*/
get images(): AsyncIterable<ImageMedia>;
/**
* Video media handles, one per message containing at least one
* `VideoBlock`. See {@link audio} for shared semantics.
*/
get video(): AsyncIterable<VideoMedia>;
/**
* File media handles, one per message containing at least one
* `FileBlock`. See {@link audio} for shared semantics.
*/
get files(): AsyncIterable<FileMedia>;
/**
* Promise that resolves with the final state value when the run
* completes. Shares the `values` getter's SSE connection.
* Mirrors the in-process `run.output`.
*/
get output(): Promise<unknown>;
/**
* Proxy over compile-time {@link StreamTransformer} projections
* exposed by the bound assistant on `custom:<name>` channels.
*
* Each access (e.g. `thread.extensions.toolActivity`) lazily opens a
* dedicated `custom:<name>` subscription, returns a cached
* {@link ThreadExtension} handle that is both `AsyncIterable<T>`
* (streaming items as they arrive) and `PromiseLike<T>` (resolves
* with the final value when the run terminates), and reuses the same
* handle on subsequent access.
*
* Mirrors the in-process `run.extensions.<name>` shape.
*/
get extensions(): ThreadExtensions<TExtensions>;
/**
* 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.
*/
submitRun(params: {
input?: unknown;
config?: unknown;
metadata?: Record<string, unknown>;
/**
* Fork the new run from an explicit checkpoint instead of the
* thread's latest. This is an SDK-side convenience: it is folded into
* `config.configurable.checkpoint_id` before the `run.start` message
* is sent, so the agent server only ever sees the single
* legacy-compliant fork field (`forkFrom` never hits the wire).
*/
forkFrom?: string;
/**
* Controls how concurrent submissions on the same thread are
* handled by the server (`reject` | `rollback` | `interrupt` |
* `enqueue`).
*/
multitaskStrategy?: "reject" | "rollback" | "interrupt" | "enqueue";
}): Promise<RunResult>;
/**
* Respond to an interrupt without the v1 eager lazy-getter shims.
* See {@link submitRun} for why this exists alongside
* {@link input.respond}.
*/
respondInput(params: InputRespondParams): Promise<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.
*/
onEvent(listener: (event: Event) => void): () => void;
/**
* Register a listener for stream-level failures: an unsolicited server
* error frame, or the transport giving up on reconnecting. Returns an
* unsubscribe function.
*/
onError(listener: (error: Error) => void): () => void;
/**
* 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.
*/
startLifecycleWatcher(): void;
close(): Promise<void>;
/**
* 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`.
*/
subscribe<TChannel extends Channel>(channel: TChannel, options?: SubscribeOptions): Promise<SubscriptionHandle<EventForChannel<TChannel>, YieldForChannel<TChannel>>>;
subscribe<const TChannels extends readonly Channel[]>(channels: TChannels, options?: SubscribeOptions): Promise<SubscriptionHandle<EventForChannels<TChannels>, YieldForChannels<TChannels>>>;
subscribe(params: SubscribeParams): Promise<SubscriptionHandle<Event>>;
}
//#endregion
export { SubscriptionHandle, ThreadStream };
//# sourceMappingURL=index.d.cts.map