@langchain/langgraph-sdk 0.1.5 → 0.1.7

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/react/index.cjs +3 -1
  3. package/dist/react/index.d.ts +2 -1
  4. package/dist/react/index.js +1 -0
  5. package/dist/react/stream.cjs +12 -460
  6. package/dist/react/stream.custom.cjs +148 -0
  7. package/dist/react/stream.custom.d.ts +41 -0
  8. package/dist/react/stream.custom.js +142 -0
  9. package/dist/react/stream.d.ts +61 -1
  10. package/dist/react/stream.js +13 -460
  11. package/dist/react/stream.lgp.cjs +499 -0
  12. package/dist/react/stream.lgp.d.ts +7 -0
  13. package/dist/react/stream.lgp.js +495 -0
  14. package/dist/react/thread.cjs +19 -0
  15. package/dist/react/thread.d.ts +4 -0
  16. package/dist/react/thread.js +15 -0
  17. package/dist/react/types.d.ts +25 -1
  18. package/dist/ui/branching.test.cjs +370 -0
  19. package/dist/ui/branching.test.d.ts +1 -0
  20. package/dist/ui/branching.test.js +368 -0
  21. package/dist/{react → ui}/manager.cjs +8 -4
  22. package/dist/{react → ui}/manager.d.ts +1 -0
  23. package/dist/{react → ui}/manager.js +8 -4
  24. package/package.json +1 -1
  25. /package/dist/{react → ui}/branching.cjs +0 -0
  26. /package/dist/{react → ui}/branching.d.ts +0 -0
  27. /package/dist/{react → ui}/branching.js +0 -0
  28. /package/dist/{react → ui}/errors.cjs +0 -0
  29. /package/dist/{react → ui}/errors.d.ts +0 -0
  30. /package/dist/{react → ui}/errors.js +0 -0
  31. /package/dist/{react → ui}/messages.cjs +0 -0
  32. /package/dist/{react → ui}/messages.d.ts +0 -0
  33. /package/dist/{react → ui}/messages.js +0 -0
  34. /package/dist/{react → ui}/utils.cjs +0 -0
  35. /package/dist/{react → ui}/utils.d.ts +0 -0
  36. /package/dist/{react → ui}/utils.js +0 -0
