UNPKG

@langchain/langgraph-sdk

Version:

Client library for interacting with the LangGraph API

255 lines (254 loc) • 11.7 kB
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