@langchain/langgraph-sdk 0.0.74 → 0.0.75

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.cjs CHANGED
@@ -32,6 +32,19 @@ function getApiKey(apiKey) {
32
32
  return undefined;
33
33
  }
34
34
  exports.getApiKey = getApiKey;
35
+ const REGEX_RUN_METADATA = /(\/threads\/(?<thread_id>.+))?\/runs\/(?<run_id>.+)/;
36
+ function getRunMetadataFromResponse(response) {
37
+ const contentLocation = response.headers.get("Content-Location");
38
+ if (!contentLocation)
39
+ return undefined;
40
+ const match = REGEX_RUN_METADATA.exec(contentLocation);
41
+ if (!match?.groups?.run_id)
42
+ return undefined;
43
+ return {
44
+ run_id: match.groups.run_id,
45
+ thread_id: match.groups.thread_id || undefined,
46
+ };
47
+ }
35
48
  class BaseClient {
36
49
  constructor(config) {
37
50
  Object.defineProperty(this, "asyncCaller", {
@@ -100,6 +113,9 @@ class BaseClient {
100
113
  };
101
114
  delete mutatedOptions.json;
102
115
  }
116
+ if (mutatedOptions.withResponse) {
117
+ delete mutatedOptions.withResponse;
118
+ }
103
119
  let timeoutSignal = null;
104
120
  if (typeof options?.timeoutMs !== "undefined") {
105
121
  if (options.timeoutMs != null) {
@@ -126,10 +142,16 @@ class BaseClient {
126
142
  }
127
143
  async fetch(path, options) {
128
144
  const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(path, options));
129
- if (response.status === 202 || response.status === 204) {
130
- return undefined;
145
+ const body = (() => {
146
+ if (response.status === 202 || response.status === 204) {
147
+ return undefined;
148
+ }
149
+ return response.json();
150
+ })();
151
+ if (options?.withResponse) {
152
+ return [await body, response];
131
153
  }
132
- return response.json();
154
+ return body;
133
155
  }
134
156
  }
135
157
  class CronsClient extends BaseClient {
@@ -556,6 +578,9 @@ class RunsClient extends BaseClient {
556
578
  timeoutMs: null,
557
579
  signal: payload?.signal,
558
580
  }));
581
+ const runMetadata = getRunMetadataFromResponse(response);
582
+ if (runMetadata)
583
+ payload?.onRunCreated?.(runMetadata);
559
584
  const stream = (response.body || new ReadableStream({ start: (ctrl) => ctrl.close() }))
560
585
  .pipeThrough(new sse_js_1.BytesLineDecoder())
561
586
  .pipeThrough(new sse_js_1.SSEDecoder());
@@ -588,11 +613,16 @@ class RunsClient extends BaseClient {
588
613
  if_not_exists: payload?.ifNotExists,
589
614
  checkpoint_during: payload?.checkpointDuring,
590
615
  };
591
- return this.fetch(`/threads/${threadId}/runs`, {
616
+ const [run, response] = await this.fetch(`/threads/${threadId}/runs`, {
592
617
  method: "POST",
593
618
  json,
594
619
  signal: payload?.signal,
620
+ withResponse: true,
595
621
  });
622
+ const runMetadata = getRunMetadataFromResponse(response);
623
+ if (runMetadata)
624
+ payload?.onRunCreated?.(runMetadata);
625
+ return run;
596
626
  }
597
627
  /**
598
628
  * Create a batch of stateless background runs.
@@ -639,22 +669,26 @@ class RunsClient extends BaseClient {
639
669
  checkpoint_during: payload?.checkpointDuring,
640
670
  };
641
671
  const endpoint = threadId == null ? `/runs/wait` : `/threads/${threadId}/runs/wait`;
642
- const response = await this.fetch(endpoint, {
672
+ const [run, response] = await this.fetch(endpoint, {
643
673
  method: "POST",
644
674
  json,
645
675
  timeoutMs: null,
646
676
  signal: payload?.signal,
677
+ withResponse: true,
647
678
  });
679
+ const runMetadata = getRunMetadataFromResponse(response);
680
+ if (runMetadata)
681
+ payload?.onRunCreated?.(runMetadata);
648
682
  const raiseError = payload?.raiseError !== undefined ? payload.raiseError : true;
649
683
  if (raiseError &&
650
- "__error__" in response &&
651
- typeof response.__error__ === "object" &&
652
- response.__error__ &&
653
- "error" in response.__error__ &&
654
- "message" in response.__error__) {
655
- throw new Error(`${response.__error__?.error}: ${response.__error__?.message}`);
684
+ "__error__" in run &&
685
+ typeof run.__error__ === "object" &&
686
+ run.__error__ &&
687
+ "error" in run.__error__ &&
688
+ "message" in run.__error__) {
689
+ throw new Error(`${run.__error__?.error}: ${run.__error__?.message}`);
656
690
  }
657
- return response;
691
+ return run;
658
692
  }
659
693
  /**
660
694
  * List all runs for a thread.
@@ -715,13 +749,12 @@ class RunsClient extends BaseClient {
715
749
  }
716
750
  /**
717
751
  * Stream output from a run in real-time, until the run is done.
718
- * Output is not buffered, so any output produced before this call will
719
- * not be received here.
720
752
  *
721
- * @param threadId The ID of the thread.
753
+ * @param threadId The ID of the thread. Can be set to `null` | `undefined` for stateless runs.
722
754
  * @param runId The ID of the run.
723
755
  * @param options Additional options for controlling the stream behavior:
724
756
  * - signal: An AbortSignal that can be used to cancel the stream request
757
+ * - lastEventId: The ID of the last event received. Can be used to reconnect to a stream without losing events.
725
758
  * - cancelOnDisconnect: When true, automatically cancels the run if the client disconnects from the stream
726
759
  * - streamMode: Controls what types of events to receive from the stream (can be a single mode or array of modes)
727
760
  * Must be a subset of the stream modes passed when creating the run. Background runs default to having the union of all
@@ -734,10 +767,15 @@ class RunsClient extends BaseClient {
734
767
  options instanceof AbortSignal
735
768
  ? { signal: options }
736
769
  : options;
737
- const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(`/threads/${threadId}/runs/${runId}/stream`, {
770
+ const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(threadId != null
771
+ ? `/threads/${threadId}/runs/${runId}/stream`
772
+ : `/runs/${runId}/stream`, {
738
773
  method: "GET",
739
774
  timeoutMs: null,
740
775
  signal: opts?.signal,
776
+ headers: opts?.lastEventId
777
+ ? { "Last-Event-ID": opts.lastEventId }
778
+ : undefined,
741
779
  params: {
742
780
  cancel_on_disconnect: opts?.cancelOnDisconnect ? "1" : "0",
743
781
  stream_mode: opts?.streamMode,
package/dist/client.d.ts CHANGED
@@ -31,12 +31,21 @@ declare class BaseClient {
31
31
  json?: unknown;
32
32
  params?: Record<string, unknown>;
33
33
  timeoutMs?: number | null;
34
+ withResponse?: boolean;
34
35
  }): [url: URL, init: RequestInit];
36
+ protected fetch<T>(path: string, options: RequestInit & {
37
+ json?: unknown;
38
+ params?: Record<string, unknown>;
39
+ timeoutMs?: number | null;
40
+ signal?: AbortSignal;
41
+ withResponse: true;
42
+ }): Promise<[T, Response]>;
35
43
  protected fetch<T>(path: string, options?: RequestInit & {
36
44
  json?: unknown;
37
45
  params?: Record<string, unknown>;
38
46
  timeoutMs?: number | null;
39
47
  signal?: AbortSignal;
48
+ withResponse?: false;
40
49
  }): Promise<T>;
41
50
  }
42
51
  export declare class CronsClient extends BaseClient {
@@ -398,24 +407,25 @@ export declare class RunsClient<TStateType = DefaultValues, TUpdateType = TState
398
407
  }): Promise<void>;
399
408
  /**
400
409
  * Stream output from a run in real-time, until the run is done.
401
- * Output is not buffered, so any output produced before this call will
402
- * not be received here.
403
410
  *
404
- * @param threadId The ID of the thread.
411
+ * @param threadId The ID of the thread. Can be set to `null` | `undefined` for stateless runs.
405
412
  * @param runId The ID of the run.
406
413
  * @param options Additional options for controlling the stream behavior:
407
414
  * - signal: An AbortSignal that can be used to cancel the stream request
415
+ * - lastEventId: The ID of the last event received. Can be used to reconnect to a stream without losing events.
408
416
  * - cancelOnDisconnect: When true, automatically cancels the run if the client disconnects from the stream
409
417
  * - streamMode: Controls what types of events to receive from the stream (can be a single mode or array of modes)
410
418
  * Must be a subset of the stream modes passed when creating the run. Background runs default to having the union of all
411
419
  * stream modes enabled.
412
420
  * @returns An async generator yielding stream parts.
413
421
  */
414
- joinStream(threadId: string, runId: string, options?: {
422
+ joinStream(threadId: string | undefined | null, runId: string, options?: {
415
423
  signal?: AbortSignal;
416
424
  cancelOnDisconnect?: boolean;
425
+ lastEventId?: string;
417
426
  streamMode?: StreamMode | StreamMode[];
418
427
  } | AbortSignal): AsyncGenerator<{
428
+ id?: string;
419
429
  event: StreamEvent;
420
430
  data: any;
421
431
  }>;
package/dist/client.js CHANGED
@@ -28,6 +28,19 @@ export function getApiKey(apiKey) {
28
28
  }
29
29
  return undefined;
30
30
  }
31
+ const REGEX_RUN_METADATA = /(\/threads\/(?<thread_id>.+))?\/runs\/(?<run_id>.+)/;
32
+ function getRunMetadataFromResponse(response) {
33
+ const contentLocation = response.headers.get("Content-Location");
34
+ if (!contentLocation)
35
+ return undefined;
36
+ const match = REGEX_RUN_METADATA.exec(contentLocation);
37
+ if (!match?.groups?.run_id)
38
+ return undefined;
39
+ return {
40
+ run_id: match.groups.run_id,
41
+ thread_id: match.groups.thread_id || undefined,
42
+ };
43
+ }
31
44
  class BaseClient {
32
45
  constructor(config) {
33
46
  Object.defineProperty(this, "asyncCaller", {
@@ -96,6 +109,9 @@ class BaseClient {
96
109
  };
97
110
  delete mutatedOptions.json;
98
111
  }
112
+ if (mutatedOptions.withResponse) {
113
+ delete mutatedOptions.withResponse;
114
+ }
99
115
  let timeoutSignal = null;
100
116
  if (typeof options?.timeoutMs !== "undefined") {
101
117
  if (options.timeoutMs != null) {
@@ -122,10 +138,16 @@ class BaseClient {
122
138
  }
123
139
  async fetch(path, options) {
124
140
  const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(path, options));
125
- if (response.status === 202 || response.status === 204) {
126
- return undefined;
141
+ const body = (() => {
142
+ if (response.status === 202 || response.status === 204) {
143
+ return undefined;
144
+ }
145
+ return response.json();
146
+ })();
147
+ if (options?.withResponse) {
148
+ return [await body, response];
127
149
  }
128
- return response.json();
150
+ return body;
129
151
  }
130
152
  }
131
153
  export class CronsClient extends BaseClient {
@@ -549,6 +571,9 @@ export class RunsClient extends BaseClient {
549
571
  timeoutMs: null,
550
572
  signal: payload?.signal,
551
573
  }));
574
+ const runMetadata = getRunMetadataFromResponse(response);
575
+ if (runMetadata)
576
+ payload?.onRunCreated?.(runMetadata);
552
577
  const stream = (response.body || new ReadableStream({ start: (ctrl) => ctrl.close() }))
553
578
  .pipeThrough(new BytesLineDecoder())
554
579
  .pipeThrough(new SSEDecoder());
@@ -581,11 +606,16 @@ export class RunsClient extends BaseClient {
581
606
  if_not_exists: payload?.ifNotExists,
582
607
  checkpoint_during: payload?.checkpointDuring,
583
608
  };
584
- return this.fetch(`/threads/${threadId}/runs`, {
609
+ const [run, response] = await this.fetch(`/threads/${threadId}/runs`, {
585
610
  method: "POST",
586
611
  json,
587
612
  signal: payload?.signal,
613
+ withResponse: true,
588
614
  });
615
+ const runMetadata = getRunMetadataFromResponse(response);
616
+ if (runMetadata)
617
+ payload?.onRunCreated?.(runMetadata);
618
+ return run;
589
619
  }
590
620
  /**
591
621
  * Create a batch of stateless background runs.
@@ -632,22 +662,26 @@ export class RunsClient extends BaseClient {
632
662
  checkpoint_during: payload?.checkpointDuring,
633
663
  };
634
664
  const endpoint = threadId == null ? `/runs/wait` : `/threads/${threadId}/runs/wait`;
635
- const response = await this.fetch(endpoint, {
665
+ const [run, response] = await this.fetch(endpoint, {
636
666
  method: "POST",
637
667
  json,
638
668
  timeoutMs: null,
639
669
  signal: payload?.signal,
670
+ withResponse: true,
640
671
  });
672
+ const runMetadata = getRunMetadataFromResponse(response);
673
+ if (runMetadata)
674
+ payload?.onRunCreated?.(runMetadata);
641
675
  const raiseError = payload?.raiseError !== undefined ? payload.raiseError : true;
642
676
  if (raiseError &&
643
- "__error__" in response &&
644
- typeof response.__error__ === "object" &&
645
- response.__error__ &&
646
- "error" in response.__error__ &&
647
- "message" in response.__error__) {
648
- throw new Error(`${response.__error__?.error}: ${response.__error__?.message}`);
677
+ "__error__" in run &&
678
+ typeof run.__error__ === "object" &&
679
+ run.__error__ &&
680
+ "error" in run.__error__ &&
681
+ "message" in run.__error__) {
682
+ throw new Error(`${run.__error__?.error}: ${run.__error__?.message}`);
649
683
  }
650
- return response;
684
+ return run;
651
685
  }
652
686
  /**
653
687
  * List all runs for a thread.
@@ -708,13 +742,12 @@ export class RunsClient extends BaseClient {
708
742
  }
709
743
  /**
710
744
  * Stream output from a run in real-time, until the run is done.
711
- * Output is not buffered, so any output produced before this call will
712
- * not be received here.
713
745
  *
714
- * @param threadId The ID of the thread.
746
+ * @param threadId The ID of the thread. Can be set to `null` | `undefined` for stateless runs.
715
747
  * @param runId The ID of the run.
716
748
  * @param options Additional options for controlling the stream behavior:
717
749
  * - signal: An AbortSignal that can be used to cancel the stream request
750
+ * - lastEventId: The ID of the last event received. Can be used to reconnect to a stream without losing events.
718
751
  * - cancelOnDisconnect: When true, automatically cancels the run if the client disconnects from the stream
719
752
  * - streamMode: Controls what types of events to receive from the stream (can be a single mode or array of modes)
720
753
  * Must be a subset of the stream modes passed when creating the run. Background runs default to having the union of all
@@ -727,10 +760,15 @@ export class RunsClient extends BaseClient {
727
760
  options instanceof AbortSignal
728
761
  ? { signal: options }
729
762
  : options;
730
- const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(`/threads/${threadId}/runs/${runId}/stream`, {
763
+ const response = await this.asyncCaller.fetch(...this.prepareFetchOptions(threadId != null
764
+ ? `/threads/${threadId}/runs/${runId}/stream`
765
+ : `/runs/${runId}/stream`, {
731
766
  method: "GET",
732
767
  timeoutMs: null,
733
768
  signal: opts?.signal,
769
+ headers: opts?.lastEventId
770
+ ? { "Last-Event-ID": opts.lastEventId }
771
+ : undefined,
734
772
  params: {
735
773
  cancel_on_disconnect: opts?.cancelOnDisconnect ? "1" : "0",
736
774
  stream_mode: opts?.streamMode,
package/dist/types.d.ts CHANGED
@@ -104,6 +104,13 @@ interface RunsInvokePayload {
104
104
  * One or more commands to invoke the graph with.
105
105
  */
106
106
  command?: Command;
107
+ /**
108
+ * Callback when a run is created.
109
+ */
110
+ onRunCreated?: (params: {
111
+ run_id: string;
112
+ thread_id?: string;
113
+ }) => void;
107
114
  }
108
115
  export interface RunsStreamPayload<TStreamMode extends StreamMode | StreamMode[] = [], TSubgraphs extends boolean = false> extends RunsInvokePayload {
109
116
  /**
@@ -15,9 +15,11 @@ type MessageTupleMetadata = {
15
15
  [key: string]: unknown;
16
16
  };
17
17
  type AsSubgraph<TEvent extends {
18
+ id?: string;
18
19
  event: string;
19
20
  data: unknown;
20
21
  }> = {
22
+ id?: TEvent["id"];
21
23
  event: TEvent["event"] | `${TEvent["event"]}|${string}`;
22
24
  data: TEvent["data"];
23
25
  };
@@ -25,6 +27,7 @@ type AsSubgraph<TEvent extends {
25
27
  * Stream event with values after completion of each step.
26
28
  */
27
29
  export type ValuesStreamEvent<StateType> = {
30
+ id?: string;
28
31
  event: "values";
29
32
  data: StateType;
30
33
  };
@@ -43,6 +46,7 @@ export type SubgraphMessagesTupleStreamEvent = AsSubgraph<MessagesTupleStreamEve
43
46
  * Metadata stream event with information about the run and thread
44
47
  */
45
48
  export type MetadataStreamEvent = {
49
+ id?: string;
46
50
  event: "metadata";
47
51
  data: {
48
52
  run_id: string;
@@ -53,6 +57,7 @@ export type MetadataStreamEvent = {
53
57
  * Stream event with error information.
54
58
  */
55
59
  export type ErrorStreamEvent = {
60
+ id?: string;
56
61
  event: "error";
57
62
  data: {
58
63
  error: string;
@@ -67,6 +72,7 @@ export type SubgraphErrorStreamEvent = AsSubgraph<ErrorStreamEvent>;
67
72
  * produced the update as well as the update.
68
73
  */
69
74
  export type UpdatesStreamEvent<UpdateType> = {
75
+ id?: string;
70
76
  event: "updates";
71
77
  data: {
72
78
  [node: string]: UpdateType;
@@ -84,6 +90,7 @@ export type CustomStreamEvent<T> = {
84
90
  /** @internal */
85
91
  export type SubgraphCustomStreamEvent<T> = AsSubgraph<CustomStreamEvent<T>>;
86
92
  type MessagesMetadataStreamEvent = {
93
+ id?: string;
87
94
  event: "messages/metadata";
88
95
  data: {
89
96
  [messageId: string]: {
@@ -92,10 +99,12 @@ type MessagesMetadataStreamEvent = {
92
99
  };
93
100
  };
94
101
  type MessagesCompleteStreamEvent = {
102
+ id?: string;
95
103
  event: "messages/complete";
96
104
  data: Message[];
97
105
  };
98
106
  type MessagesPartialStreamEvent = {
107
+ id?: string;
99
108
  event: "messages/partial";
100
109
  data: Message[];
101
110
  };
@@ -110,6 +119,7 @@ export type SubgraphMessagesStreamEvent = AsSubgraph<MessagesMetadataStreamEvent
110
119
  * Stream event with detailed debug information.
111
120
  */
112
121
  export type DebugStreamEvent = {
122
+ id?: string;
113
123
  event: "debug";
114
124
  data: unknown;
115
125
  };
@@ -119,6 +129,7 @@ export type SubgraphDebugStreamEvent = AsSubgraph<DebugStreamEvent>;
119
129
  * Stream event with events occurring during execution.
120
130
  */
121
131
  export type EventsStreamEvent = {
132
+ id?: string;
122
133
  event: "events";
123
134
  data: {
124
135
  event: `on_${"chat_model" | "llm" | "chain" | "tool" | "retriever" | "prompt"}_${"start" | "stream" | "end"}` | (string & {});
@@ -137,6 +148,7 @@ export type SubgraphEventsStreamEvent = AsSubgraph<EventsStreamEvent>;
137
148
  * the `RunsStreamPayload` to receive this event.
138
149
  */
139
150
  export type FeedbackStreamEvent = {
151
+ id?: string;
140
152
  event: "feedback";
141
153
  data: {
142
154
  [feedbackKey: string]: string;
@@ -94,6 +94,7 @@ class SSEDecoder extends TransformStream {
94
94
  if (!event && !data.length && !lastEventId && retry == null)
95
95
  return;
96
96
  const sse = {
97
+ id: lastEventId || undefined,
97
98
  event,
98
99
  data: data.length ? decodeArraysToJson(decoder, data) : null,
99
100
  };
@@ -133,6 +134,7 @@ class SSEDecoder extends TransformStream {
133
134
  flush(controller) {
134
135
  if (event) {
135
136
  controller.enqueue({
137
+ id: lastEventId || undefined,
136
138
  event,
137
139
  data: data.length ? decodeArraysToJson(decoder, data) : null,
138
140
  });
@@ -2,6 +2,7 @@ export declare class BytesLineDecoder extends TransformStream<Uint8Array, Uint8A
2
2
  constructor();
3
3
  }
4
4
  interface StreamPart {
5
+ id: string | undefined;
5
6
  event: string;
6
7
  data: unknown;
7
8
  }
package/dist/utils/sse.js CHANGED
@@ -90,6 +90,7 @@ export class SSEDecoder extends TransformStream {
90
90
  if (!event && !data.length && !lastEventId && retry == null)
91
91
  return;
92
92
  const sse = {
93
+ id: lastEventId || undefined,
93
94
  event,
94
95
  data: data.length ? decodeArraysToJson(decoder, data) : null,
95
96
  };
@@ -129,6 +130,7 @@ export class SSEDecoder extends TransformStream {
129
130
  flush(controller) {
130
131
  if (event) {
131
132
  controller.enqueue({
133
+ id: lastEventId || undefined,
132
134
  event,
133
135
  data: data.length ? decodeArraysToJson(decoder, data) : null,
134
136
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "0.0.74",
3
+ "version": "0.0.75",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "packageManager": "yarn@1.22.19",
@@ -10,7 +10,7 @@
10
10
  "prepack": "yarn run build",
11
11
  "format": "prettier --write src",
12
12
  "lint": "prettier --check src && tsc --noEmit",
13
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts",
13
+ "test": "vitest",
14
14
  "typedoc": "typedoc && typedoc src/react/index.ts --out docs/react --options typedoc.react.json && typedoc src/auth/index.ts --out docs/auth --options typedoc.auth.json"
15
15
  },
16
16
  "main": "index.js",
@@ -22,28 +22,32 @@
22
22
  "uuid": "^9.0.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@jest/globals": "^29.7.0",
26
25
  "@langchain/core": "^0.3.31",
27
26
  "@langchain/scripts": "^0.1.4",
27
+ "@testing-library/dom": "^10.4.0",
28
+ "@testing-library/jest-dom": "^6.6.3",
29
+ "@testing-library/react": "^16.3.0",
30
+ "@testing-library/user-event": "^14.6.1",
28
31
  "@tsconfig/recommended": "^1.0.2",
29
- "@types/jest": "^29.5.12",
30
32
  "@types/node": "^20.12.12",
31
- "@types/uuid": "^9.0.1",
32
33
  "@types/react": "^19.0.8",
33
34
  "@types/react-dom": "^19.0.3",
35
+ "@types/uuid": "^9.0.1",
36
+ "@vitejs/plugin-react": "^4.4.1",
34
37
  "concat-md": "^0.5.1",
35
- "jest": "^29.7.0",
38
+ "jsdom": "^26.1.0",
39
+ "msw": "^2.8.2",
36
40
  "prettier": "^3.2.5",
37
- "ts-jest": "^29.1.2",
41
+ "react": "^19.0.0",
42
+ "react-dom": "^19.0.0",
38
43
  "typedoc": "^0.27.7",
39
44
  "typedoc-plugin-markdown": "^4.4.2",
40
45
  "typescript": "^5.4.5",
41
- "react": "^19.0.0",
42
- "react-dom": "^19.0.0"
46
+ "vitest": "^3.1.3"
43
47
  },
44
48
  "peerDependencies": {
45
- "react": "^18 || ^19",
46
- "@langchain/core": ">=0.2.31 <0.4.0"
49
+ "@langchain/core": ">=0.2.31 <0.4.0",
50
+ "react": "^18 || ^19"
47
51
  },
48
52
  "peerDependenciesMeta": {
49
53
  "react": {