@langchain/langgraph-sdk 1.10.3-rc.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/stream/index.cjs +23 -1
- package/dist/client/stream/index.cjs.map +1 -1
- package/dist/client/stream/index.d.cts +6 -0
- package/dist/client/stream/index.d.cts.map +1 -1
- package/dist/client/stream/index.d.ts +6 -0
- package/dist/client/stream/index.d.ts.map +1 -1
- package/dist/client/stream/index.js +23 -1
- package/dist/client/stream/index.js.map +1 -1
- package/dist/client/stream/transport/http.cjs +23 -5
- package/dist/client/stream/transport/http.cjs.map +1 -1
- package/dist/client/stream/transport/http.d.cts +1 -0
- package/dist/client/stream/transport/http.d.cts.map +1 -1
- package/dist/client/stream/transport/http.d.ts +1 -0
- package/dist/client/stream/transport/http.d.ts.map +1 -1
- package/dist/client/stream/transport/http.js +23 -5
- package/dist/client/stream/transport/http.js.map +1 -1
- package/dist/client/stream/transport/types.d.cts +9 -12
- package/dist/client/stream/transport/types.d.cts.map +1 -1
- package/dist/client/stream/transport/types.d.ts +9 -12
- package/dist/client/stream/transport/types.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.cjs +15 -3
- package/dist/client/stream/transport/websocket.cjs.map +1 -1
- package/dist/client/stream/transport/websocket.d.cts +1 -0
- package/dist/client/stream/transport/websocket.d.cts.map +1 -1
- package/dist/client/stream/transport/websocket.d.ts +1 -0
- package/dist/client/stream/transport/websocket.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.js +15 -3
- package/dist/client/stream/transport/websocket.js.map +1 -1
- package/dist/client/stream/types.d.cts +5 -7
- package/dist/client/stream/types.d.cts.map +1 -1
- package/dist/client/stream/types.d.ts +5 -7
- package/dist/client/stream/types.d.ts.map +1 -1
- package/dist/client/threads/index.cjs +2 -1
- package/dist/client/threads/index.cjs.map +1 -1
- package/dist/client/threads/index.js +2 -1
- package/dist/client/threads/index.js.map +1 -1
- package/dist/stream/controller.cjs +111 -31
- package/dist/stream/controller.cjs.map +1 -1
- package/dist/stream/controller.d.cts.map +1 -1
- package/dist/stream/controller.d.ts.map +1 -1
- package/dist/stream/controller.js +111 -31
- package/dist/stream/controller.js.map +1 -1
- package/dist/stream/types.d.cts +5 -0
- package/dist/stream/types.d.cts.map +1 -1
- package/dist/stream/types.d.ts +5 -0
- package/dist/stream/types.d.ts.map +1 -1
- package/dist/utils/reconnect.cjs.map +1 -1
- package/dist/utils/reconnect.d.cts +18 -0
- package/dist/utils/reconnect.d.cts.map +1 -0
- package/dist/utils/reconnect.d.ts +18 -0
- package/dist/utils/reconnect.d.ts.map +1 -0
- package/dist/utils/reconnect.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["uuidv7"],"sources":["../../../src/client/threads/index.ts"],"sourcesContent":["import { v7 as uuidv7 } from \"@langchain/core/utils/uuid\";\n\nimport {\n Checkpoint,\n Config,\n DefaultValues,\n Metadata,\n SortOrder,\n Thread,\n ThreadSelectField,\n ThreadSortBy,\n ThreadState,\n ThreadStatus,\n ThreadValuesFilter,\n} from \"../../schema.js\";\nimport type { Command, OnConflictBehavior, StreamEvent } from \"../../types.js\";\nimport type { ThreadStreamMode } from \"../../types.stream.js\";\nimport { BaseClient } from \"../base.js\";\nimport { ThreadStream } from \"../stream/index.js\";\nimport type {\n ThreadStreamOptions,\n ThreadStreamTransportKind,\n} from \"../stream/types.js\";\nimport { DEFAULT_MAX_RECONNECT_ATTEMPTS } from \"../../utils/reconnect.js\";\nimport { ProtocolSseTransportAdapter } from \"../stream/transport/http.js\";\nimport { ProtocolWebSocketTransportAdapter } from \"../stream/transport/websocket.js\";\nimport type { TransportAdapter } from \"../stream/transport.js\";\n\nexport class ThreadsClient<\n TStateType = DefaultValues,\n TUpdateType = TStateType,\n> extends BaseClient {\n /**\n * Get a thread by ID.\n *\n * @param threadId ID of the thread.\n * @returns The thread.\n */\n async get<ValuesType = TStateType>(\n threadId: string,\n options?: { signal?: AbortSignal; include?: string[] }\n ): Promise<Thread<ValuesType>> {\n return this.fetch<Thread<ValuesType>>(`/threads/${threadId}`, {\n params: {\n include: options?.include ?? undefined,\n },\n signal: options?.signal,\n });\n }\n\n /**\n * Create a new thread.\n *\n * @param payload Payload for creating a thread.\n * @returns The created thread.\n */\n async create(payload?: {\n metadata?: Metadata;\n threadId?: string;\n ifExists?: OnConflictBehavior;\n graphId?: string;\n supersteps?: Array<{\n updates: Array<{ values: unknown; command?: Command; asNode: string }>;\n }>;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n signal?: AbortSignal;\n }): Promise<Thread<TStateType>> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread<TStateType>>(`/threads`, {\n method: \"POST\",\n json: {\n metadata: {\n ...payload?.metadata,\n graph_id: payload?.graphId,\n },\n thread_id: payload?.threadId,\n if_exists: payload?.ifExists,\n supersteps: payload?.supersteps?.map((s) => ({\n updates: s.updates.map((u) => ({\n values: u.values,\n command: u.command,\n as_node: u.asNode,\n })),\n })),\n ttl: ttlPayload,\n },\n signal: payload?.signal,\n });\n }\n\n /**\n * Copy an existing thread\n * @param threadId ID of the thread to be copied\n * @returns Newly copied thread\n */\n async copy(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<Thread<TStateType>> {\n return this.fetch<Thread<TStateType>>(`/threads/${threadId}/copy`, {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n /**\n * Update a thread.\n *\n * @param threadId ID of the thread.\n * @param payload Payload for updating the thread.\n * @returns The updated thread.\n */\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: false;\n signal?: AbortSignal;\n }\n ): Promise<Thread>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: true;\n signal?: AbortSignal;\n }\n ): Promise<void>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void>;\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread | void>(`/threads/${threadId}`, {\n method: \"PATCH\",\n headers: payload?.returnMinimal\n ? { Prefer: \"return=minimal\" }\n : undefined,\n json: { metadata: payload?.metadata, ttl: ttlPayload },\n signal: payload?.signal,\n });\n }\n\n /**\n * Delete a thread.\n *\n * @param threadId ID of the thread.\n */\n async delete(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n return this.fetch<void>(`/threads/${threadId}`, {\n method: \"DELETE\",\n signal: options?.signal,\n });\n }\n\n /**\n * Prune threads by ID. The 'delete' strategy removes threads entirely.\n * The 'keep_latest' strategy prunes old checkpoints but keeps threads\n * and their latest state.\n *\n * @param threadIds List of thread IDs to prune.\n * @param options Additional options for pruning.\n * @param options.strategy The prune strategy. Defaults to 'delete'.\n * @param options.signal Signal to abort the request.\n * @returns An object containing `pruned_count`.\n */\n async prune(\n threadIds: string[],\n options?: {\n strategy?: \"delete\" | \"keep_latest\";\n signal?: AbortSignal;\n }\n ): Promise<{ pruned_count: number }> {\n return this.fetch<{ pruned_count: number }>(\"/threads/prune\", {\n method: \"POST\",\n json: {\n thread_ids: threadIds,\n strategy: options?.strategy ?? \"delete\",\n },\n signal: options?.signal,\n });\n }\n\n /**\n * List threads\n *\n * @param query Query options\n * @returns List of threads\n */\n async search<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n ids?: string[];\n limit?: number;\n offset?: number;\n status?: ThreadStatus;\n sortBy?: ThreadSortBy;\n sortOrder?: SortOrder;\n select?: ThreadSelectField[];\n values?: ThreadValuesFilter;\n extract?: Record<string, string>;\n signal?: AbortSignal;\n }): Promise<Thread<ValuesType>[]> {\n return this.fetch<Thread<ValuesType>[]>(\"/threads/search\", {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n ids: query?.ids ?? undefined,\n limit: query?.limit ?? 10,\n offset: query?.offset ?? 0,\n status: query?.status,\n sort_by: query?.sortBy,\n sort_order: query?.sortOrder,\n select: query?.select ?? undefined,\n values: query?.values ?? undefined,\n extract: query?.extract ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Count threads matching filters.\n *\n * @param query.metadata Thread metadata to filter on.\n * @param query.values State values to filter on.\n * @param query.status Thread status to filter on.\n * @returns Number of threads matching the criteria.\n */\n async count<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n values?: ValuesType;\n status?: ThreadStatus;\n signal?: AbortSignal;\n }): Promise<number> {\n return this.fetch<number>(`/threads/count`, {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n values: query?.values ?? undefined,\n status: query?.status ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Get state for a thread.\n *\n * @param threadId ID of the thread.\n * @returns Thread state.\n */\n async getState<ValuesType = TStateType>(\n threadId: string,\n checkpoint?: Checkpoint | string,\n options?: { subgraphs?: boolean; signal?: AbortSignal }\n ): Promise<ThreadState<ValuesType>> {\n if (checkpoint != null) {\n if (typeof checkpoint !== \"string\") {\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/checkpoint`,\n {\n method: \"POST\",\n json: { checkpoint, subgraphs: options?.subgraphs },\n signal: options?.signal,\n }\n );\n }\n\n // deprecated\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/${checkpoint}`,\n { params: { subgraphs: options?.subgraphs }, signal: options?.signal }\n );\n }\n\n return this.fetch<ThreadState<ValuesType>>(`/threads/${threadId}/state`, {\n params: { subgraphs: options?.subgraphs },\n signal: options?.signal,\n // Coalesce concurrent identical reads (e.g. two controllers\n // hydrating the same thread on reconnect). Skipped automatically\n // when a caller supplies its own `signal`.\n dedupe: true,\n });\n }\n\n /**\n * Add state to a thread.\n *\n * @param threadId The ID of the thread.\n * @returns\n */\n async updateState<ValuesType = TUpdateType>(\n threadId: string,\n options: {\n values: ValuesType;\n checkpoint?: Checkpoint;\n checkpointId?: string;\n asNode?: string;\n signal?: AbortSignal;\n }\n ): Promise<Pick<Config, \"configurable\">> {\n return this.fetch<Pick<Config, \"configurable\">>(\n `/threads/${threadId}/state`,\n {\n method: \"POST\",\n json: {\n values: options.values,\n checkpoint: options.checkpoint,\n checkpoint_id: options.checkpointId,\n as_node: options?.asNode,\n },\n signal: options?.signal,\n }\n );\n }\n\n /**\n * Patch the metadata of a thread.\n *\n * @param threadIdOrConfig Thread ID or config to patch the state of.\n * @param metadata Metadata to patch the state with.\n */\n async patchState(\n threadIdOrConfig: string | Config,\n metadata: Metadata,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n let threadId: string;\n\n if (typeof threadIdOrConfig !== \"string\") {\n if (typeof threadIdOrConfig.configurable?.thread_id !== \"string\") {\n throw new Error(\n \"Thread ID is required when updating state with a config.\"\n );\n }\n threadId = threadIdOrConfig.configurable.thread_id;\n } else {\n threadId = threadIdOrConfig;\n }\n\n return this.fetch<void>(`/threads/${threadId}/state`, {\n method: \"PATCH\",\n json: { metadata },\n signal: options?.signal,\n });\n }\n\n /**\n * Get all past states for a thread.\n *\n * @param threadId ID of the thread.\n * @param options Additional options.\n * @returns List of thread states.\n */\n async getHistory<ValuesType = TStateType>(\n threadId: string,\n options?: {\n limit?: number;\n before?: Config;\n checkpoint?: Partial<Omit<Checkpoint, \"thread_id\">>;\n metadata?: Metadata;\n signal?: AbortSignal;\n }\n ): Promise<ThreadState<ValuesType>[]> {\n return this.fetch<ThreadState<ValuesType>[]>(\n `/threads/${threadId}/history`,\n {\n method: \"POST\",\n json: {\n limit: options?.limit ?? 10,\n before: options?.before,\n metadata: options?.metadata,\n checkpoint: options?.checkpoint,\n },\n signal: options?.signal,\n // `getHistory` is a read despite using POST — coalesce the\n // hydrate-time discovery seed when two controllers reconnect to\n // the same thread concurrently. Skipped when `signal` is set.\n dedupe: true,\n }\n );\n }\n\n async *joinStream(\n threadId: string,\n options?: {\n lastEventId?: string;\n streamMode?: ThreadStreamMode | ThreadStreamMode[];\n signal?: AbortSignal;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): AsyncGenerator<{ id?: string; event: StreamEvent; data: any }> {\n yield* this.streamWithRetry({\n endpoint: `/threads/${threadId}/stream`,\n method: \"GET\",\n signal: options?.signal,\n headers: options?.lastEventId\n ? { \"Last-Event-ID\": options.lastEventId }\n : undefined,\n params: options?.streamMode\n ? { stream_mode: options.streamMode }\n : undefined,\n });\n }\n\n /**\n * Open a protocol stream over the thread-centric v2 protocol.\n *\n * Returns a {@link ThreadStream} with lazy getters\n * (`.messages`, `.values`, `.toolCalls`, `.subgraphs`, `.subagents`,\n * `.output`) and `thread.run.start({ input, ... })` for starting runs.\n * Mirrors the in-process `graph.streamEvents(..., { version: \"v3\" })` API.\n *\n * The thread is bound to `options.assistantId` for its lifetime.\n * The wire transport defaults to SSE; pass `transport: \"websocket\"`\n * in options (or configure `streamProtocol: \"v2-websocket\"` on the\n * client) to use a WebSocket instead.\n *\n * @example New thread (UUID generated client-side)\n * ```ts\n * const thread = client.threads.stream({ assistantId: \"my-agent\" });\n * ```\n *\n * @example Attach to an existing thread\n * ```ts\n * const thread = client.threads.stream(threadId, { assistantId: \"my-agent\" });\n * ```\n *\n * @example WebSocket transport\n * ```ts\n * const thread = client.threads.stream({\n * assistantId: \"my-agent\",\n * transport: \"websocket\",\n * });\n * ```\n */\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadId: string,\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadIdOrOptions: string | ThreadStreamOptions,\n maybeOptions?: ThreadStreamOptions\n ): ThreadStream<TExtensions> {\n const { threadId, options } =\n typeof threadIdOrOptions === \"string\"\n ? {\n threadId: threadIdOrOptions,\n options: maybeOptions as ThreadStreamOptions,\n }\n : // A nullish first arg is the generate-thread-id form, not the\n // options-only overload. Without this branch, a runtime\n // `stream(null, opts)` binds `null` to `options` and the\n // `options.fetch` read below throws. Use the second arg as options.\n // (Cast: the declared type excludes null, but callers can reach\n // here at runtime, e.g. an in-flight reconnect after the id clears.)\n (threadIdOrOptions as ThreadStreamOptions | null | undefined) == null\n ? {\n threadId: uuidv7(),\n options: maybeOptions as ThreadStreamOptions,\n }\n : { threadId: uuidv7(), options: threadIdOrOptions };\n\n // `transport` accepts either a preset string (`\"sse\"` / `\"websocket\"`)\n // or a custom {@link AgentServerAdapter}. A custom adapter replaces\n // the built-in factories entirely — this is the seam that lets users\n // point `useStream` at any agent server (including the thin wrappers\n // produced by `HttpAgentServerAdapter`).\n // When callers supply `fetch`, use it verbatim (tests, auth shims). Otherwise\n // route protocol HTTP and media URL fetches through AsyncCaller like REST.\n const userFetch = options.fetch;\n const protocolFetch =\n userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller);\n\n let transport: TransportAdapter;\n if (options.transport != null && typeof options.transport !== \"string\") {\n transport = options.transport;\n // Bind (or re-bind) the caller-supplied adapter to this thread so a\n // single instance can follow lazy creation (the first `submit()` on a\n // `threadId: null` controller mints the id here) and thread switches.\n // No-op for adapters that bake `threadId` at construction.\n transport.setThreadId?.(threadId);\n } else {\n const transportKind: ThreadStreamTransportKind =\n options.transport ??\n (this.streamProtocol === \"v2-websocket\" ? \"websocket\" : \"sse\");\n const maxReconnectAttempts =\n options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;\n\n /**\n * Common options for both transports.\n */\n const commonOpts = {\n apiUrl: this.apiUrl,\n threadId,\n defaultHeaders: this.defaultHeaders,\n onRequest: this.onRequest,\n maxReconnectAttempts,\n reconnectDelayMs: options.reconnectDelayMs,\n onReconnect: options.onReconnect,\n };\n\n transport =\n transportKind === \"websocket\"\n ? new ProtocolWebSocketTransportAdapter({\n ...commonOpts,\n webSocketFactory: options.webSocketFactory,\n })\n : new ProtocolSseTransportAdapter({\n ...commonOpts,\n idleReconnect: options.streamIdleReconnect,\n fetch: userFetch,\n asyncCaller: userFetch ? undefined : this.asyncCaller,\n });\n }\n\n return new ThreadStream<TExtensions>(transport, {\n ...options,\n fetch: protocolFetch,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["uuidv7"],"sources":["../../../src/client/threads/index.ts"],"sourcesContent":["import { v7 as uuidv7 } from \"@langchain/core/utils/uuid\";\n\nimport {\n Checkpoint,\n Config,\n DefaultValues,\n Metadata,\n SortOrder,\n Thread,\n ThreadSelectField,\n ThreadSortBy,\n ThreadState,\n ThreadStatus,\n ThreadValuesFilter,\n} from \"../../schema.js\";\nimport type { Command, OnConflictBehavior, StreamEvent } from \"../../types.js\";\nimport type { ThreadStreamMode } from \"../../types.stream.js\";\nimport { BaseClient } from \"../base.js\";\nimport { ThreadStream } from \"../stream/index.js\";\nimport type {\n ThreadStreamOptions,\n ThreadStreamTransportKind,\n} from \"../stream/types.js\";\nimport { DEFAULT_MAX_RECONNECT_ATTEMPTS } from \"../../utils/reconnect.js\";\nimport { ProtocolSseTransportAdapter } from \"../stream/transport/http.js\";\nimport { ProtocolWebSocketTransportAdapter } from \"../stream/transport/websocket.js\";\nimport type { TransportAdapter } from \"../stream/transport.js\";\n\nexport class ThreadsClient<\n TStateType = DefaultValues,\n TUpdateType = TStateType,\n> extends BaseClient {\n /**\n * Get a thread by ID.\n *\n * @param threadId ID of the thread.\n * @returns The thread.\n */\n async get<ValuesType = TStateType>(\n threadId: string,\n options?: { signal?: AbortSignal; include?: string[] }\n ): Promise<Thread<ValuesType>> {\n return this.fetch<Thread<ValuesType>>(`/threads/${threadId}`, {\n params: {\n include: options?.include ?? undefined,\n },\n signal: options?.signal,\n });\n }\n\n /**\n * Create a new thread.\n *\n * @param payload Payload for creating a thread.\n * @returns The created thread.\n */\n async create(payload?: {\n metadata?: Metadata;\n threadId?: string;\n ifExists?: OnConflictBehavior;\n graphId?: string;\n supersteps?: Array<{\n updates: Array<{ values: unknown; command?: Command; asNode: string }>;\n }>;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n signal?: AbortSignal;\n }): Promise<Thread<TStateType>> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread<TStateType>>(`/threads`, {\n method: \"POST\",\n json: {\n metadata: {\n ...payload?.metadata,\n graph_id: payload?.graphId,\n },\n thread_id: payload?.threadId,\n if_exists: payload?.ifExists,\n supersteps: payload?.supersteps?.map((s) => ({\n updates: s.updates.map((u) => ({\n values: u.values,\n command: u.command,\n as_node: u.asNode,\n })),\n })),\n ttl: ttlPayload,\n },\n signal: payload?.signal,\n });\n }\n\n /**\n * Copy an existing thread\n * @param threadId ID of the thread to be copied\n * @returns Newly copied thread\n */\n async copy(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<Thread<TStateType>> {\n return this.fetch<Thread<TStateType>>(`/threads/${threadId}/copy`, {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n /**\n * Update a thread.\n *\n * @param threadId ID of the thread.\n * @param payload Payload for updating the thread.\n * @returns The updated thread.\n */\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: false;\n signal?: AbortSignal;\n }\n ): Promise<Thread>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: true;\n signal?: AbortSignal;\n }\n ): Promise<void>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void>;\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread | void>(`/threads/${threadId}`, {\n method: \"PATCH\",\n headers: payload?.returnMinimal\n ? { Prefer: \"return=minimal\" }\n : undefined,\n json: { metadata: payload?.metadata, ttl: ttlPayload },\n signal: payload?.signal,\n });\n }\n\n /**\n * Delete a thread.\n *\n * @param threadId ID of the thread.\n */\n async delete(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n return this.fetch<void>(`/threads/${threadId}`, {\n method: \"DELETE\",\n signal: options?.signal,\n });\n }\n\n /**\n * Prune threads by ID. The 'delete' strategy removes threads entirely.\n * The 'keep_latest' strategy prunes old checkpoints but keeps threads\n * and their latest state.\n *\n * @param threadIds List of thread IDs to prune.\n * @param options Additional options for pruning.\n * @param options.strategy The prune strategy. Defaults to 'delete'.\n * @param options.signal Signal to abort the request.\n * @returns An object containing `pruned_count`.\n */\n async prune(\n threadIds: string[],\n options?: {\n strategy?: \"delete\" | \"keep_latest\";\n signal?: AbortSignal;\n }\n ): Promise<{ pruned_count: number }> {\n return this.fetch<{ pruned_count: number }>(\"/threads/prune\", {\n method: \"POST\",\n json: {\n thread_ids: threadIds,\n strategy: options?.strategy ?? \"delete\",\n },\n signal: options?.signal,\n });\n }\n\n /**\n * List threads\n *\n * @param query Query options\n * @returns List of threads\n */\n async search<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n ids?: string[];\n limit?: number;\n offset?: number;\n status?: ThreadStatus;\n sortBy?: ThreadSortBy;\n sortOrder?: SortOrder;\n select?: ThreadSelectField[];\n values?: ThreadValuesFilter;\n extract?: Record<string, string>;\n signal?: AbortSignal;\n }): Promise<Thread<ValuesType>[]> {\n return this.fetch<Thread<ValuesType>[]>(\"/threads/search\", {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n ids: query?.ids ?? undefined,\n limit: query?.limit ?? 10,\n offset: query?.offset ?? 0,\n status: query?.status,\n sort_by: query?.sortBy,\n sort_order: query?.sortOrder,\n select: query?.select ?? undefined,\n values: query?.values ?? undefined,\n extract: query?.extract ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Count threads matching filters.\n *\n * @param query.metadata Thread metadata to filter on.\n * @param query.values State values to filter on.\n * @param query.status Thread status to filter on.\n * @returns Number of threads matching the criteria.\n */\n async count<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n values?: ValuesType;\n status?: ThreadStatus;\n signal?: AbortSignal;\n }): Promise<number> {\n return this.fetch<number>(`/threads/count`, {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n values: query?.values ?? undefined,\n status: query?.status ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Get state for a thread.\n *\n * @param threadId ID of the thread.\n * @returns Thread state.\n */\n async getState<ValuesType = TStateType>(\n threadId: string,\n checkpoint?: Checkpoint | string,\n options?: { subgraphs?: boolean; signal?: AbortSignal }\n ): Promise<ThreadState<ValuesType>> {\n if (checkpoint != null) {\n if (typeof checkpoint !== \"string\") {\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/checkpoint`,\n {\n method: \"POST\",\n json: { checkpoint, subgraphs: options?.subgraphs },\n signal: options?.signal,\n }\n );\n }\n\n // deprecated\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/${checkpoint}`,\n { params: { subgraphs: options?.subgraphs }, signal: options?.signal }\n );\n }\n\n return this.fetch<ThreadState<ValuesType>>(`/threads/${threadId}/state`, {\n params: { subgraphs: options?.subgraphs },\n signal: options?.signal,\n // Coalesce concurrent identical reads (e.g. two controllers\n // hydrating the same thread on reconnect). Skipped automatically\n // when a caller supplies its own `signal`.\n dedupe: true,\n });\n }\n\n /**\n * Add state to a thread.\n *\n * @param threadId The ID of the thread.\n * @returns\n */\n async updateState<ValuesType = TUpdateType>(\n threadId: string,\n options: {\n values: ValuesType;\n checkpoint?: Checkpoint;\n checkpointId?: string;\n asNode?: string;\n signal?: AbortSignal;\n }\n ): Promise<Pick<Config, \"configurable\">> {\n return this.fetch<Pick<Config, \"configurable\">>(\n `/threads/${threadId}/state`,\n {\n method: \"POST\",\n json: {\n values: options.values,\n checkpoint: options.checkpoint,\n checkpoint_id: options.checkpointId,\n as_node: options?.asNode,\n },\n signal: options?.signal,\n }\n );\n }\n\n /**\n * Patch the metadata of a thread.\n *\n * @param threadIdOrConfig Thread ID or config to patch the state of.\n * @param metadata Metadata to patch the state with.\n */\n async patchState(\n threadIdOrConfig: string | Config,\n metadata: Metadata,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n let threadId: string;\n\n if (typeof threadIdOrConfig !== \"string\") {\n if (typeof threadIdOrConfig.configurable?.thread_id !== \"string\") {\n throw new Error(\n \"Thread ID is required when updating state with a config.\"\n );\n }\n threadId = threadIdOrConfig.configurable.thread_id;\n } else {\n threadId = threadIdOrConfig;\n }\n\n return this.fetch<void>(`/threads/${threadId}/state`, {\n method: \"PATCH\",\n json: { metadata },\n signal: options?.signal,\n });\n }\n\n /**\n * Get all past states for a thread.\n *\n * @param threadId ID of the thread.\n * @param options Additional options.\n * @returns List of thread states.\n */\n async getHistory<ValuesType = TStateType>(\n threadId: string,\n options?: {\n limit?: number;\n before?: Config;\n checkpoint?: Partial<Omit<Checkpoint, \"thread_id\">>;\n metadata?: Metadata;\n signal?: AbortSignal;\n }\n ): Promise<ThreadState<ValuesType>[]> {\n return this.fetch<ThreadState<ValuesType>[]>(\n `/threads/${threadId}/history`,\n {\n method: \"POST\",\n json: {\n limit: options?.limit ?? 10,\n before: options?.before,\n metadata: options?.metadata,\n checkpoint: options?.checkpoint,\n },\n signal: options?.signal,\n // `getHistory` is a read despite using POST — coalesce the\n // hydrate-time discovery seed when two controllers reconnect to\n // the same thread concurrently. Skipped when `signal` is set.\n dedupe: true,\n }\n );\n }\n\n async *joinStream(\n threadId: string,\n options?: {\n lastEventId?: string;\n streamMode?: ThreadStreamMode | ThreadStreamMode[];\n signal?: AbortSignal;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): AsyncGenerator<{ id?: string; event: StreamEvent; data: any }> {\n yield* this.streamWithRetry({\n endpoint: `/threads/${threadId}/stream`,\n method: \"GET\",\n signal: options?.signal,\n headers: options?.lastEventId\n ? { \"Last-Event-ID\": options.lastEventId }\n : undefined,\n params: options?.streamMode\n ? { stream_mode: options.streamMode }\n : undefined,\n });\n }\n\n /**\n * Open a protocol stream over the thread-centric v2 protocol.\n *\n * Returns a {@link ThreadStream} with lazy getters\n * (`.messages`, `.values`, `.toolCalls`, `.subgraphs`, `.subagents`,\n * `.output`) and `thread.run.start({ input, ... })` for starting runs.\n * Mirrors the in-process `graph.streamEvents(..., { version: \"v3\" })` API.\n *\n * The thread is bound to `options.assistantId` for its lifetime.\n * The wire transport defaults to SSE; pass `transport: \"websocket\"`\n * in options (or configure `streamProtocol: \"v2-websocket\"` on the\n * client) to use a WebSocket instead.\n *\n * @example New thread (UUID generated client-side)\n * ```ts\n * const thread = client.threads.stream({ assistantId: \"my-agent\" });\n * ```\n *\n * @example Attach to an existing thread\n * ```ts\n * const thread = client.threads.stream(threadId, { assistantId: \"my-agent\" });\n * ```\n *\n * @example WebSocket transport\n * ```ts\n * const thread = client.threads.stream({\n * assistantId: \"my-agent\",\n * transport: \"websocket\",\n * });\n * ```\n */\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadId: string,\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadIdOrOptions: string | ThreadStreamOptions,\n maybeOptions?: ThreadStreamOptions\n ): ThreadStream<TExtensions> {\n const { threadId, options } =\n typeof threadIdOrOptions === \"string\"\n ? {\n threadId: threadIdOrOptions,\n options: maybeOptions as ThreadStreamOptions,\n }\n : // A nullish first arg is the generate-thread-id form, not the\n // options-only overload. Without this branch, a runtime\n // `stream(null, opts)` binds `null` to `options` and the\n // `options.fetch` read below throws. Use the second arg as options.\n // (Cast: the declared type excludes null, but callers can reach\n // here at runtime, e.g. an in-flight reconnect after the id clears.)\n (threadIdOrOptions as ThreadStreamOptions | null | undefined) == null\n ? {\n threadId: uuidv7(),\n options: maybeOptions as ThreadStreamOptions,\n }\n : { threadId: uuidv7(), options: threadIdOrOptions };\n\n // `transport` accepts either a preset string (`\"sse\"` / `\"websocket\"`)\n // or a custom {@link AgentServerAdapter}. A custom adapter replaces\n // the built-in factories entirely — this is the seam that lets users\n // point `useStream` at any agent server (including the thin wrappers\n // produced by `HttpAgentServerAdapter`).\n // When callers supply `fetch`, use it verbatim (tests, auth shims). Otherwise\n // route protocol HTTP and media URL fetches through AsyncCaller like REST.\n const userFetch = options.fetch;\n const protocolFetch =\n userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller);\n\n let transport: TransportAdapter;\n if (options.transport != null && typeof options.transport !== \"string\") {\n transport = options.transport;\n // Bind (or re-bind) the caller-supplied adapter to this thread so a\n // single instance can follow lazy creation (the first `submit()` on a\n // `threadId: null` controller mints the id here) and thread switches.\n // No-op for adapters that bake `threadId` at construction.\n transport.setThreadId?.(threadId);\n } else {\n const transportKind: ThreadStreamTransportKind =\n options.transport ??\n (this.streamProtocol === \"v2-websocket\" ? \"websocket\" : \"sse\");\n const maxReconnectAttempts =\n options.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;\n\n /**\n * Common options for both transports.\n */\n const commonOpts = {\n apiUrl: this.apiUrl,\n threadId,\n defaultHeaders: this.defaultHeaders,\n onRequest: this.onRequest,\n maxReconnectAttempts,\n reconnectDelayMs: options.reconnectDelayMs,\n onReconnect: options.onReconnect,\n onConnected: options.onConnected,\n };\n\n transport =\n transportKind === \"websocket\"\n ? new ProtocolWebSocketTransportAdapter({\n ...commonOpts,\n webSocketFactory: options.webSocketFactory,\n })\n : new ProtocolSseTransportAdapter({\n ...commonOpts,\n idleReconnect: options.streamIdleReconnect,\n fetch: userFetch,\n asyncCaller: userFetch ? undefined : this.asyncCaller,\n });\n }\n\n return new ThreadStream<TExtensions>(transport, {\n ...options,\n fetch: protocolFetch,\n });\n }\n}\n"],"mappings":";;;;;;AA4BA,IAAa,gBAAb,cAGU,WAAW;;;;;;;CAOnB,MAAM,IACJ,UACA,SAC6B;AAC7B,SAAO,KAAK,MAA0B,YAAY,YAAY;GAC5D,QAAQ,EACN,SAAS,SAAS,WAAW,KAAA,GAC9B;GACD,QAAQ,SAAS;GAClB,CAAC;;;;;;;;CASJ,MAAM,OAAO,SAUmB;EAC9B,MAAM,aACJ,OAAO,SAAS,QAAQ,WACpB;GAAE,KAAK,QAAQ;GAAK,UAAU;GAAmB,GACjD,SAAS;AAEf,SAAO,KAAK,MAA0B,YAAY;GAChD,QAAQ;GACR,MAAM;IACJ,UAAU;KACR,GAAG,SAAS;KACZ,UAAU,SAAS;KACpB;IACD,WAAW,SAAS;IACpB,WAAW,SAAS;IACpB,YAAY,SAAS,YAAY,KAAK,OAAO,EAC3C,SAAS,EAAE,QAAQ,KAAK,OAAO;KAC7B,QAAQ,EAAE;KACV,SAAS,EAAE;KACX,SAAS,EAAE;KACZ,EAAE,EACJ,EAAE;IACH,KAAK;IACN;GACD,QAAQ,SAAS;GAClB,CAAC;;;;;;;CAQJ,MAAM,KACJ,UACA,SAC6B;AAC7B,SAAO,KAAK,MAA0B,YAAY,SAAS,QAAQ;GACjE,QAAQ;GACR,QAAQ,SAAS;GAClB,CAAC;;CAqCJ,MAAM,OACJ,UACA,SAMwB;EACxB,MAAM,aACJ,OAAO,SAAS,QAAQ,WACpB;GAAE,KAAK,QAAQ;GAAK,UAAU;GAAmB,GACjD,SAAS;AAEf,SAAO,KAAK,MAAqB,YAAY,YAAY;GACvD,QAAQ;GACR,SAAS,SAAS,gBACd,EAAE,QAAQ,kBAAkB,GAC5B,KAAA;GACJ,MAAM;IAAE,UAAU,SAAS;IAAU,KAAK;IAAY;GACtD,QAAQ,SAAS;GAClB,CAAC;;;;;;;CAQJ,MAAM,OACJ,UACA,SACe;AACf,SAAO,KAAK,MAAY,YAAY,YAAY;GAC9C,QAAQ;GACR,QAAQ,SAAS;GAClB,CAAC;;;;;;;;;;;;;CAcJ,MAAM,MACJ,WACA,SAImC;AACnC,SAAO,KAAK,MAAgC,kBAAkB;GAC5D,QAAQ;GACR,MAAM;IACJ,YAAY;IACZ,UAAU,SAAS,YAAY;IAChC;GACD,QAAQ,SAAS;GAClB,CAAC;;;;;;;;CASJ,MAAM,OAAgC,OAYJ;AAChC,SAAO,KAAK,MAA4B,mBAAmB;GACzD,QAAQ;GACR,MAAM;IACJ,UAAU,OAAO,YAAY,KAAA;IAC7B,KAAK,OAAO,OAAO,KAAA;IACnB,OAAO,OAAO,SAAS;IACvB,QAAQ,OAAO,UAAU;IACzB,QAAQ,OAAO;IACf,SAAS,OAAO;IAChB,YAAY,OAAO;IACnB,QAAQ,OAAO,UAAU,KAAA;IACzB,QAAQ,OAAO,UAAU,KAAA;IACzB,SAAS,OAAO,WAAW,KAAA;IAC5B;GACD,QAAQ,OAAO;GAChB,CAAC;;;;;;;;;;CAWJ,MAAM,MAA+B,OAKjB;AAClB,SAAO,KAAK,MAAc,kBAAkB;GAC1C,QAAQ;GACR,MAAM;IACJ,UAAU,OAAO,YAAY,KAAA;IAC7B,QAAQ,OAAO,UAAU,KAAA;IACzB,QAAQ,OAAO,UAAU,KAAA;IAC1B;GACD,QAAQ,OAAO;GAChB,CAAC;;;;;;;;CASJ,MAAM,SACJ,UACA,YACA,SACkC;AAClC,MAAI,cAAc,MAAM;AACtB,OAAI,OAAO,eAAe,SACxB,QAAO,KAAK,MACV,YAAY,SAAS,oBACrB;IACE,QAAQ;IACR,MAAM;KAAE;KAAY,WAAW,SAAS;KAAW;IACnD,QAAQ,SAAS;IAClB,CACF;AAIH,UAAO,KAAK,MACV,YAAY,SAAS,SAAS,cAC9B;IAAE,QAAQ,EAAE,WAAW,SAAS,WAAW;IAAE,QAAQ,SAAS;IAAQ,CACvE;;AAGH,SAAO,KAAK,MAA+B,YAAY,SAAS,SAAS;GACvE,QAAQ,EAAE,WAAW,SAAS,WAAW;GACzC,QAAQ,SAAS;GAIjB,QAAQ;GACT,CAAC;;;;;;;;CASJ,MAAM,YACJ,UACA,SAOuC;AACvC,SAAO,KAAK,MACV,YAAY,SAAS,SACrB;GACE,QAAQ;GACR,MAAM;IACJ,QAAQ,QAAQ;IAChB,YAAY,QAAQ;IACpB,eAAe,QAAQ;IACvB,SAAS,SAAS;IACnB;GACD,QAAQ,SAAS;GAClB,CACF;;;;;;;;CASH,MAAM,WACJ,kBACA,UACA,SACe;EACf,IAAI;AAEJ,MAAI,OAAO,qBAAqB,UAAU;AACxC,OAAI,OAAO,iBAAiB,cAAc,cAAc,SACtD,OAAM,IAAI,MACR,2DACD;AAEH,cAAW,iBAAiB,aAAa;QAEzC,YAAW;AAGb,SAAO,KAAK,MAAY,YAAY,SAAS,SAAS;GACpD,QAAQ;GACR,MAAM,EAAE,UAAU;GAClB,QAAQ,SAAS;GAClB,CAAC;;;;;;;;;CAUJ,MAAM,WACJ,UACA,SAOoC;AACpC,SAAO,KAAK,MACV,YAAY,SAAS,WACrB;GACE,QAAQ;GACR,MAAM;IACJ,OAAO,SAAS,SAAS;IACzB,QAAQ,SAAS;IACjB,UAAU,SAAS;IACnB,YAAY,SAAS;IACtB;GACD,QAAQ,SAAS;GAIjB,QAAQ;GACT,CACF;;CAGH,OAAO,WACL,UACA,SAMgE;AAChE,SAAO,KAAK,gBAAgB;GAC1B,UAAU,YAAY,SAAS;GAC/B,QAAQ;GACR,QAAQ,SAAS;GACjB,SAAS,SAAS,cACd,EAAE,iBAAiB,QAAQ,aAAa,GACxC,KAAA;GACJ,QAAQ,SAAS,aACb,EAAE,aAAa,QAAQ,YAAY,GACnC,KAAA;GACL,CAAC;;CAyCJ,OACE,mBACA,cAC2B;EAC3B,MAAM,EAAE,UAAU,YAChB,OAAO,sBAAsB,WACzB;GACE,UAAU;GACV,SAAS;GACV,GAOA,qBAAgE,OAC/D;GACE,UAAUA,IAAQ;GAClB,SAAS;GACV,GACD;GAAE,UAAUA,IAAQ;GAAE,SAAS;GAAmB;EAS1D,MAAM,YAAY,QAAQ;EAC1B,MAAM,gBACJ,aAAa,KAAK,YAAY,MAAM,KAAK,KAAK,YAAY;EAE5D,IAAI;AACJ,MAAI,QAAQ,aAAa,QAAQ,OAAO,QAAQ,cAAc,UAAU;AACtE,eAAY,QAAQ;AAKpB,aAAU,cAAc,SAAS;SAC5B;GACL,MAAM,gBACJ,QAAQ,cACP,KAAK,mBAAmB,iBAAiB,cAAc;GAC1D,MAAM,uBACJ,QAAQ,wBAAA;;;;GAKV,MAAM,aAAa;IACjB,QAAQ,KAAK;IACb;IACA,gBAAgB,KAAK;IACrB,WAAW,KAAK;IAChB;IACA,kBAAkB,QAAQ;IAC1B,aAAa,QAAQ;IACrB,aAAa,QAAQ;IACtB;AAED,eACE,kBAAkB,cACd,IAAI,kCAAkC;IACpC,GAAG;IACH,kBAAkB,QAAQ;IAC3B,CAAC,GACF,IAAI,4BAA4B;IAC9B,GAAG;IACH,eAAe,QAAQ;IACvB,OAAO;IACP,aAAa,YAAY,KAAA,IAAY,KAAK;IAC3C,CAAC;;AAGV,SAAO,IAAI,aAA0B,WAAW;GAC9C,GAAG;GACH,OAAO;GACR,CAAC"}
|
|
@@ -105,6 +105,8 @@ const ROOT_PUMP_CHANNELS = [
|
|
|
105
105
|
"messages",
|
|
106
106
|
"tools"
|
|
107
107
|
];
|
|
108
|
+
const PARKED_INTERRUPT_SETTLE_MS = 5e3;
|
|
109
|
+
const PARKED_INTERRUPT_SETTLE_POLL_MS = 500;
|
|
108
110
|
/**
|
|
109
111
|
* Coordinates one thread's protocol-v2 stream and exposes stable
|
|
110
112
|
* observable projections for framework bindings.
|
|
@@ -143,6 +145,7 @@ var StreamController = class {
|
|
|
143
145
|
*/
|
|
144
146
|
#rootPumpDeferred = false;
|
|
145
147
|
#threadEventUnsubscribe;
|
|
148
|
+
#threadErrorUnsubscribe;
|
|
146
149
|
#disposed = false;
|
|
147
150
|
#pendingDisposeTimer = null;
|
|
148
151
|
/**
|
|
@@ -167,17 +170,16 @@ var StreamController = class {
|
|
|
167
170
|
* than {@link #interruptReplayThroughSeq} bypass the allowlist.
|
|
168
171
|
*/
|
|
169
172
|
#hydratedActiveInterruptIds = null;
|
|
170
|
-
/** Checkpoint whose replay establishes the hydrate-time interrupt cutoff. */
|
|
171
|
-
#hydratedInterruptCheckpointId;
|
|
172
173
|
/**
|
|
173
|
-
* Highest event sequence
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
174
|
+
* Highest event sequence already applied when the latest run command
|
|
175
|
+
* was accepted. Interrupts outside the hydrate-time allowlist remain
|
|
176
|
+
* filtered through this sequence, while newer events are live output
|
|
177
|
+
* from the newly-started run and must be accepted.
|
|
177
178
|
*/
|
|
178
179
|
#interruptReplayThroughSeq;
|
|
179
|
-
/** Unknown inputs waiting
|
|
180
|
+
/** Unknown inputs waiting to be classified as live or replayed history. */
|
|
180
181
|
#pendingHydrationInterruptEvents = [];
|
|
182
|
+
#settleParkedInterruptsPromise;
|
|
181
183
|
/**
|
|
182
184
|
* Unknown interrupt events received between local command dispatch and its
|
|
183
185
|
* response. The response supplies the sequence barrier needed to classify
|
|
@@ -331,7 +333,6 @@ var StreamController = class {
|
|
|
331
333
|
this.#interruptCommandPending = this.#hydratedActiveInterruptIds != null;
|
|
332
334
|
this.#pendingInterruptEvents = this.#pendingHydrationInterruptEvents;
|
|
333
335
|
this.#pendingHydrationInterruptEvents = [];
|
|
334
|
-
this.#hydratedInterruptCheckpointId = void 0;
|
|
335
336
|
},
|
|
336
337
|
onRunStart: () => this.#markLocalRunStart(),
|
|
337
338
|
onRunCreated: (runId) => {
|
|
@@ -582,7 +583,6 @@ var StreamController = class {
|
|
|
582
583
|
}));
|
|
583
584
|
if (this.#submitGeneration === generationAtFetch) {
|
|
584
585
|
this.#hydratedActiveInterruptIds = activeIds;
|
|
585
|
-
this.#hydratedInterruptCheckpointId = state.checkpoint?.checkpoint_id ?? void 0;
|
|
586
586
|
this.#interruptReplayThroughSeq = void 0;
|
|
587
587
|
}
|
|
588
588
|
}
|
|
@@ -1218,7 +1218,10 @@ var StreamController = class {
|
|
|
1218
1218
|
* still required.
|
|
1219
1219
|
*/
|
|
1220
1220
|
#ensureThread(threadId, deferRootPump = false) {
|
|
1221
|
-
if (this.#thread != null)
|
|
1221
|
+
if (this.#thread != null) {
|
|
1222
|
+
if (!deferRootPump && !this.#rootPumpDeferred && this.#rootPump == null) this.#startRootPump(this.#thread);
|
|
1223
|
+
return this.#thread;
|
|
1224
|
+
}
|
|
1222
1225
|
this.#thread = this.#options.client.threads.stream(threadId, {
|
|
1223
1226
|
assistantId: this.#options.assistantId,
|
|
1224
1227
|
transport: this.#options.transport,
|
|
@@ -1227,7 +1230,8 @@ var StreamController = class {
|
|
|
1227
1230
|
maxReconnectAttempts: this.#options.maxReconnectAttempts,
|
|
1228
1231
|
streamIdleReconnect: this.#options.streamIdleReconnect,
|
|
1229
1232
|
reconnectDelayMs: this.#options.reconnectDelayMs,
|
|
1230
|
-
onReconnect: this.#options.onReconnect
|
|
1233
|
+
onReconnect: this.#options.onReconnect,
|
|
1234
|
+
onConnected: this.#options.onConnected
|
|
1231
1235
|
});
|
|
1232
1236
|
this.registry.bind(this.#thread);
|
|
1233
1237
|
if (deferRootPump) {
|
|
@@ -1287,6 +1291,8 @@ var StreamController = class {
|
|
|
1287
1291
|
this.registry.bind(void 0);
|
|
1288
1292
|
this.#threadEventUnsubscribe?.();
|
|
1289
1293
|
this.#threadEventUnsubscribe = void 0;
|
|
1294
|
+
this.#threadErrorUnsubscribe?.();
|
|
1295
|
+
this.#threadErrorUnsubscribe = void 0;
|
|
1290
1296
|
/**
|
|
1291
1297
|
* Persistent lifecycle driver is scoped to the current thread
|
|
1292
1298
|
* stream. Remove it so a swap to a new thread starts with a clean
|
|
@@ -1314,7 +1320,6 @@ var StreamController = class {
|
|
|
1314
1320
|
this.#localRunDepth = 0;
|
|
1315
1321
|
this.#messageMetadata.reset();
|
|
1316
1322
|
this.#hydratedActiveInterruptIds = null;
|
|
1317
|
-
this.#hydratedInterruptCheckpointId = void 0;
|
|
1318
1323
|
this.#interruptReplayThroughSeq = void 0;
|
|
1319
1324
|
this.#pendingHydrationInterruptEvents = [];
|
|
1320
1325
|
this.#discardPendingInterruptEvents();
|
|
@@ -1363,6 +1368,14 @@ var StreamController = class {
|
|
|
1363
1368
|
* pump's narrow filter.
|
|
1364
1369
|
*/
|
|
1365
1370
|
this.#threadEventUnsubscribe = thread.onEvent((event) => this.#onWildcardEvent(event));
|
|
1371
|
+
this.#threadErrorUnsubscribe = thread.onError((error) => {
|
|
1372
|
+
this.rootStore.setState((s) => ({
|
|
1373
|
+
...s,
|
|
1374
|
+
error,
|
|
1375
|
+
isLoading: false
|
|
1376
|
+
}));
|
|
1377
|
+
this.#rootSubscription?.close();
|
|
1378
|
+
});
|
|
1366
1379
|
/**
|
|
1367
1380
|
* Persistent isLoading driver. Drives `isLoading` from
|
|
1368
1381
|
* root-namespace lifecycle events so that in-flight runs observed
|
|
@@ -1373,7 +1386,7 @@ var StreamController = class {
|
|
|
1373
1386
|
*/
|
|
1374
1387
|
this.#rootEventListeners.add(this.#lifecycleLoading.listener);
|
|
1375
1388
|
this.#rootEventListeners.add(this.#runLifecycleListener);
|
|
1376
|
-
|
|
1389
|
+
const pump = (async () => {
|
|
1377
1390
|
try {
|
|
1378
1391
|
/**
|
|
1379
1392
|
* Root content pump: depth 1 is required because the controller
|
|
@@ -1464,7 +1477,15 @@ var StreamController = class {
|
|
|
1464
1477
|
} catch {}
|
|
1465
1478
|
}
|
|
1466
1479
|
if (this.#disposed || pumpGeneration !== this.#rootPumpGeneration) break;
|
|
1467
|
-
if (!subscription.isPaused)
|
|
1480
|
+
if (!subscription.isPaused) {
|
|
1481
|
+
const snapshot = this.rootStore.getSnapshot();
|
|
1482
|
+
if (snapshot.isLoading && snapshot.error == null) this.rootStore.setState((s) => ({
|
|
1483
|
+
...s,
|
|
1484
|
+
error: /* @__PURE__ */ new Error("Thread event stream closed before the active run completed."),
|
|
1485
|
+
isLoading: false
|
|
1486
|
+
}));
|
|
1487
|
+
break;
|
|
1488
|
+
}
|
|
1468
1489
|
await subscription.waitForResume();
|
|
1469
1490
|
}
|
|
1470
1491
|
} catch {
|
|
@@ -1472,6 +1493,21 @@ var StreamController = class {
|
|
|
1472
1493
|
resolveReady = void 0;
|
|
1473
1494
|
}
|
|
1474
1495
|
})();
|
|
1496
|
+
this.#rootPump = pump;
|
|
1497
|
+
pump.finally(() => {
|
|
1498
|
+
if (pumpGeneration !== this.#rootPumpGeneration) return;
|
|
1499
|
+
if (this.#rootPump !== pump) return;
|
|
1500
|
+
this.#rootPumpGeneration += 1;
|
|
1501
|
+
this.#rootSubscription = void 0;
|
|
1502
|
+
this.#rootPump = void 0;
|
|
1503
|
+
this.#rootPumpReady = void 0;
|
|
1504
|
+
this.#threadEventUnsubscribe?.();
|
|
1505
|
+
this.#threadEventUnsubscribe = void 0;
|
|
1506
|
+
this.#threadErrorUnsubscribe?.();
|
|
1507
|
+
this.#threadErrorUnsubscribe = void 0;
|
|
1508
|
+
this.#rootEventListeners.delete(this.#lifecycleLoading.listener);
|
|
1509
|
+
this.#rootEventListeners.delete(this.#runLifecycleListener);
|
|
1510
|
+
});
|
|
1475
1511
|
}
|
|
1476
1512
|
/**
|
|
1477
1513
|
* Handle an event delivered via {@link ThreadStream.onEvent}.
|
|
@@ -1492,7 +1528,6 @@ var StreamController = class {
|
|
|
1492
1528
|
} catch {}
|
|
1493
1529
|
this.#subgraphs.push(event);
|
|
1494
1530
|
this.#lifecycleLoading.handle(event);
|
|
1495
|
-
this.#advanceInterruptReplayBarrierFromCheckpoint(event);
|
|
1496
1531
|
/**
|
|
1497
1532
|
* `input.requested` events (including HITL inside a subagent /
|
|
1498
1533
|
* subgraph) are not always observable via the narrow content pump.
|
|
@@ -1502,6 +1537,7 @@ var StreamController = class {
|
|
|
1502
1537
|
* resume targeting.
|
|
1503
1538
|
*/
|
|
1504
1539
|
this.#recordInterrupt(event);
|
|
1540
|
+
this.#settleParkedInterruptsOnTerminal(event);
|
|
1505
1541
|
}
|
|
1506
1542
|
/**
|
|
1507
1543
|
* Process one root-pump event and update all root projections.
|
|
@@ -1742,11 +1778,12 @@ var StreamController = class {
|
|
|
1742
1778
|
this.#pendingInterruptEvents.push(event);
|
|
1743
1779
|
return;
|
|
1744
1780
|
}
|
|
1745
|
-
|
|
1781
|
+
const barrier = this.#interruptReplayThroughSeq;
|
|
1782
|
+
if (isUnknownInterrupt && barrier == null) {
|
|
1746
1783
|
this.#pendingHydrationInterruptEvents.push(event);
|
|
1747
1784
|
return;
|
|
1748
1785
|
}
|
|
1749
|
-
if (isUnknownInterrupt &&
|
|
1786
|
+
if (isUnknownInterrupt && barrier != null && eventSeq != null && eventSeq <= barrier) return;
|
|
1750
1787
|
const namespace = Array.isArray(event.params.namespace) ? [...event.params.namespace] : [...ROOT_NAMESPACE];
|
|
1751
1788
|
const interrupt = require_interrupts.normalizeInterruptForClient({
|
|
1752
1789
|
id: interruptId,
|
|
@@ -1763,16 +1800,6 @@ var StreamController = class {
|
|
|
1763
1800
|
};
|
|
1764
1801
|
});
|
|
1765
1802
|
}
|
|
1766
|
-
/** Establish the hydration cutoff when ordered replay reaches its checkpoint. */
|
|
1767
|
-
#advanceInterruptReplayBarrierFromCheckpoint(event) {
|
|
1768
|
-
if (event.method !== "checkpoints" || this.#hydratedInterruptCheckpointId == null || !require_namespace.isRootNamespace(event.params.namespace)) return;
|
|
1769
|
-
if (event.params.data?.id !== this.#hydratedInterruptCheckpointId || typeof event.seq !== "number") return;
|
|
1770
|
-
this.#interruptReplayThroughSeq = event.seq;
|
|
1771
|
-
this.#hydratedInterruptCheckpointId = void 0;
|
|
1772
|
-
const pendingEvents = this.#pendingHydrationInterruptEvents.sort((a, b) => (a.seq ?? 0) - (b.seq ?? 0));
|
|
1773
|
-
this.#pendingHydrationInterruptEvents = [];
|
|
1774
|
-
for (const pendingEvent of pendingEvents) this.#recordInterrupt(pendingEvent);
|
|
1775
|
-
}
|
|
1776
1803
|
/**
|
|
1777
1804
|
* Convert the hydrate-time allowlist into a replay barrier after a command
|
|
1778
1805
|
* is accepted. Built-in transports update `lastAppliedThroughSeq` from the
|
|
@@ -1849,12 +1876,12 @@ var StreamController = class {
|
|
|
1849
1876
|
*/
|
|
1850
1877
|
async #reconcilePendingInterruptsFromServer() {
|
|
1851
1878
|
const threadId = this.#currentThreadId;
|
|
1852
|
-
if (threadId == null || this.#disposed) return;
|
|
1879
|
+
if (threadId == null || this.#disposed) return null;
|
|
1853
1880
|
const generationAtFetch = this.#submitGeneration;
|
|
1854
1881
|
try {
|
|
1855
1882
|
const state = await this.#fetchHydrationState();
|
|
1856
|
-
if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generationAtFetch) return;
|
|
1857
|
-
if (!Array.isArray(state?.tasks)) return;
|
|
1883
|
+
if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generationAtFetch) return null;
|
|
1884
|
+
if (!Array.isArray(state?.tasks)) return null;
|
|
1858
1885
|
const { activeInterrupts, activeIds } = collectActiveInterruptsFromTasks(state.tasks);
|
|
1859
1886
|
const pendingInterrupts = activeInterrupts.filter((interrupt) => interrupt.id == null || !this.#resolvedInterrupts.has(interrupt.id));
|
|
1860
1887
|
this.rootStore.setState((s) => ({
|
|
@@ -1863,7 +1890,55 @@ var StreamController = class {
|
|
|
1863
1890
|
interrupt: pendingInterrupts[0]
|
|
1864
1891
|
}));
|
|
1865
1892
|
this.#hydratedActiveInterruptIds = activeIds;
|
|
1866
|
-
|
|
1893
|
+
return state;
|
|
1894
|
+
} catch {
|
|
1895
|
+
return null;
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
#settleParkedInterruptsOnTerminal(event) {
|
|
1899
|
+
if (this.#pendingHydrationInterruptEvents.length === 0) return;
|
|
1900
|
+
if (event.method !== "lifecycle") return;
|
|
1901
|
+
if (!require_namespace.isRootNamespace(event.params.namespace)) return;
|
|
1902
|
+
const status = event.params.data?.event;
|
|
1903
|
+
if (status !== "interrupted" && status !== "completed" && status !== "failed") return;
|
|
1904
|
+
this.#settleParkedInterrupts();
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Decide parked interrupts with server state instead of a stream marker.
|
|
1908
|
+
*
|
|
1909
|
+
* After a passive rejoin the stream cannot tell a replayed, already
|
|
1910
|
+
* resolved `input.requested` from one the current run just raised: the
|
|
1911
|
+
* SSE replays the thread buffer on connect with no marker for where the
|
|
1912
|
+
* replay ends. `state.tasks[].interrupts` is authoritative: parked ids it
|
|
1913
|
+
* lists are live, the rest are history.
|
|
1914
|
+
*/
|
|
1915
|
+
async #settleParkedInterrupts() {
|
|
1916
|
+
const makePromise = async () => {
|
|
1917
|
+
try {
|
|
1918
|
+
const threadId = this.#currentThreadId;
|
|
1919
|
+
const generation = this.#submitGeneration;
|
|
1920
|
+
const deadline = Date.now() + PARKED_INTERRUPT_SETTLE_MS;
|
|
1921
|
+
for (;;) {
|
|
1922
|
+
if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generation || this.#pendingHydrationInterruptEvents.length === 0) return;
|
|
1923
|
+
const parkedIds = new Set(this.#pendingHydrationInterruptEvents.map((event) => event.params.data.interrupt_id));
|
|
1924
|
+
const state = await this.#reconcilePendingInterruptsFromServer();
|
|
1925
|
+
if (state != null) {
|
|
1926
|
+
if ([...this.#hydratedActiveInterruptIds ?? []].some((id) => parkedIds.has(id)) || !isThreadStateActive(state)) {
|
|
1927
|
+
this.#pendingHydrationInterruptEvents = [];
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
if (Date.now() >= deadline) return;
|
|
1932
|
+
await new Promise((resolve) => {
|
|
1933
|
+
setTimeout(resolve, PARKED_INTERRUPT_SETTLE_POLL_MS);
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
} finally {
|
|
1937
|
+
this.#settleParkedInterruptsPromise = void 0;
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
this.#settleParkedInterruptsPromise ??= makePromise();
|
|
1941
|
+
return this.#settleParkedInterruptsPromise;
|
|
1867
1942
|
}
|
|
1868
1943
|
/**
|
|
1869
1944
|
* Resolve on the next root-namespace terminal lifecycle event
|
|
@@ -1909,6 +1984,7 @@ var StreamController = class {
|
|
|
1909
1984
|
settled = true;
|
|
1910
1985
|
unsubscribeRoot?.();
|
|
1911
1986
|
unsubscribeThread?.();
|
|
1987
|
+
unsubscribeError?.();
|
|
1912
1988
|
signal.removeEventListener("abort", finishAborted);
|
|
1913
1989
|
resolve(result);
|
|
1914
1990
|
}
|
|
@@ -1934,6 +2010,10 @@ var StreamController = class {
|
|
|
1934
2010
|
};
|
|
1935
2011
|
const unsubscribeRoot = this.#rootBus.subscribe(onEvent);
|
|
1936
2012
|
const unsubscribeThread = this.#thread?.onEvent(onEvent);
|
|
2013
|
+
const unsubscribeError = this.#thread?.onError((error) => finish({
|
|
2014
|
+
event: "failed",
|
|
2015
|
+
error: error.message
|
|
2016
|
+
}));
|
|
1937
2017
|
if (signal.aborted) finishAborted();
|
|
1938
2018
|
else signal.addEventListener("abort", finishAborted, { once: true });
|
|
1939
2019
|
});
|