@@ -0,0 +1,495 @@
1
+ /* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */
2
+ "use client";
3
+ import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore, } from "react";
4
+ import { findLast, unique } from "../ui/utils.js";
5
+ import { StreamError } from "../ui/errors.js";
6
+ import { getBranchContext } from "../ui/branching.js";
7
+ import { StreamManager } from "../ui/manager.js";
8
+ import { Client, getClientConfigHash } from "../client.js";
9
+ import { MessageTupleManager } from "../ui/messages.js";
10
+ import { useControllableThreadId } from "./thread.js";
11
+ function getFetchHistoryKey(client, threadId, limit) {
12
+ return [getClientConfigHash(client), threadId, limit].join(":");
13
+ }
14
+ function fetchHistory(client, threadId, options) {
15
+ if (options?.limit === false) {
16
+ return client.threads.getState(threadId).then((state) => {
17
+ if (state.checkpoint == null)
18
+ return [];
19
+ return [state];
20
+ });
21
+ }
22
+ const limit = typeof options?.limit === "number" ? options.limit : 10;
23
+ return client.threads.getHistory(threadId, { limit });
24
+ }
25
+ function useThreadHistory(client, threadId, limit, options) {
26
+ const key = getFetchHistoryKey(client, threadId, limit);
27
+ const [state, setState] = useState(() => ({
28
+ key: undefined,
29
+ data: undefined,
30
+ error: undefined,
31
+ isLoading: threadId != null,
32
+ }));
33
+ const clientRef = useRef(client);
34
+ clientRef.current = client;
35
+ const onErrorRef = useRef(options?.onError);
36
+ onErrorRef.current = options?.onError;
37
+ const fetcher = useCallback((threadId, limit) => {
38
+ const client = clientRef.current;
39
+ const key = getFetchHistoryKey(client, threadId, limit);
40
+ if (threadId != null) {
41
+ setState((state) => {
42
+ if (state.key === key)
43
+ return { ...state, isLoading: true };
44
+ return { key, data: undefined, error: undefined, isLoading: true };
45
+ });
46
+ return fetchHistory(client, threadId, { limit }).then((data) => {
47
+ setState((state) => {
48
+ if (state.key !== key)
49
+ return state;
50
+ return { key, data, error: undefined, isLoading: false };
51
+ });
52
+ return data;
53
+ }, (error) => {
54
+ setState((state) => {
55
+ if (state.key !== key)
56
+ return state;
57
+ return { key, data: state.data, error, isLoading: false };
58
+ });
59
+ onErrorRef.current?.(error);
60
+ return Promise.reject(error);
61
+ });
62
+ }
63
+ setState({ key, data: undefined, error: undefined, isLoading: false });
64
+ return Promise.resolve([]);
65
+ }, []);
66
+ useEffect(() => {
67
+ // Skip if a stream is already in progress, no need to fetch history
68
+ if (options.submittingRef.current != null &&
69
+ options.submittingRef.current === threadId) {
70
+ return;
71
+ }
72
+ void fetcher(threadId, limit);
73
+ // The `threadId` and `limit` arguments are already present in `key`
74
+ // Thus we don't need to include them in the dependency array
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps
76
+ }, [fetcher, key]);
77
+ return {
78
+ data: state.data,
79
+ error: state.error,
80
+ isLoading: state.isLoading,
81
+ mutate: (mutateId) => fetcher(mutateId ?? threadId, limit),
82
+ };
83
+ }
84
+ export function useStreamLGP(options) {
85
+ const reconnectOnMountRef = useRef(options.reconnectOnMount);
86
+ const runMetadataStorage = useMemo(() => {
87
+ if (typeof window === "undefined")
88
+ return null;
89
+ const storage = reconnectOnMountRef.current;
90
+ if (storage === true)
91
+ return window.sessionStorage;
92
+ if (typeof storage === "function")
93
+ return storage();
94
+ return null;
95
+ }, []);
96
+ const client = useMemo(() => options.client ??
97
+ new Client({
98
+ apiUrl: options.apiUrl,
99
+ apiKey: options.apiKey,
100
+ callerOptions: options.callerOptions,
101
+ defaultHeaders: options.defaultHeaders,
102
+ }), [
103
+ options.client,
104
+ options.apiKey,
105
+ options.apiUrl,
106
+ options.callerOptions,
107
+ options.defaultHeaders,
108
+ ]);
109
+ const [messageManager] = useState(() => new MessageTupleManager());
110
+ const [stream] = useState(() => new StreamManager(messageManager));
111
+ useSyncExternalStore(stream.subscribe, stream.getSnapshot, stream.getSnapshot);
112
+ const [threadId, onThreadId] = useControllableThreadId(options);
113
+ const trackStreamModeRef = useRef([]);
114
+ const trackStreamMode = useCallback((...mode) => {
115
+ const ref = trackStreamModeRef.current;
116
+ for (const m of mode) {
117
+ if (!ref.includes(m))
118
+ ref.push(m);
119
+ }
120
+ }, []);
121
+ const hasUpdateListener = options.onUpdateEvent != null;
122
+ const hasCustomListener = options.onCustomEvent != null;
123
+ const hasLangChainListener = options.onLangChainEvent != null;
124
+ const hasDebugListener = options.onDebugEvent != null;
125
+ const hasCheckpointListener = options.onCheckpointEvent != null;
126
+ const hasTaskListener = options.onTaskEvent != null;
127
+ const callbackStreamMode = useMemo(() => {
128
+ const modes = [];
129
+ if (hasUpdateListener)
130
+ modes.push("updates");
131
+ if (hasCustomListener)
132
+ modes.push("custom");
133
+ if (hasLangChainListener)
134
+ modes.push("events");
135
+ if (hasDebugListener)
136
+ modes.push("debug");
137
+ if (hasCheckpointListener)
138
+ modes.push("checkpoints");
139
+ if (hasTaskListener)
140
+ modes.push("tasks");
141
+ return modes;
142
+ }, [
143
+ hasUpdateListener,
144
+ hasCustomListener,
145
+ hasLangChainListener,
146
+ hasDebugListener,
147
+ hasCheckpointListener,
148
+ hasTaskListener,
149
+ ]);
150
+ const clearCallbackRef = useRef(null);
151
+ clearCallbackRef.current = stream.clear;
152
+ const threadIdRef = useRef(threadId);
153
+ const threadIdStreamingRef = useRef(null);
154
+ // Cancel the stream if thread ID has changed
155
+ useEffect(() => {
156
+ if (threadIdRef.current !== threadId) {
157
+ threadIdRef.current = threadId;
158
+ stream.clear();
159
+ }
160
+ }, [threadId, stream]);
161
+ const historyLimit = typeof options.fetchStateHistory === "object" &&
162
+ options.fetchStateHistory != null
163
+ ? options.fetchStateHistory.limit ?? false
164
+ : options.fetchStateHistory ?? false;
165
+ const history = useThreadHistory(client, threadId, historyLimit, {
166
+ submittingRef: threadIdStreamingRef,
167
+ onError: options.onError,
168
+ });
169
+ const getMessages = (value) => {
170
+ const messagesKey = options.messagesKey ?? "messages";
171
+ return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
172
+ };
173
+ const setMessages = (current, messages) => {
174
+ const messagesKey = options.messagesKey ?? "messages";
175
+ return { ...current, [messagesKey]: messages };
176
+ };
177
+ const [branch, setBranch] = useState("");
178
+ const branchContext = getBranchContext(branch, history.data);
179
+ const historyValues = branchContext.threadHead?.values ??
180
+ options.initialValues ??
181
+ {};
182
+ const historyError = (() => {
183
+ const error = branchContext.threadHead?.tasks?.at(-1)?.error;
184
+ if (error == null)
185
+ return undefined;
186
+ try {
187
+ const parsed = JSON.parse(error);
188
+ if (StreamError.isStructuredError(parsed))
189
+ return new StreamError(parsed);
190
+ return parsed;
191
+ }
192
+ catch {
193
+ // do nothing
194
+ }
195
+ return error;
196
+ })();
197
+ const messageMetadata = (() => {
198
+ const alreadyShown = new Set();
199
+ return getMessages(historyValues).map((message, idx) => {
200
+ const messageId = message.id ?? idx;
201
+ // Find the first checkpoint where the message was seen
202
+ const firstSeenState = findLast(history.data ?? [], (state) => getMessages(state.values)
203
+ .map((m, idx) => m.id ?? idx)
204
+ .includes(messageId));
205
+ const checkpointId = firstSeenState?.checkpoint?.checkpoint_id;
206
+ let branch = checkpointId != null
207
+ ? branchContext.branchByCheckpoint[checkpointId]
208
+ : undefined;
209
+ if (!branch?.branch?.length)
210
+ branch = undefined;
211
+ // serialize branches
212
+ const optionsShown = branch?.branchOptions?.flat(2).join(",");
213
+ if (optionsShown) {
214
+ if (alreadyShown.has(optionsShown))
215
+ branch = undefined;
216
+ alreadyShown.add(optionsShown);
217
+ }
218
+ return {
219
+ messageId: messageId.toString(),
220
+ firstSeenState,
221
+ branch: branch?.branch,
222
+ branchOptions: branch?.branchOptions,
223
+ };
224
+ });
225
+ })();
226
+ const stop = () => stream.stop(historyValues, {
227
+ onStop: (args) => {
228
+ if (runMetadataStorage && threadId) {
229
+ const runId = runMetadataStorage.getItem(`lg:stream:${threadId}`);
230
+ if (runId)
231
+ void client.runs.cancel(threadId, runId);
232
+ runMetadataStorage.removeItem(`lg:stream:${threadId}`);
233
+ }
234
+ options.onStop?.(args);
235
+ },
236
+ });
237
+ // --- TRANSPORT ---
238
+ const submit = async (values, submitOptions) => {
239
+ // Unbranch things
240
+ const checkpointId = submitOptions?.checkpoint?.checkpoint_id;
241
+ setBranch(checkpointId != null
242
+ ? branchContext.branchByCheckpoint[checkpointId]?.branch ?? ""
243
+ : "");
244
+ stream.setStreamValues(() => {
245
+ if (submitOptions?.optimisticValues != null) {
246
+ return {
247
+ ...historyValues,
248
+ ...(typeof submitOptions.optimisticValues === "function"
249
+ ? submitOptions.optimisticValues(historyValues)
250
+ : submitOptions.optimisticValues),
251
+ };
252
+ }
253
+ return { ...historyValues };
254
+ });
255
+ // When `fetchStateHistory` is requested, thus we assume that branching
256
+ // is enabled. We then need to include the implicit branch.
257
+ const includeImplicitBranch = historyLimit === true || typeof historyLimit === "number";
258
+ let callbackMeta;
259
+ let rejoinKey;
260
+ let usableThreadId = threadId;
261
+ await stream.start(async (signal) => {
262
+ if (!usableThreadId) {
263
+ const thread = await client.threads.create({
264
+ threadId: submitOptions?.threadId,
265
+ metadata: submitOptions?.metadata,
266
+ });
267
+ usableThreadId = thread.thread_id;
268
+ // Pre-emptively update the thread ID before
269
+ // stream cancellation is kicked off and thread
270
+ // is being refetched
271
+ threadIdRef.current = usableThreadId;
272
+ threadIdStreamingRef.current = usableThreadId;
273
+ onThreadId(usableThreadId);
274
+ }
275
+ if (!usableThreadId) {
276
+ throw new Error("Failed to obtain valid thread ID.");
277
+ }
278
+ threadIdStreamingRef.current = usableThreadId;
279
+ const streamMode = unique([
280
+ ...(submitOptions?.streamMode ?? []),
281
+ ...trackStreamModeRef.current,
282
+ ...callbackStreamMode,
283
+ ]);
284
+ let checkpoint = submitOptions?.checkpoint ??
285
+ (includeImplicitBranch
286
+ ? branchContext.threadHead?.checkpoint
287
+ : undefined) ??
288
+ undefined;
289
+ // Avoid specifying a checkpoint if user explicitly set it to null
290
+ if (submitOptions?.checkpoint === null)
291
+ checkpoint = undefined;
292
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
293
+ // @ts-expect-error
294
+ if (checkpoint != null)
295
+ delete checkpoint.thread_id;
296
+ const streamResumable = submitOptions?.streamResumable ?? !!runMetadataStorage;
297
+ return client.runs.stream(usableThreadId, options.assistantId, {
298
+ input: values,
299
+ config: submitOptions?.config,
300
+ context: submitOptions?.context,
301
+ command: submitOptions?.command,
302
+ interruptBefore: submitOptions?.interruptBefore,
303
+ interruptAfter: submitOptions?.interruptAfter,
304
+ metadata: submitOptions?.metadata,
305
+ multitaskStrategy: submitOptions?.multitaskStrategy,
306
+ onCompletion: submitOptions?.onCompletion,
307
+ onDisconnect: submitOptions?.onDisconnect ??
308
+ (streamResumable ? "continue" : "cancel"),
309
+ signal,
310
+ checkpoint,
311
+ streamMode,
312
+ streamSubgraphs: submitOptions?.streamSubgraphs,
313
+ streamResumable,
314
+ durability: submitOptions?.durability,
315
+ onRunCreated(params) {
316
+ callbackMeta = {
317
+ run_id: params.run_id,
318
+ thread_id: params.thread_id ?? usableThreadId,
319
+ };
320
+ if (runMetadataStorage) {
321
+ rejoinKey = `lg:stream:${usableThreadId}`;
322
+ runMetadataStorage.setItem(rejoinKey, callbackMeta.run_id);
323
+ }
324
+ options.onCreated?.(callbackMeta);
325
+ },
326
+ });
327
+ }, {
328
+ getMessages,
329
+ setMessages,
330
+ initialValues: historyValues,
331
+ callbacks: options,
332
+ async onSuccess() {
333
+ if (rejoinKey)
334
+ runMetadataStorage?.removeItem(rejoinKey);
335
+ const shouldRefetch =
336
+ // We're expecting the whole thread state in onFinish
337
+ options.onFinish != null ||
338
+ // We're fetching history, thus we need the latest checkpoint
339
+ // to ensure we're not accidentally submitting to a wrong branch
340
+ includeImplicitBranch;
341
+ if (shouldRefetch) {
342
+ const newHistory = await history.mutate(usableThreadId);
343
+ const lastHead = newHistory.at(0);
344
+ if (lastHead) {
345
+ // We now have the latest update from /history
346
+ // Thus we can clear the local stream state
347
+ options.onFinish?.(lastHead, callbackMeta);
348
+ return null;
349
+ }
350
+ }
351
+ return undefined;
352
+ },
353
+ onError(error) {
354
+ options.onError?.(error, callbackMeta);
355
+ },
356
+ onFinish() {
357
+ threadIdStreamingRef.current = null;
358
+ },
359
+ });
360
+ };
361
+ const joinStream = async (runId, lastEventId, joinOptions) => {
362
+ // eslint-disable-next-line no-param-reassign
363
+ lastEventId ??= "-1";
364
+ if (!threadId)
365
+ return;
366
+ const callbackMeta = {
367
+ thread_id: threadId,
368
+ run_id: runId,
369
+ };
370
+ await stream.start(async (signal) => {
371
+ threadIdStreamingRef.current = threadId;
372
+ return client.runs.joinStream(threadId, runId, {
373
+ signal,
374
+ lastEventId,
375
+ streamMode: joinOptions?.streamMode,
376
+ });
377
+ }, {
378
+ getMessages,
379
+ setMessages,
380
+ initialValues: historyValues,
381
+ callbacks: options,
382
+ async onSuccess() {
383
+ runMetadataStorage?.removeItem(`lg:stream:${threadId}`);
384
+ const newHistory = await history.mutate(threadId);
385
+ const lastHead = newHistory.at(0);
386
+ if (lastHead)
387
+ options.onFinish?.(lastHead, callbackMeta);
388
+ },
389
+ onError(error) {
390
+ options.onError?.(error, callbackMeta);
391
+ },
392
+ onFinish() {
393
+ threadIdStreamingRef.current = null;
394
+ },
395
+ });
396
+ };
397
+ const reconnectKey = useMemo(() => {
398
+ if (!runMetadataStorage || stream.isLoading)
399
+ return undefined;
400
+ if (typeof window === "undefined")
401
+ return undefined;
402
+ const runId = runMetadataStorage?.getItem(`lg:stream:${threadId}`);
403
+ if (!runId)
404
+ return undefined;
405
+ return { runId, threadId };
406
+ }, [runMetadataStorage, stream.isLoading, threadId]);
407
+ const shouldReconnect = !!runMetadataStorage;
408
+ const reconnectRef = useRef({ threadId, shouldReconnect });
409
+ const joinStreamRef = useRef(joinStream);
410
+ joinStreamRef.current = joinStream;
411
+ useEffect(() => {
412
+ // reset shouldReconnect when switching threads
413
+ if (reconnectRef.current.threadId !== threadId) {
414
+ reconnectRef.current = { threadId, shouldReconnect };
415
+ }
416
+ }, [threadId, shouldReconnect]);
417
+ useEffect(() => {
418
+ if (reconnectKey && reconnectRef.current.shouldReconnect) {
419
+ reconnectRef.current.shouldReconnect = false;
420
+ void joinStreamRef.current?.(reconnectKey.runId);
421
+ }
422
+ }, [reconnectKey]);
423
+ const error = stream.error ?? historyError ?? history.error;
424
+ const values = stream.values ?? historyValues;
425
+ return {
426
+ get values() {
427
+ trackStreamMode("values");
428
+ return values;
429
+ },
430
+ client,
431
+ assistantId: options.assistantId,
432
+ error,
433
+ isLoading: stream.isLoading,
434
+ stop,
435
+ submit,
436
+ joinStream,
437
+ branch,
438
+ setBranch,
439
+ get history() {
440
+ if (historyLimit === false) {
441
+ throw new Error("`fetchStateHistory` must be set to `true` to use `history`");
442
+ }
443
+ return branchContext.flatHistory;
444
+ },
445
+ isThreadLoading: history.isLoading && history.data == null,
446
+ get experimental_branchTree() {
447
+ if (historyLimit === false) {
448
+ throw new Error("`fetchStateHistory` must be set to `true` to use `experimental_branchTree`");
449
+ }
450
+ return branchContext.branchTree;
451
+ },
452
+ get interrupt() {
453
+ if (values != null &&
454
+ "__interrupt__" in values &&
455
+ Array.isArray(values.__interrupt__)) {
456
+ const valueInterrupts = values.__interrupt__;
457
+ if (valueInterrupts.length === 0)
458
+ return { when: "breakpoint" };
459
+ if (valueInterrupts.length === 1)
460
+ return valueInterrupts[0];
461
+ // TODO: fix the typing of interrupts if multiple interrupts are returned
462
+ return valueInterrupts;
463
+ }
464
+ // If we're deferring to old interrupt detection logic, don't show the interrupt if the stream is loading
465
+ if (stream.isLoading)
466
+ return undefined;
467
+ const interrupts = branchContext.threadHead?.tasks?.at(-1)?.interrupts;
468
+ if (interrupts == null || interrupts.length === 0) {
469
+ // check if there's a next task present
470
+ const next = branchContext.threadHead?.next ?? [];
471
+ if (!next.length || error != null)
472
+ return undefined;
473
+ return { when: "breakpoint" };
474
+ }
475
+ // Return only the current interrupt
476
+ return interrupts.at(-1);
477
+ },
478
+ get messages() {
479
+ trackStreamMode("messages-tuple", "values");
480
+ return getMessages(values);
481
+ },
482
+ getMessagesMetadata(message, index) {
483
+ trackStreamMode("values");
484
+ const streamMetadata = messageManager.get(message.id)?.metadata;
485
+ const historyMetadata = messageMetadata?.find((m) => m.messageId === (message.id ?? index));
486
+ if (streamMetadata != null || historyMetadata != null) {
487
+ return {
488
+ ...historyMetadata,
489
+ streamMetadata,
490
+ };
491
+ }
492
+ return undefined;
493
+ },
494
+ };
495
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ "use client";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useControllableThreadId = void 0;
5
+ const react_1 = require("react");
6
+ const useControllableThreadId = (options) => {
7
+ const [localThreadId, _setLocalThreadId] = (0, react_1.useState)(options?.threadId ?? null);
8
+ const onThreadIdRef = (0, react_1.useRef)(options?.onThreadId);
9
+ onThreadIdRef.current = options?.onThreadId;
10
+ const setThreadId = (0, react_1.useCallback)((threadId) => {
11
+ _setLocalThreadId(threadId);
12
+ onThreadIdRef.current?.(threadId);
13
+ }, []);
14
+ if (!options || !("threadId" in options)) {
15
+ return [localThreadId, setThreadId];
16
+ }
17
+ return [options.threadId ?? null, setThreadId];
18
+ };
19
+ exports.useControllableThreadId = useControllableThreadId;
@@ -0,0 +1,4 @@
1
+ export declare const useControllableThreadId: (options?: {
2
+ threadId?: string | null;
3
+ onThreadId?: (threadId: string) => void;
4
+ }) => [string | null, (threadId: string) => void];
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { useState, useRef, useCallback } from "react";
3
+ export const useControllableThreadId = (options) => {
4
+ const [localThreadId, _setLocalThreadId] = useState(options?.threadId ?? null);
5
+ const onThreadIdRef = useRef(options?.onThreadId);
6
+ onThreadIdRef.current = options?.onThreadId;
7
+ const setThreadId = useCallback((threadId) => {
8
+ _setLocalThreadId(threadId);
9
+ onThreadIdRef.current?.(threadId);
10
+ }, []);
11
+ if (!options || !("threadId" in options)) {
12
+ return [localThreadId, setThreadId];
13
+ }
14
+ return [options.threadId ?? null, setThreadId];
15
+ };
@@ -3,7 +3,7 @@ import type { ThreadState, Interrupt, Config, Checkpoint, Metadata } from "../sc
3
3
  import type { Command, MultitaskStrategy, OnCompletionBehavior, DisconnectMode, Durability } from "../types.js";
4
4
  import type { Message } from "../types.messages.js";
5
5
  import type { UpdatesStreamEvent, CustomStreamEvent, MetadataStreamEvent, EventsStreamEvent, DebugStreamEvent, CheckpointsStreamEvent, TasksStreamEvent, StreamMode } from "../types.stream.js";
6
- import type { Sequence } from "./branching.js";
6
+ import type { Sequence } from "../ui/branching.js";
7
7
  export type MessageMetadata<StateType extends Record<string, unknown>> = {
8
8
  /**
9
9
  * The ID of the message used.
@@ -313,4 +313,28 @@ export interface SubmitOptions<StateType extends Record<string, unknown> = Recor
313
313
  */
314
314
  threadId?: string;
315
315
  }
316
+ /**
317
+ * Transport used to stream the thread.
318
+ * Only applicable for custom endpoints using `toLangGraphEventStream` or `toLangGraphEventStreamResponse`.
319
+ */
320
+ export interface UseStreamTransport<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> {
321
+ stream: (payload: {
322
+ input: GetUpdateType<Bag, StateType> | null | undefined;
323
+ context: GetConfigurableType<Bag> | undefined;
324
+ command: Command | undefined;
325
+ config: ConfigWithConfigurable<GetConfigurableType<Bag>> | undefined;
326
+ signal: AbortSignal;
327
+ }) => Promise<AsyncGenerator<{
328
+ id?: string;
329
+ event: string;
330
+ data: unknown;
331
+ }>>;
332
+ }
333
+ export type UseStreamCustomOptions<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> = Pick<UseStreamOptions<StateType, Bag>, "messagesKey" | "threadId" | "onThreadId" | "onError" | "onCreated" | "onUpdateEvent" | "onCustomEvent" | "onMetadataEvent" | "onLangChainEvent" | "onDebugEvent" | "onCheckpointEvent" | "onTaskEvent" | "onStop" | "initialValues"> & {
334
+ transport: UseStreamTransport<StateType, Bag>;
335
+ };
336
+ export type UseStreamCustom<StateType extends Record<string, unknown> = Record<string, unknown>, Bag extends BagTemplate = BagTemplate> = Pick<UseStream<StateType, Bag>, "values" | "error" | "isLoading" | "stop" | "interrupt" | "messages"> & {
337
+ submit: (values: GetUpdateType<Bag, StateType> | null | undefined, options?: CustomSubmitOptions<StateType, GetConfigurableType<Bag>>) => Promise<void>;
338
+ };
339
+ export type CustomSubmitOptions<StateType extends Record<string, unknown> = Record<string, unknown>, ConfigurableType extends Record<string, unknown> = Record<string, unknown>> = Pick<SubmitOptions<StateType, ConfigurableType>, "optimisticValues" | "context" | "command" | "config">;
316
340
  export {};