@langchain/langgraph-sdk 0.0.102 → 0.0.104

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.104
4
+
5
+ ### Patch Changes
6
+
7
+ - af9ec5a: feat(sdk): add `isThreadLoading` option to `useStream`, handle thread error fetching
8
+ - 8e1ec9e: feat(sdk): add Context API support for useStream
9
+ - f43e48c: fix(sdk): handle subgraph custom events in stream processing of useStream
10
+
11
+ ## 0.0.103
12
+
13
+ ### Patch Changes
14
+
15
+ - f1bcec7: Add support for context API
16
+
3
17
  ## 0.0.102
4
18
 
5
19
  ### Patch Changes
@@ -16,6 +16,7 @@ interface AssistantCreate {
16
16
  assistant_id?: Maybe<string>;
17
17
  metadata?: Maybe<Record<string, unknown>>;
18
18
  config?: Maybe<AssistantConfig>;
19
+ context?: Maybe<unknown>;
19
20
  if_exists?: Maybe<"raise" | "do_nothing">;
20
21
  name?: Maybe<string>;
21
22
  graph_id: string;
@@ -34,6 +35,7 @@ interface AssistantUpdate {
34
35
  assistant_id: string;
35
36
  metadata?: Maybe<Record<string, unknown>>;
36
37
  config?: Maybe<AssistantConfig>;
38
+ context?: Maybe<unknown>;
37
39
  graph_id?: Maybe<string>;
38
40
  name?: Maybe<string>;
39
41
  version?: Maybe<number>;
package/dist/client.cjs CHANGED
@@ -235,6 +235,7 @@ class CronsClient extends BaseClient {
235
235
  schedule: payload?.schedule,
236
236
  input: payload?.input,
237
237
  config: payload?.config,
238
+ context: payload?.context,
238
239
  metadata: payload?.metadata,
239
240
  assistant_id: assistantId,
240
241
  interrupt_before: payload?.interruptBefore,
@@ -260,6 +261,7 @@ class CronsClient extends BaseClient {
260
261
  schedule: payload?.schedule,
261
262
  input: payload?.input,
262
263
  config: payload?.config,
264
+ context: payload?.context,
263
265
  metadata: payload?.metadata,
264
266
  assistant_id: assistantId,
265
267
  interrupt_before: payload?.interruptBefore,
@@ -358,6 +360,7 @@ class AssistantsClient extends BaseClient {
358
360
  json: {
359
361
  graph_id: payload.graphId,
360
362
  config: payload.config,
363
+ context: payload.context,
361
364
  metadata: payload.metadata,
362
365
  assistant_id: payload.assistantId,
363
366
  if_exists: payload.ifExists,
@@ -378,6 +381,7 @@ class AssistantsClient extends BaseClient {
378
381
  json: {
379
382
  graph_id: payload.graphId,
380
383
  config: payload.config,
384
+ context: payload.context,
381
385
  metadata: payload.metadata,
382
386
  name: payload.name,
383
387
  description: payload.description,
@@ -624,6 +628,7 @@ class RunsClient extends BaseClient {
624
628
  input: payload?.input,
625
629
  command: payload?.command,
626
630
  config: payload?.config,
631
+ context: payload?.context,
627
632
  metadata: payload?.metadata,
628
633
  stream_mode: payload?.streamMode,
629
634
  stream_subgraphs: payload?.streamSubgraphs,
@@ -671,6 +676,7 @@ class RunsClient extends BaseClient {
671
676
  input: payload?.input,
672
677
  command: payload?.command,
673
678
  config: payload?.config,
679
+ context: payload?.context,
674
680
  metadata: payload?.metadata,
675
681
  stream_mode: payload?.streamMode,
676
682
  stream_subgraphs: payload?.streamSubgraphs,
@@ -733,6 +739,7 @@ class RunsClient extends BaseClient {
733
739
  input: payload?.input,
734
740
  command: payload?.command,
735
741
  config: payload?.config,
742
+ context: payload?.context,
736
743
  metadata: payload?.metadata,
737
744
  assistant_id: assistantId,
738
745
  interrupt_before: payload?.interruptBefore,
package/dist/client.d.ts CHANGED
@@ -129,6 +129,7 @@ export declare class AssistantsClient extends BaseClient {
129
129
  create(payload: {
130
130
  graphId: string;
131
131
  config?: Config;
132
+ context?: unknown;
132
133
  metadata?: Metadata;
133
134
  assistantId?: string;
134
135
  ifExists?: OnConflictBehavior;
@@ -144,6 +145,7 @@ export declare class AssistantsClient extends BaseClient {
144
145
  update(assistantId: string, payload: {
145
146
  graphId?: string;
146
147
  config?: Config;
148
+ context?: unknown;
147
149
  metadata?: Metadata;
148
150
  name?: string;
149
151
  description?: string;
package/dist/client.js CHANGED
@@ -230,6 +230,7 @@ export class CronsClient extends BaseClient {
230
230
  schedule: payload?.schedule,
231
231
  input: payload?.input,
232
232
  config: payload?.config,
233
+ context: payload?.context,
233
234
  metadata: payload?.metadata,
234
235
  assistant_id: assistantId,
235
236
  interrupt_before: payload?.interruptBefore,
@@ -255,6 +256,7 @@ export class CronsClient extends BaseClient {
255
256
  schedule: payload?.schedule,
256
257
  input: payload?.input,
257
258
  config: payload?.config,
259
+ context: payload?.context,
258
260
  metadata: payload?.metadata,
259
261
  assistant_id: assistantId,
260
262
  interrupt_before: payload?.interruptBefore,
@@ -352,6 +354,7 @@ export class AssistantsClient extends BaseClient {
352
354
  json: {
353
355
  graph_id: payload.graphId,
354
356
  config: payload.config,
357
+ context: payload.context,
355
358
  metadata: payload.metadata,
356
359
  assistant_id: payload.assistantId,
357
360
  if_exists: payload.ifExists,
@@ -372,6 +375,7 @@ export class AssistantsClient extends BaseClient {
372
375
  json: {
373
376
  graph_id: payload.graphId,
374
377
  config: payload.config,
378
+ context: payload.context,
375
379
  metadata: payload.metadata,
376
380
  name: payload.name,
377
381
  description: payload.description,
@@ -616,6 +620,7 @@ export class RunsClient extends BaseClient {
616
620
  input: payload?.input,
617
621
  command: payload?.command,
618
622
  config: payload?.config,
623
+ context: payload?.context,
619
624
  metadata: payload?.metadata,
620
625
  stream_mode: payload?.streamMode,
621
626
  stream_subgraphs: payload?.streamSubgraphs,
@@ -663,6 +668,7 @@ export class RunsClient extends BaseClient {
663
668
  input: payload?.input,
664
669
  command: payload?.command,
665
670
  config: payload?.config,
671
+ context: payload?.context,
666
672
  metadata: payload?.metadata,
667
673
  stream_mode: payload?.streamMode,
668
674
  stream_subgraphs: payload?.streamSubgraphs,
@@ -725,6 +731,7 @@ export class RunsClient extends BaseClient {
725
731
  input: payload?.input,
726
732
  command: payload?.command,
727
733
  config: payload?.config,
734
+ context: payload?.context,
728
735
  metadata: payload?.metadata,
729
736
  assistant_id: assistantId,
730
737
  interrupt_before: payload?.interruptBefore,
@@ -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
@@ -55,6 +55,11 @@ export interface GraphSchema {
55
55
  * Missing if unable to generate JSON schema from graph.
56
56
  */
57
57
  config_schema?: JSONSchema7 | null | undefined;
58
+ /**
59
+ * The schema for the graph context.
60
+ * Missing if unable to generate JSON schema from graph.
61
+ */
62
+ context_schema?: JSONSchema7 | null | undefined;
58
63
  }
59
64
  export type Subgraphs = Record<string, GraphSchema>;
60
65
  export type Metadata = Optional<{
package/dist/types.d.ts CHANGED
@@ -39,6 +39,11 @@ export interface RunsInvokePayload {
39
39
  * Additional configuration for the run.
40
40
  */
41
41
  config?: Config;
42
+ /**
43
+ * Static context to add to the assistant.
44
+ * @remarks Added in LangGraph.js 0.4
45
+ */
46
+ context?: unknown;
42
47
  /**
43
48
  * Checkpoint ID for when creating a new run.
44
49
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "0.0.102",
3
+ "version": "0.0.104",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "scripts": {