@langchain/langgraph-sdk 0.0.103 → 0.0.105

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @langchain/langgraph-sdk
2
2
 
3
+ ## 0.0.105
4
+
5
+ ### Patch Changes
6
+
7
+ - 7054a6a: add context to assistantBase interface
8
+
9
+ ## 0.0.104
10
+
11
+ ### Patch Changes
12
+
13
+ - af9ec5a: feat(sdk): add `isThreadLoading` option to `useStream`, handle thread error fetching
14
+ - 8e1ec9e: feat(sdk): add Context API support for useStream
15
+ - f43e48c: fix(sdk): handle subgraph custom events in stream processing of useStream
16
+
3
17
  ## 0.0.103
4
18
 
5
19
  ### Patch Changes
@@ -198,25 +198,38 @@ function fetchHistory(client, threadId, options) {
198
198
  const limit = typeof options?.limit === "number" ? options.limit : 1000;
199
199
  return client.threads.getHistory(threadId, { limit });
200
200
  }
201
- function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingRef) {
202
- const [history, setHistory] = (0, react_1.useState)([]);
201
+ function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingRef, onErrorRef) {
202
+ const [history, setHistory] = (0, react_1.useState)(undefined);
203
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
204
+ const [error, setError] = (0, react_1.useState)(undefined);
203
205
  const clientHash = (0, client_js_1.getClientConfigHash)(client);
204
206
  const clientRef = (0, react_1.useRef)(client);
205
207
  clientRef.current = client;
206
208
  const fetcher = (0, react_1.useCallback)((threadId) => {
207
209
  if (threadId != null) {
208
210
  const client = clientRef.current;
211
+ setIsLoading(true);
209
212
  return fetchHistory(client, threadId, {
210
213
  limit,
211
- }).then((history) => {
214
+ })
215
+ .then((history) => {
212
216
  setHistory(history);
213
217
  return history;
218
+ }, (error) => {
219
+ setError(error);
220
+ onErrorRef.current?.(error);
221
+ return Promise.reject(error);
222
+ })
223
+ .finally(() => {
224
+ setIsLoading(false);
214
225
  });
215
226
  }
216
- setHistory([]);
227
+ setHistory(undefined);
228
+ setError(undefined);
229
+ setIsLoading(false);
217
230
  clearCallbackRef.current?.();
218
231
  return Promise.resolve([]);
219
- }, [clearCallbackRef, limit]);
232
+ }, [clearCallbackRef, onErrorRef, limit]);
220
233
  (0, react_1.useEffect)(() => {
221
234
  if (submittingRef.current)
222
235
  return;
@@ -224,6 +237,8 @@ function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingR
224
237
  }, [fetcher, clientHash, limit, submittingRef, threadId]);
225
238
  return {
226
239
  data: history,
240
+ isLoading,
241
+ error,
227
242
  mutate: (mutateId) => fetcher(mutateId ?? threadId),
228
243
  };
229
244
  }
@@ -346,20 +361,22 @@ function useStream(options) {
346
361
  setStreamValues(null);
347
362
  messageManagerRef.current.clear();
348
363
  };
364
+ const onErrorRef = (0, react_1.useRef)(undefined);
365
+ onErrorRef.current = options.onError;
349
366
  const historyLimit = typeof fetchStateHistory === "object" && fetchStateHistory != null
350
367
  ? fetchStateHistory.limit ?? true
351
368
  : fetchStateHistory ?? true;
352
- const history = useThreadHistory(threadId, client, historyLimit, clearCallbackRef, submittingRef);
369
+ const history = useThreadHistory(threadId, client, historyLimit, clearCallbackRef, submittingRef, onErrorRef);
353
370
  const getMessages = (0, react_1.useMemo)(() => {
354
371
  return (value) => Array.isArray(value[messagesKey])
355
372
  ? value[messagesKey]
356
373
  : [];
357
374
  }, [messagesKey]);
