@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/.env +0 -0
- package/LICENSE +201 -201
- package/README.md +163 -163
- package/dist/LangGraphClient.d.ts +3 -1
- package/dist/LangGraphClient.js +25 -7
- package/dist/ui-store/createChatStore.js +2 -0
- package/package.json +1 -1
- package/src/LangGraphClient.ts +629 -614
- package/src/SpendTime.ts +60 -60
- package/src/ToolManager.ts +131 -131
- package/src/index.ts +5 -5
- package/src/tool/ToolUI.ts +33 -33
- package/src/tool/copilotkit-actions.ts +72 -72
- package/src/tool/createTool.ts +89 -89
- package/src/tool/index.ts +3 -3
- package/src/tool/utils.ts +158 -158
- package/src/ui-store/UnionStore.ts +29 -29
- package/src/ui-store/createChatStore.ts +294 -293
- 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.
|
|
@@ -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.
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -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 =
|
|
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__
|