@langgraph-js/sdk 1.5.4 → 1.6.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/README.md CHANGED
@@ -1,163 +1,163 @@
1
- # @langgraph-js/sdk
2
-
3
- ![npm version](https://img.shields.io/npm/v/@langgraph-js/sdk)
4
- ![license](https://img.shields.io/npm/l/@langgraph-js/sdk)
5
-
6
- > The missing UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces
7
-
8
- ## Why @langgraph-js/sdk?
9
-
10
- Building AI agent applications is complex, especially when you need to bridge the gap between LangGraph agents and interactive user interfaces. This SDK solves the critical challenges of frontend integration:
11
-
12
- - **Provides a complete UI integration layer** - no more complex custom code to handle tools, streaming, and state management
13
- - **Simplifies human-in-the-loop interactions** - easily incorporate user feedback within agent workflows
14
- - **Handles edge cases automatically** - interruptions, errors, token management and more
15
- - **Offers a rich set of UI components** - ready-to-use elements to display agent interactions
16
-
17
- [DOCS](https://langgraph-js.netlify.app)
18
-
19
- ## Installation
20
-
21
- ```bash
22
- # Using npm
23
- npm install @langgraph-js/sdk
24
-
25
- # Using yarn
26
- yarn add @langgraph-js/sdk
27
-
28
- # Using pnpm
29
- pnpm add @langgraph-js/sdk
30
- ```
31
-
32
- ## Key Features
33
-
34
- ### Generative UI
35
-
36
- - ✅ Custom Tool Messages
37
- - ✅ Token Counter
38
- - ✅ Stop Graph Progress
39
- - ✅ Interrupt Handling
40
- - ✅ Error Handling
41
- - ✅ Spend Time Tracking
42
- - ✅ Time Persistence
43
-
44
- ### Frontend Actions
45
-
46
- - ✅ Definition of Union Tools
47
- - ✅ Frontend Functions As Tools
48
- - ✅ Human-in-the-Loop Interaction
49
- - ✅ Interrupt Mode
50
-
51
- ### Authorization
52
-
53
- - ✅ Cookie-Based Authentication
54
- - ✅ Custom Token Authentication
55
-
56
- ### Persistence
57
-
58
- - ✅ Read History from LangGraph
59
-
60
- ## Advanced Usage
61
-
62
- ### Creating a Chat Store
63
-
64
- You can easily create a reactive store for your LangGraph client:
65
-
66
- ```typescript
67
- import { createChatStore } from "@langgraph-js/sdk";
68
-
69
- export const globalChatStore = createChatStore(
70
- "agent",
71
- {
72
- // Custom LangGraph backend interaction
73
- apiUrl: "http://localhost:8123",
74
- // Custom headers for authentication
75
- defaultHeaders: JSON.parse(localStorage.getItem("code") || "{}"),
76
- callerOptions: {
77
- // Example for including cookies
78
- // fetch(url: string, options: RequestInit) {
79
- // options.credentials = "include";
80
- // return fetch(url, options);
81
- // },
82
- },
83
- },
84
- {
85
- onInit(client) {
86
- client.tools.bindTools([]);
87
- },
88
- }
89
- );
90
- ```
91
-
92
- ### React Integration
93
-
94
- First, install the nanostores React integration:
95
-
96
- ```bash
97
- pnpm i @nanostores/react
98
- ```
99
-
100
- Then create a context provider for your chat:
101
-
102
- ```tsx
103
- import React, { createContext, useContext, useEffect } from "react";
104
- import { globalChatStore } from "../store"; // Import your store
105
- import { UnionStore, useUnionStore } from "@langgraph-js/sdk";
106
- import { useStore } from "@nanostores/react";
107
-
108
- type ChatContextType = UnionStore<typeof globalChatStore>;
109
-
110
- const ChatContext = createContext<ChatContextType | undefined>(undefined);
111
-
112
- export const useChat = () => {
113
- const context = useContext(ChatContext);
114
- if (!context) {
115
- throw new Error("useChat must be used within a ChatProvider");
116
- }
117
- return context;
118
- };
119
-
120
- export const ChatProvider = ({ children }) => {
121
- // Use store to ensure React gets reactive state updates
122
- const store = useUnionStore(globalChatStore, useStore);
123
-
124
- useEffect(() => {
125
- // Initialize client
126
- store.initClient().then(() => {
127
- // Initialize conversation history
128
- store.refreshHistoryList();
129
- });
130
- }, [store.currentAgent]);
131
-
132
- return <ChatContext.Provider value={store}>{children}</ChatContext.Provider>;
133
- };
134
- ```
135
-
136
- Use it in your components:
137
-
138
- ```tsx
139
- export const MyChat = () => {
140
- return (
141
- <ChatProvider>
142
- <ChatComp></ChatComp>
143
- </ChatProvider>
144
- );
145
- };
146
-
147
- function ChatComp() {
148
- const chat = useChat();
149
- // Use chat store methods and state here
150
- }
151
- ```
152
-
153
- ## Documentation
154
-
155
- For complete documentation, visit our [official docs](https://langgraph-js.netlify.app).
156
-
157
- ## Contributing
158
-
159
- Contributions are welcome! Please feel free to submit a Pull Request.
160
-
161
- ## License
162
-
163
- This project is licensed under the Apache-2.0 License.
1
+ # @langgraph-js/sdk
2
+
3
+ ![npm version](https://img.shields.io/npm/v/@langgraph-js/sdk)
4
+ ![license](https://img.shields.io/npm/l/@langgraph-js/sdk)
5
+
6
+ > The missing UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces
7
+
8
+ ## Why @langgraph-js/sdk?
9
+
10
+ Building AI agent applications is complex, especially when you need to bridge the gap between LangGraph agents and interactive user interfaces. This SDK solves the critical challenges of frontend integration:
11
+
12
+ - **Provides a complete UI integration layer** - no more complex custom code to handle tools, streaming, and state management
13
+ - **Simplifies human-in-the-loop interactions** - easily incorporate user feedback within agent workflows
14
+ - **Handles edge cases automatically** - interruptions, errors, token management and more
15
+ - **Offers a rich set of UI components** - ready-to-use elements to display agent interactions
16
+
17
+ [DOCS](https://langgraph-js.netlify.app)
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # Using npm
23
+ npm install @langgraph-js/sdk
24
+
25
+ # Using yarn
26
+ yarn add @langgraph-js/sdk
27
+
28
+ # Using pnpm
29
+ pnpm add @langgraph-js/sdk
30
+ ```
31
+
32
+ ## Key Features
33
+
34
+ ### Generative UI
35
+
36
+ - ✅ Custom Tool Messages
37
+ - ✅ Token Counter
38
+ - ✅ Stop Graph Progress
39
+ - ✅ Interrupt Handling
40
+ - ✅ Error Handling
41
+ - ✅ Spend Time Tracking
42
+ - ✅ Time Persistence
43
+
44
+ ### Frontend Actions
45
+
46
+ - ✅ Definition of Union Tools
47
+ - ✅ Frontend Functions As Tools
48
+ - ✅ Human-in-the-Loop Interaction
49
+ - ✅ Interrupt Mode
50
+
51
+ ### Authorization
52
+
53
+ - ✅ Cookie-Based Authentication
54
+ - ✅ Custom Token Authentication
55
+
56
+ ### Persistence
57
+
58
+ - ✅ Read History from LangGraph
59
+
60
+ ## Advanced Usage
61
+
62
+ ### Creating a Chat Store
63
+
64
+ You can easily create a reactive store for your LangGraph client:
65
+
66
+ ```typescript
67
+ import { createChatStore } from "@langgraph-js/sdk";
68
+
69
+ export const globalChatStore = createChatStore(
70
+ "agent",
71
+ {
72
+ // Custom LangGraph backend interaction
73
+ apiUrl: "http://localhost:8123",
74
+ // Custom headers for authentication
75
+ defaultHeaders: JSON.parse(localStorage.getItem("code") || "{}"),
76
+ callerOptions: {
77
+ // Example for including cookies
78
+ // fetch(url: string, options: RequestInit) {
79
+ // options.credentials = "include";
80
+ // return fetch(url, options);
81
+ // },
82
+ },
83
+ },
84
+ {
85
+ onInit(client) {
86
+ client.tools.bindTools([]);
87
+ },
88
+ }
89
+ );
90
+ ```
91
+
92
+ ### React Integration
93
+
94
+ First, install the nanostores React integration:
95
+
96
+ ```bash
97
+ pnpm i @nanostores/react
98
+ ```
99
+
100
+ Then create a context provider for your chat:
101
+
102
+ ```tsx
103
+ import React, { createContext, useContext, useEffect } from "react";
104
+ import { globalChatStore } from "../store"; // Import your store
105
+ import { UnionStore, useUnionStore } from "@langgraph-js/sdk";
106
+ import { useStore } from "@nanostores/react";
107
+
108
+ type ChatContextType = UnionStore<typeof globalChatStore>;
109
+
110
+ const ChatContext = createContext<ChatContextType | undefined>(undefined);
111
+
112
+ export const useChat = () => {
113
+ const context = useContext(ChatContext);
114
+ if (!context) {
115
+ throw new Error("useChat must be used within a ChatProvider");
116
+ }
117
+ return context;
118
+ };
119
+
120
+ export const ChatProvider = ({ children }) => {
121
+ // Use store to ensure React gets reactive state updates
122
+ const store = useUnionStore(globalChatStore, useStore);
123
+
124
+ useEffect(() => {
125
+ // Initialize client
126
+ store.initClient().then(() => {
127
+ // Initialize conversation history
128
+ store.refreshHistoryList();
129
+ });
130
+ }, [store.currentAgent]);
131
+
132
+ return <ChatContext.Provider value={store}>{children}</ChatContext.Provider>;
133
+ };
134
+ ```
135
+
136
+ Use it in your components:
137
+
138
+ ```tsx
139
+ export const MyChat = () => {
140
+ return (
141
+ <ChatProvider>
142
+ <ChatComp></ChatComp>
143
+ </ChatProvider>
144
+ );
145
+ };
146
+
147
+ function ChatComp() {
148
+ const chat = useChat();
149
+ // Use chat store methods and state here
150
+ }
151
+ ```
152
+
153
+ ## Documentation
154
+
155
+ For complete documentation, visit our [official docs](https://langgraph-js.netlify.app).
156
+
157
+ ## Contributing
158
+
159
+ Contributions are welcome! Please feel free to submit a Pull Request.
160
+
161
+ ## License
162
+
163
+ This project is licensed under the Apache-2.0 License.
@@ -75,7 +75,7 @@ export declare class StreamingMessageType {
75
75
  static isToolAssistant(m: Message): any;
76
76
  }
77
77
  type StreamingUpdateEvent = {
78
- type: "message" | "value" | "update" | "error" | "thread" | "done";
78
+ type: "message" | "value" | "update" | "error" | "thread" | "done" | "start";
79
79
  data: any;
80
80
  };
81
81
  type StreamingUpdateCallback = (event: StreamingUpdateEvent) => void;
@@ -121,6 +121,8 @@ export declare class LangGraphClient extends Client {
121
121
  cloneMessage(message: Message): Message;
122
122
  private updateStreamingMessage;
123
123
  private replaceMessageWithValuesMessage;
124
+ /** 将 graphMessages 和 streamingMessage 合并,并返回新的消息数组 */
125
+ private combineGraphMessagesWithStreamingMessages;
124
126
  /**
125
127
  * @zh 用于 UI 中的流式渲染中的消息。
126
128
  * @en Messages used for streaming rendering in the UI.
@@ -146,6 +146,21 @@ export class LangGraphClient extends Client {
146
146
  }
147
147
  return message;
148
148
  }
149
+ /** 将 graphMessages 和 streamingMessage 合并,并返回新的消息数组 */
150
+ combineGraphMessagesWithStreamingMessages() {
151
+ const idMap = new Map(this.streamingMessage.map((i) => [i.id, i]));
152
+ return [
153
+ ...this.graphMessages.map((i) => {
154
+ if (idMap.has(i.id)) {
155
+ const newValue = idMap.get(i.id);
156
+ idMap.delete(i.id);
157
+ return newValue;
158
+ }
159
+ return i;
160
+ }),
161
+ ...idMap.values(),
162
+ ];
163
+ }
149
164
  /**
150
165
  * @zh 用于 UI 中的流式渲染中的消息。
151
166
  * @en Messages used for streaming rendering in the UI.
@@ -155,8 +170,7 @@ export class LangGraphClient extends Client {
155
170
  const previousMessage = new Map();
156
171
  const closedToolCallIds = new Set();
157
172
  const result = [];
158
- const inputMessages = [...this.graphMessages, ...this.streamingMessage];
159
- console.log(inputMessages);
173
+ const inputMessages = this.combineGraphMessagesWithStreamingMessages();
160
174
  // 从后往前遍历,这样可以保证最新的消息在前面
161
175
  for (let i = inputMessages.length - 1; i >= 0; i--) {
162
176
  const message = this.cloneMessage(inputMessages[i]);
@@ -164,10 +178,6 @@ export class LangGraphClient extends Client {
164
178
  result.unshift(message);
165
179
  continue;
166
180
  }
167
- // 如果已经处理过这个 id 的消息,跳过
168
- if (previousMessage.has(message.id)) {
169
- continue;
170
- }
171
181
  if (StreamingMessageType.isToolAssistant(message)) {
172
182
  const m = this.replaceMessageWithValuesMessage(message);
173
183
  // 记录这个 id 的消息,并添加到结果中
@@ -368,6 +378,12 @@ export class LangGraphClient extends Client {
368
378
  command,
369
379
  });
370
380
  const streamRecord = [];
381
+ this.emitStreamingUpdate({
382
+ type: "start",
383
+ data: {
384
+ event: "start",
385
+ },
386
+ });
371
387
  for await (const chunk of streamResponse) {
372
388
  streamRecord.push(chunk);
373
389
  if (chunk.event === "metadata") {
@@ -403,7 +419,6 @@ export class LangGraphClient extends Client {
403
419
  });
404
420
  }
405
421
  this.graphState = chunk.data;
406
- this.streamingMessage = [];
407
422
  }
408
423
  continue;
409
424
  }
@@ -423,6 +438,7 @@ export class LangGraphClient extends Client {
423
438
  event: "done",
424
439
  },
425
440
  });
441
+ this.streamingMessage = [];
426
442
  return streamRecord;
427
443
  }
428
444
  /** 子图的数据需要通过 merge 的方式重新进行合并更新 */
@@ -446,6 +462,8 @@ export class LangGraphClient extends Client {
446
462
  var _a;
447
463
  const data = this.streamingMessage; // 需要保证不被清理
448
464
  const lastMessage = data[data.length - 1];
465
+ if (!lastMessage)
466
+ return;
449
467
  // 如果最后一条消息是前端工具消息,则调用工具
450
468
  if (lastMessage.type === "ai" && ((_a = lastMessage.tool_calls) === null || _a === void 0 ? void 0 : _a.length)) {
451
469
  const result = lastMessage.tool_calls.map((tool) => {
@@ -102,6 +102,8 @@ export const createChatStore = (initClientName, config, context = {}) => {
102
102
  // await newClient.createThread();
103
103
  inChatError.set(null);
104
104
  newClient.onStreamingUpdate((event) => {
105
+ if (event.type === "start")
106
+ loading.set(true);
105
107
  if (event.type === "thread" || event.type === "done") {
106
108
  // console.log(event.data);
107
109
  // 创建新流程时,默认为 __start__
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langgraph-js/sdk",
3
- "version": "1.5.4",
3
+ "version": "1.6.0",
4
4
  "description": "The UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",