358
- const { rootSequence, paths } = getBranchSequence(history.data);
375
+ const { rootSequence, paths } = getBranchSequence(history.data ?? []);
359
376
  const { history: flatHistory, branchByCheckpoint } = getBranchView(rootSequence, paths, branch);
360
377
  const threadHead = flatHistory.at(-1);
361
378
  const historyValues = threadHead?.values ?? options.initialValues ?? {};
362
- const historyError = (() => {
379
+ const historyValueError = (() => {
363
380
  const error = threadHead?.tasks?.at(-1)?.error;
364
381
  if (error == null)
365
382
  return undefined;
@@ -379,10 +396,10 @@ function useStream(options) {
379
396
  const alreadyShown = new Set();
380
397
  return getMessages(historyValues).map((message, idx) => {
381
398
  const messageId = message.id ?? idx;
382
- const firstSeenIdx = findLastIndex(history.data, (state) => getMessages(state.values)
399
+ const firstSeenIdx = findLastIndex(history.data ?? [], (state) => getMessages(state.values)
383
400
  .map((m, idx) => m.id ?? idx)
384
401
  .includes(messageId));
385
- const firstSeen = history.data[firstSeenIdx];
402
+ const firstSeen = history.data?.[firstSeenIdx];
386
403
  const checkpointId = firstSeen?.checkpoint?.checkpoint_id;
387
404
  let branch = firstSeen && checkpointId != null
388
405
  ? branchByCheckpoint[checkpointId]
@@ -433,7 +450,10 @@ function useStream(options) {
433
450
  }
434
451
  if (event === "updates")
435
452
  options.onUpdateEvent?.(data);
436
- if (event === "custom")
453
+ if (event === "custom" ||
454
+ // if `streamSubgraphs: true`, then we also want
455
+ // to also receive custom events from subgraphs
456
+ event.startsWith("custom|"))
437
457
  options.onCustomEvent?.(data, {
438
458
  mutate: getMutateFn("stream", historyValues),
439
459
  });
@@ -553,6 +573,8 @@ function useStream(options) {
553
573
  onThreadId(thread.thread_id);
554
574
  usableThreadId = thread.thread_id;
555
575
  }
576
+ if (!usableThreadId)
577
+ throw new Error("Failed to obtain valid thread ID.");
556
578
  const streamMode = unique([
557
579
  ...(submitOptions?.streamMode ?? []),
558
580
  ...trackStreamModeRef.current,
@@ -569,6 +591,7 @@ function useStream(options) {
569
591
  const stream = client.runs.stream(usableThreadId, assistantId, {
570
592
  input: values,
571
593
  config: submitOptions?.config,
594
+ context: submitOptions?.context,
572
595
  command: submitOptions?.command,
573
596
  interruptBefore: submitOptions?.interruptBefore,
574
597
  interruptAfter: submitOptions?.interruptAfter,
@@ -631,7 +654,7 @@ function useStream(options) {
631
654
  void joinStreamRef.current?.(reconnectKey.runId);
632
655
  }
633
656
  }, [reconnectKey]);
634
- const error = streamError ?? historyError;
657
+ const error = streamError ?? historyValueError ?? history.error;
635
658
  const values = streamValues ?? historyValues;
636
659
  return {
637
660
  get values() {
@@ -648,6 +671,7 @@ function useStream(options) {
648
671
  branch,
649
672
  setBranch,
650
673
  history: flatHistory,
674
+ isThreadLoading: history.isLoading && history.data == null,
651
675
  get experimental_branchTree() {
652
676
  if (historyLimit === false) {
653
677
  throw new Error("`experimental_branchTree` is not available when `fetchStateHistory` is set to `false`");
@@ -203,6 +203,10 @@ export interface UseStream<StateType extends Record<string, unknown> = Record<st
203
203
  * Whether the stream is currently running.
204
204
  */
205
205
  isLoading: boolean;
206
+ /**
207
+ * Whether the thread is currently being loaded.
208
+ */
209
+ isThreadLoading: boolean;
206
210
  /**
207
211
  * Stops the stream.
208
212
  */
@@ -264,8 +268,9 @@ export interface UseStream<StateType extends Record<string, unknown> = Record<st
264
268
  type ConfigWithConfigurable<ConfigurableType extends Record<string, unknown>> = Config & {
265
269
  configurable?: ConfigurableType;
266
270
  };
267
- interface SubmitOptions<StateType extends Record<string, unknown> = Record<string, unknown>, ConfigurableType extends Record<string, unknown> = Record<string, unknown>> {
268
- config?: ConfigWithConfigurable<ConfigurableType>;
271
+ interface SubmitOptions<StateType extends Record<string, unknown> = Record<string, unknown>, ContextType extends Record<string, unknown> = Record<string, unknown>> {
272
+ config?: ConfigWithConfigurable<ContextType>;
273
+ context?: ContextType;
269
274
  checkpoint?: Omit<Checkpoint, "thread_id"> | null;
270
275
  command?: Command;
271
276
  interruptBefore?: "*" | string[];
@@ -194,25 +194,38 @@ function fetchHistory(client, threadId, options) {
194
194
  const limit = typeof options?.limit === "number" ? options.limit : 1000;
195
195
  return client.threads.getHistory(threadId, { limit });
196
196
  }
197
- function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingRef) {
198
- const [history, setHistory] = useState([]);
197
+ function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingRef, onErrorRef) {
198
+ const [history, setHistory] = useState(undefined);
199
+ const [isLoading, setIsLoading] = useState(false);
200
+ const [error, setError] = useState(undefined);
199
201
  const clientHash = getClientConfigHash(client);
200
202
  const clientRef = useRef(client);
201
203
  clientRef.current = client;
202
204
  const fetcher = useCallback((threadId) => {
203
205
  if (threadId != null) {
204
206
  const client = clientRef.current;
207
+ setIsLoading(true);
205
208
  return fetchHistory(client, threadId, {
206
209
  limit,
207
- }).then((history) => {
210
+ })
211
+ .then((history) => {
208
212
  setHistory(history);
209
213
  return history;
214
+ }, (error) => {
215
+ setError(error);
216
+ onErrorRef.current?.(error);
217
+ return Promise.reject(error);
218
+ })
219
+ .finally(() => {
220
+ setIsLoading(false);
210
221
  });
211
222
  }
212
- setHistory([]);
223
+ setHistory(undefined);
224
+ setError(undefined);
225
+ setIsLoading(false);
213
226
  clearCallbackRef.current?.();
214
227
  return Promise.resolve([]);
215
- }, [clearCallbackRef, limit]);
228
+ }, [clearCallbackRef, onErrorRef, limit]);
216
229
  useEffect(() => {
217
230
  if (submittingRef.current)
218
231
  return;
@@ -220,6 +233,8 @@ function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingR
220
233
  }, [fetcher, clientHash, limit, submittingRef, threadId]);
221
234
  return {
222
235
  data: history,
236
+ isLoading,
237
+ error,
223
238
  mutate: (mutateId) => fetcher(mutateId ?? threadId),
224
239
  };
225
240
  }
@@ -342,20 +357,22 @@ export function useStream(options) {
342
357
  setStreamValues(null);
343
358
  messageManagerRef.current.clear();
344
359
  };
360
+ const onErrorRef = useRef(undefined);
361
+ onErrorRef.current = options.onError;
345
362
  const historyLimit = typeof fetchStateHistory === "object" && fetchStateHistory != null
346
363
  ? fetchStateHistory.limit ?? true
347
364
  : fetchStateHistory ?? true;
348
- const history = useThreadHistory(threadId, client, historyLimit, clearCallbackRef, submittingRef);
365
+ const history = useThreadHistory(threadId, client, historyLimit, clearCallbackRef, submittingRef, onErrorRef);
349
366
  const getMessages = useMemo(() => {
350
367
  return (value) => Array.isArray(value[messagesKey])
351
368
  ? value[messagesKey]
352
369
  : [];
353
370
  }, [messagesKey]);
354
- const { rootSequence, paths } = getBranchSequence(history.data);
371
+ const { rootSequence, paths } = getBranchSequence(history.data ?? []);
355
372
  const { history: flatHistory, branchByCheckpoint } = getBranchView(rootSequence, paths, branch);
356
373
  const threadHead = flatHistory.at(-1);
357
374
  const historyValues = threadHead?.values ?? options.initialValues ?? {};
358
- const historyError = (() => {
375
+ const historyValueError = (() => {
359
376
  const error = threadHead?.tasks?.at(-1)?.error;
360
377
  if (error == null)
361
378
  return undefined;
@@ -375,10 +392,10 @@ export function useStream(options) {
375
392
  const alreadyShown = new Set();
376
393
  return getMessages(historyValues).map((message, idx) => {
377
394
  const messageId = message.id ?? idx;
378
- const firstSeenIdx = findLastIndex(history.data, (state) => getMessages(state.values)
395
+ const firstSeenIdx = findLastIndex(history.data ?? [], (state) => getMessages(state.values)
379
396
  .map((m, idx) => m.id ?? idx)
380
397
  .includes(messageId));
381
- const firstSeen = history.data[firstSeenIdx];
398
+ const firstSeen = history.data?.[firstSeenIdx];
382
399
  const checkpointId = firstSeen?.checkpoint?.checkpoint_id;
383
400
  let branch = firstSeen && checkpointId != null
384
401
  ? branchByCheckpoint[checkpointId]
@@ -429,7 +446,10 @@ export function useStream(options) {
429
446
  }
430
447
  if (event === "updates")
431
448
  options.onUpdateEvent?.(data);
432
- if (event === "custom")
449
+ if (event === "custom" ||
450
+ // if `streamSubgraphs: true`, then we also want
451
+ // to also receive custom events from subgraphs
452
+ event.startsWith("custom|"))
433
453
  options.onCustomEvent?.(data, {
434
454
  mutate: getMutateFn("stream", historyValues),
435
455
  });
@@ -549,6 +569,8 @@ export function useStream(options) {
549
569
  onThreadId(thread.thread_id);
550
570
  usableThreadId = thread.thread_id;
551
571
  }
572
+ if (!usableThreadId)
573
+ throw new Error("Failed to obtain valid thread ID.");
552
574
  const streamMode = unique([
553
575
  ...(submitOptions?.streamMode ?? []),
554
576
  ...trackStreamModeRef.current,
@@ -565,6 +587,7 @@ export function useStream(options) {
565
587
  const stream = client.runs.stream(usableThreadId, assistantId, {
566
588
  input: values,
567
589
  config: submitOptions?.config,
590
+ context: submitOptions?.context,
568
591
  command: submitOptions?.command,
569
592
  interruptBefore: submitOptions?.interruptBefore,
570
593
  interruptAfter: submitOptions?.interruptAfter,
@@ -627,7 +650,7 @@ export function useStream(options) {
627
650
  void joinStreamRef.current?.(reconnectKey.runId);
628
651
  }
629
652
  }, [reconnectKey]);
630
- const error = streamError ?? historyError;
653
+ const error = streamError ?? historyValueError ?? history.error;
631
654
  const values = streamValues ?? historyValues;
632
655
  return {
633
656
  get values() {
@@ -644,6 +667,7 @@ export function useStream(options) {
644
667
  branch,
645
668
  setBranch,
646
669
  history: flatHistory,
670
+ isThreadLoading: history.isLoading && history.data == null,
647
671
  get experimental_branchTree() {
648
672
  if (historyLimit === false) {
649
673
  throw new Error("`experimental_branchTree` is not available when `fetchStateHistory` is set to `false`");
package/dist/schema.d.ts CHANGED
@@ -76,6 +76,8 @@ export interface AssistantBase {
76
76
  graph_id: string;
77
77
  /** The assistant config. */
78
78
  config: Config;
79
+ /** The assistant context. */
80
+ context: unknown;
79
81
  /** The time the assistant was created. */
80
82
  created_at: string;
81
83
  /** The assistant metadata. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "0.0.103",
3
+ "version": "0.0.105",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "scripts": {