@langgraph-js/sdk 1.3.1 → 1.4.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/.env +0 -0
- package/LICENSE +201 -201
- package/README.md +163 -163
- package/dist/LangGraphClient.d.ts +3 -0
- package/dist/LangGraphClient.js +43 -3
- package/dist/ui-store/createChatStore.js +2 -0
- package/package.json +1 -1
- package/src/LangGraphClient.ts +613 -574
- package/src/SpendTime.ts +60 -60
- package/src/ToolManager.ts +129 -129
- package/src/index.ts +5 -5
- package/src/tool/copilotkit-actions.ts +72 -72
- package/src/tool/createTool.ts +78 -78
- package/src/tool/index.ts +2 -2
- package/src/tool/utils.ts +158 -158
- package/src/ui-store/UnionStore.ts +29 -29
- package/src/ui-store/createChatStore.ts +287 -286
- package/src/ui-store/index.ts +2 -2
- package/src/ui-store/rafDebounce.ts +29 -29
- package/test/testResponse.json +5418 -5418
- package/tsconfig.json +112 -112
package/README.md
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# @langgraph-js/sdk
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
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
|
+

|
|
4
|
+

|
|
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.
|
|
@@ -119,6 +119,7 @@ export declare class LangGraphClient extends Client {
|
|
|
119
119
|
/** 图发过来的更新信息 */
|
|
120
120
|
graphMessages: RenderMessage[];
|
|
121
121
|
cloneMessage(message: Message): Message;
|
|
122
|
+
private updateStreamingMessage;
|
|
122
123
|
private replaceMessageWithValuesMessage;
|
|
123
124
|
/**
|
|
124
125
|
* @zh 用于 UI 中的流式渲染中的消息。
|
|
@@ -164,6 +165,8 @@ export declare class LangGraphClient extends Client {
|
|
|
164
165
|
* @en Sends a message to the LangGraph backend.
|
|
165
166
|
*/
|
|
166
167
|
sendMessage(input: string | Message[], { extraParams, _debug, command }?: SendMessageOptions): Promise<any[]>;
|
|
168
|
+
/** 子图的数据需要通过 merge 的方式重新进行合并更新 */
|
|
169
|
+
private mergeSubGraphMessagesToStreamingMessages;
|
|
167
170
|
private runFETool;
|
|
168
171
|
private callFETool;
|
|
169
172
|
/**
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -126,6 +126,14 @@ export class LangGraphClient extends Client {
|
|
|
126
126
|
cloneMessage(message) {
|
|
127
127
|
return JSON.parse(JSON.stringify(message));
|
|
128
128
|
}
|
|
129
|
+
updateStreamingMessage(message) {
|
|
130
|
+
const lastMessage = this.streamingMessage[this.streamingMessage.length - 1];
|
|
131
|
+
if (!(lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.id) || message.id !== lastMessage.id) {
|
|
132
|
+
this.streamingMessage.push(message);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.streamingMessage[this.streamingMessage.length - 1] = message;
|
|
136
|
+
}
|
|
129
137
|
replaceMessageWithValuesMessage(message, isTool = false) {
|
|
130
138
|
const key = (isTool ? "tool_call_id" : "id");
|
|
131
139
|
const valuesMessage = this.graphMessages.find((i) => i[key] === message[key]);
|
|
@@ -145,8 +153,10 @@ export class LangGraphClient extends Client {
|
|
|
145
153
|
get renderMessage() {
|
|
146
154
|
var _a;
|
|
147
155
|
const previousMessage = new Map();
|
|
156
|
+
const closedToolCallIds = new Set();
|
|
148
157
|
const result = [];
|
|
149
158
|
const inputMessages = [...this.graphMessages, ...this.streamingMessage];
|
|
159
|
+
console.log(inputMessages);
|
|
150
160
|
// 从后往前遍历,这样可以保证最新的消息在前面
|
|
151
161
|
for (let i = inputMessages.length - 1; i >= 0; i--) {
|
|
152
162
|
const message = this.cloneMessage(inputMessages[i]);
|
|
@@ -164,7 +174,11 @@ export class LangGraphClient extends Client {
|
|
|
164
174
|
previousMessage.set(message.id, m);
|
|
165
175
|
/** @ts-ignore */
|
|
166
176
|
const tool_calls = ((_a = m.tool_calls) === null || _a === void 0 ? void 0 : _a.length) ? m.tool_calls : m.tool_call_chunks;
|
|
167
|
-
const new_tool_calls = tool_calls
|
|
177
|
+
const new_tool_calls = tool_calls
|
|
178
|
+
.filter((i) => {
|
|
179
|
+
return !closedToolCallIds.has(i.id);
|
|
180
|
+
})
|
|
181
|
+
.map((tool, index) => {
|
|
168
182
|
var _a, _b, _c, _d;
|
|
169
183
|
return this.replaceMessageWithValuesMessage({
|
|
170
184
|
type: "tool",
|
|
@@ -186,6 +200,9 @@ export class LangGraphClient extends Client {
|
|
|
186
200
|
result.unshift(m);
|
|
187
201
|
}
|
|
188
202
|
else {
|
|
203
|
+
if (message.type === "tool" && message.tool_call_id) {
|
|
204
|
+
closedToolCallIds.add(message.tool_call_id);
|
|
205
|
+
}
|
|
189
206
|
// 记录这个 id 的消息,并添加到结果中
|
|
190
207
|
const m = this.replaceMessageWithValuesMessage(message);
|
|
191
208
|
previousMessage.set(message.id, m);
|
|
@@ -364,7 +381,7 @@ export class LangGraphClient extends Client {
|
|
|
364
381
|
}
|
|
365
382
|
else if (chunk.event === "messages/partial") {
|
|
366
383
|
for (const message of chunk.data) {
|
|
367
|
-
this.
|
|
384
|
+
this.updateStreamingMessage(message);
|
|
368
385
|
}
|
|
369
386
|
this.emitStreamingUpdate({
|
|
370
387
|
type: "message",
|
|
@@ -372,7 +389,7 @@ export class LangGraphClient extends Client {
|
|
|
372
389
|
});
|
|
373
390
|
continue;
|
|
374
391
|
}
|
|
375
|
-
else if (chunk.event
|
|
392
|
+
else if (chunk.event === "values") {
|
|
376
393
|
const data = chunk.data;
|
|
377
394
|
if (data.messages) {
|
|
378
395
|
const isResume = !!(command === null || command === void 0 ? void 0 : command.resume);
|
|
@@ -390,6 +407,12 @@ export class LangGraphClient extends Client {
|
|
|
390
407
|
this.streamingMessage = [];
|
|
391
408
|
continue;
|
|
392
409
|
}
|
|
410
|
+
else if (chunk.event.startsWith("values|")) {
|
|
411
|
+
// 这个 values 必然是子 values
|
|
412
|
+
if (chunk.data.messages) {
|
|
413
|
+
this.mergeSubGraphMessagesToStreamingMessages(chunk.data.messages);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
393
416
|
}
|
|
394
417
|
this.streamingMessage = [];
|
|
395
418
|
const data = await this.runFETool();
|
|
@@ -403,6 +426,23 @@ export class LangGraphClient extends Client {
|
|
|
403
426
|
});
|
|
404
427
|
return streamRecord;
|
|
405
428
|
}
|
|
429
|
+
/** 子图的数据需要通过 merge 的方式重新进行合并更新 */
|
|
430
|
+
mergeSubGraphMessagesToStreamingMessages(messages) {
|
|
431
|
+
const map = new Map(messages.filter((i) => i.id).map((i) => [i.id, i]));
|
|
432
|
+
this.streamingMessage.forEach((i) => {
|
|
433
|
+
if (map.has(i.id)) {
|
|
434
|
+
const newValue = map.get(i.id);
|
|
435
|
+
Object.assign(i, newValue);
|
|
436
|
+
map.delete(i.id);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
// 剩余的 message 一定不在 streamMessage 中
|
|
440
|
+
map.forEach((i) => {
|
|
441
|
+
if (i.type === "tool" && i.tool_call_id) {
|
|
442
|
+
this.streamingMessage.push(i);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
406
446
|
runFETool() {
|
|
407
447
|
var _a;
|
|
408
448
|
const data = this.graphMessages;
|
|
@@ -105,6 +105,8 @@ export const createChatStore = (initClientName, config, context = {}) => {
|
|
|
105
105
|
// console.log(event.data);
|
|
106
106
|
// 创建新流程时,默认为 __start__
|
|
107
107
|
currentNodeName.set("__start__");
|
|
108
|
+
if (event.type === "done")
|
|
109
|
+
loading.set(false);
|
|
108
110
|
// 创建新会话时,需要自动刷新历史面板
|
|
109
111
|
return refreshHistoryList();
|
|
110
112
|
}
|