UNPKG

@langchain/langgraph-sdk

Version:

Client library for interacting with the LangGraph API

295 lines (294 loc) • 8.41 kB
import { BaseClient, encodePathSegment } from "../base.js"; import { ThreadStream } from "../stream/index.js"; import { ProtocolSseTransportAdapter } from "../stream/transport/http.js"; import { ProtocolWebSocketTransportAdapter } from "../stream/transport/websocket.js"; import { v7 } from "@langchain/core/utils/uuid"; //#region src/client/threads/index.ts var ThreadsClient = class extends BaseClient { /** * Get a thread by ID. * * @param threadId ID of the thread. * @returns The thread. */ async get(threadId, options) { return this.fetch(`/threads/${encodePathSegment(threadId)}`, { params: { include: options?.include ?? void 0 }, signal: options?.signal }); } /** * Create a new thread. * * @param payload Payload for creating a thread. * @returns The created thread. */ async create(payload) { const ttlPayload = typeof payload?.ttl === "number" ? { ttl: payload.ttl, strategy: "delete" } : payload?.ttl; return this.fetch(`/threads`, { method: "POST", json: { metadata: { ...payload?.metadata, graph_id: payload?.graphId }, thread_id: payload?.threadId, if_exists: payload?.ifExists, supersteps: payload?.supersteps?.map((s) => ({ updates: s.updates.map((u) => ({ values: u.values, command: u.command, as_node: u.asNode })) })), ttl: ttlPayload }, signal: payload?.signal }); } /** * Copy an existing thread * @param threadId ID of the thread to be copied * @returns Newly copied thread */ async copy(threadId, options) { return this.fetch(`/threads/${encodePathSegment(threadId)}/copy`, { method: "POST", signal: options?.signal }); } async update(threadId, payload) { const ttlPayload = typeof payload?.ttl === "number" ? { ttl: payload.ttl, strategy: "delete" } : payload?.ttl; return this.fetch(`/threads/${encodePathSegment(threadId)}`, { method: "PATCH", headers: payload?.returnMinimal ? { Prefer: "return=minimal" } : void 0, json: { metadata: payload?.metadata, ttl: ttlPayload }, signal: payload?.signal }); } /** * Delete a thread. * * @param threadId ID of the thread. */ async delete(threadId, options) { return this.fetch(`/threads/${encodePathSegment(threadId)}`, { method: "DELETE", signal: options?.signal }); } /** * Prune threads by ID. The 'delete' strategy removes threads entirely. * The 'keep_latest' strategy prunes old checkpoints but keeps threads * and their latest state. * * @param threadIds List of thread IDs to prune. * @param options Additional options for pruning. * @param options.strategy The prune strategy. Defaults to 'delete'. * @param options.signal Signal to abort the request. * @returns An object containing `pruned_count`. */ async prune(threadIds, options) { return this.fetch("/threads/prune", { method: "POST", json: { thread_ids: threadIds, strategy: options?.strategy ?? "delete" }, signal: options?.signal }); } /** * List threads * * @param query Query options * @returns List of threads */ async search(query) { return this.fetch("/threads/search", { method: "POST", json: { metadata: query?.metadata ?? void 0, ids: query?.ids ?? void 0, limit: query?.limit ?? 10, offset: query?.offset ?? 0, status: query?.status, sort_by: query?.sortBy, sort_order: query?.sortOrder, select: query?.select ?? void 0, values: query?.values ?? void 0, extract: query?.extract ?? void 0 }, signal: query?.signal }); } /** * Count threads matching filters. * * @param query.metadata Thread metadata to filter on. * @param query.values State values to filter on. * @param query.status Thread status to filter on. * @returns Number of threads matching the criteria. */ async count(query) { return this.fetch(`/threads/count`, { method: "POST", json: { metadata: query?.metadata ?? void 0, values: query?.values ?? void 0, status: query?.status ?? void 0 }, signal: query?.signal }); } /** * Get state for a thread. * * @param threadId ID of the thread. * @returns Thread state. */ async getState(threadId, checkpoint, options) { if (checkpoint != null) { if (typeof checkpoint !== "string") return this.fetch(`/threads/${encodePathSegment(threadId)}/state/checkpoint`, { method: "POST", json: { checkpoint, subgraphs: options?.subgraphs }, signal: options?.signal }); return this.fetch(`/threads/${encodePathSegment(threadId)}/state/${encodePathSegment(checkpoint)}`, { params: { subgraphs: options?.subgraphs }, signal: options?.signal }); } return this.fetch(`/threads/${encodePathSegment(threadId)}/state`, { params: { subgraphs: options?.subgraphs }, signal: options?.signal, dedupe: true }); } /** * Add state to a thread. * * @param threadId The ID of the thread. * @returns */ async updateState(threadId, options) { return this.fetch(`/threads/${encodePathSegment(threadId)}/state`, { method: "POST", json: { values: options.values, checkpoint: options.checkpoint, checkpoint_id: options.checkpointId, as_node: options?.asNode }, signal: options?.signal }); } /** * Patch the metadata of a thread. * * @param threadIdOrConfig Thread ID or config to patch the state of. * @param metadata Metadata to patch the state with. */ async patchState(threadIdOrConfig, metadata, options) { let threadId; if (typeof threadIdOrConfig !== "string") { if (typeof threadIdOrConfig.configurable?.thread_id !== "string") throw new Error("Thread ID is required when updating state with a config."); threadId = threadIdOrConfig.configurable.thread_id; } else threadId = threadIdOrConfig; return this.fetch(`/threads/${encodePathSegment(threadId)}/state`, { method: "PATCH", json: { metadata }, signal: options?.signal }); } /** * Get all past states for a thread. * * @param threadId ID of the thread. * @param options Additional options. * @returns List of thread states. */ async getHistory(threadId, options) { return this.fetch(`/threads/${encodePathSegment(threadId)}/history`, { method: "POST", json: { limit: options?.limit ?? 10, before: options?.before, metadata: options?.metadata, checkpoint: options?.checkpoint }, signal: options?.signal, dedupe: true }); } async *joinStream(threadId, options) { yield* this.streamWithRetry({ endpoint: `/threads/${encodePathSegment(threadId)}/stream`, method: "GET", signal: options?.signal, headers: options?.lastEventId ? { "Last-Event-ID": options.lastEventId } : void 0, params: options?.streamMode ? { stream_mode: options.streamMode } : void 0 }); } stream(threadIdOrOptions, maybeOptions) { const { threadId, options } = typeof threadIdOrOptions === "string" ? { threadId: threadIdOrOptions, options: maybeOptions } : threadIdOrOptions == null ? { threadId: v7(), options: maybeOptions } : { threadId: v7(), options: threadIdOrOptions }; const userFetch = options.fetch; const protocolFetch = userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller); let transport; if (options.transport != null && typeof options.transport !== "string") { transport = options.transport; transport.setThreadId?.(threadId); } else { const transportKind = options.transport ?? (this.streamProtocol === "v2-websocket" ? "websocket" : "sse"); const maxReconnectAttempts = options.maxReconnectAttempts ?? 5; /** * Common options for both transports. */ const commonOpts = { apiUrl: this.apiUrl, threadId, defaultHeaders: this.defaultHeaders, onRequest: this.onRequest, maxReconnectAttempts, reconnectDelayMs: options.reconnectDelayMs, onReconnect: options.onReconnect, onConnected: options.onConnected }; transport = transportKind === "websocket" ? new ProtocolWebSocketTransportAdapter({ ...commonOpts, webSocketFactory: options.webSocketFactory }) : new ProtocolSseTransportAdapter({ ...commonOpts, idleReconnect: options.streamIdleReconnect, fetch: userFetch, asyncCaller: userFetch ? void 0 : this.asyncCaller }); } return new ThreadStream(transport, { ...options, fetch: protocolFetch }); } }; //#endregion export { ThreadsClient }; //# sourceMappingURL=index.js.map