@langgraph-js/sdk 1.7.10 → 1.8.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/.turbo/turbo-build.log +5 -0
- package/LICENSE +201 -201
- package/README.md +163 -163
- package/dist/LangGraphClient.js +3 -0
- package/dist/ToolManager.d.ts +1 -1
- package/dist/ToolManager.js +2 -1
- package/dist/server/createState.d.ts +13 -0
- package/dist/server/createState.js +20 -0
- package/dist/server/feTools.d.ts +16 -0
- package/dist/server/feTools.js +37 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +3 -0
- package/dist/server/interrupt/index.d.ts +23 -0
- package/dist/server/interrupt/index.js +36 -0
- package/dist/server/swarm/handoff.d.ts +11 -0
- package/dist/server/swarm/handoff.js +84 -0
- package/dist/server/swarm/keepState.d.ts +6 -0
- package/dist/server/swarm/keepState.js +21 -0
- package/dist/server/tools/index.d.ts +1 -0
- package/dist/server/tools/index.js +1 -0
- package/dist/server/tools/sequential-thinking.d.ts +52 -0
- package/dist/server/tools/sequential-thinking.js +69 -0
- package/dist/server/utils.d.ts +3 -0
- package/dist/server/utils.js +24 -0
- package/dist/tool/createTool.d.ts +27 -23
- package/dist/tool/createTool.js +32 -9
- package/package.json +1 -1
- package/src/LangGraphClient.ts +658 -655
- package/src/SpendTime.ts +60 -60
- package/src/ToolManager.ts +132 -132
- package/src/index.ts +5 -5
- package/src/tool/ToolUI.ts +55 -55
- package/src/tool/copilotkit-actions.ts +72 -72
- package/src/tool/createTool.ts +123 -104
- 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 +295 -295
- 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.
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -513,6 +513,9 @@ export class LangGraphClient extends Client {
|
|
|
513
513
|
async callFETool(message, args) {
|
|
514
514
|
const that = this; // 防止 this 被错误解析
|
|
515
515
|
const result = await this.tools.callTool(message.name, args, { client: that, message });
|
|
516
|
+
if (!result) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
516
519
|
return this.resume(result);
|
|
517
520
|
}
|
|
518
521
|
/**
|
package/dist/ToolManager.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare class ToolManager {
|
|
|
47
47
|
callTool(name: string, args: any, context: {
|
|
48
48
|
client: LangGraphClient;
|
|
49
49
|
message: ToolMessage;
|
|
50
|
-
}): Promise<CallToolResult>;
|
|
50
|
+
}): Promise<CallToolResult | undefined>;
|
|
51
51
|
/**
|
|
52
52
|
* @zh 将所有工具转换为 JSON 定义格式。
|
|
53
53
|
* @en Converts all tools to JSON definition format.
|
package/dist/ToolManager.js
CHANGED
|
@@ -66,11 +66,12 @@ export class ToolManager {
|
|
|
66
66
|
* @en Calls the tool with the specified name.
|
|
67
67
|
*/
|
|
68
68
|
async callTool(name, args, context) {
|
|
69
|
+
var _a;
|
|
69
70
|
const tool = this.getTool(name);
|
|
70
71
|
if (!tool) {
|
|
71
72
|
throw new Error(`Tool with name ${name} not found`);
|
|
72
73
|
}
|
|
73
|
-
return await tool.execute(args, context);
|
|
74
|
+
return await ((_a = tool.execute) === null || _a === void 0 ? void 0 : _a.call(tool, args, context));
|
|
74
75
|
}
|
|
75
76
|
/**
|
|
76
77
|
* @zh 将所有工具转换为 JSON 定义格式。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnnotationRoot, StateDefinition } from "@langchain/langgraph";
|
|
2
|
+
/**
|
|
3
|
+
* create state for langgraph
|
|
4
|
+
* @example
|
|
5
|
+
* export const GraphState = createState(createReactAgentAnnotation(), ModelState, SwarmState).build({
|
|
6
|
+
* current_plan: createDefaultAnnotation<Plan | null>(() => null),
|
|
7
|
+
* title: createDefaultAnnotation<string>(() => ""),
|
|
8
|
+
*});
|
|
9
|
+
*/
|
|
10
|
+
export declare const createState: <T extends readonly AnnotationRoot<any>[]>(...parents: T) => {
|
|
11
|
+
build: <D extends StateDefinition>(state?: D) => any;
|
|
12
|
+
};
|
|
13
|
+
export declare const createDefaultAnnotation: <T>(defaultValue: () => T) => any;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Annotation } from "@langchain/langgraph";
|
|
2
|
+
/**
|
|
3
|
+
* create state for langgraph
|
|
4
|
+
* @example
|
|
5
|
+
* export const GraphState = createState(createReactAgentAnnotation(), ModelState, SwarmState).build({
|
|
6
|
+
* current_plan: createDefaultAnnotation<Plan | null>(() => null),
|
|
7
|
+
* title: createDefaultAnnotation<string>(() => ""),
|
|
8
|
+
*});
|
|
9
|
+
*/
|
|
10
|
+
export const createState = (...parents) => {
|
|
11
|
+
return {
|
|
12
|
+
build: (state = {}) => {
|
|
13
|
+
return Annotation.Root(Object.assign({}, ...parents.map((p) => p.spec), state));
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const createDefaultAnnotation = (defaultValue) => Annotation({
|
|
18
|
+
reducer: (_, a) => a,
|
|
19
|
+
default: defaultValue,
|
|
20
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
|
+
export declare const FEToolsState: any;
|
|
3
|
+
export interface FEToolParameters {
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
description: string;
|
|
7
|
+
required: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface FETool {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
parameters: FEToolParameters[];
|
|
13
|
+
}
|
|
14
|
+
export declare const createFETool: (tool: FETool) => FETool;
|
|
15
|
+
export declare const createFeTools: (tools: FETool[]) => DynamicStructuredTool[];
|
|
16
|
+
export declare const actionToTool: (tool: FETool) => DynamicStructuredTool;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { interrupt } from "@langchain/langgraph";
|
|
2
|
+
import { createDefaultAnnotation } from "./createState.js";
|
|
3
|
+
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
4
|
+
import { createState } from "./createState.js";
|
|
5
|
+
export const FEToolsState = createState().build({
|
|
6
|
+
fe_tools: createDefaultAnnotation(() => []),
|
|
7
|
+
});
|
|
8
|
+
export const createFETool = (tool) => {
|
|
9
|
+
return tool;
|
|
10
|
+
};
|
|
11
|
+
export const createFeTools = (tools) => {
|
|
12
|
+
return tools
|
|
13
|
+
.map((tool) => {
|
|
14
|
+
try {
|
|
15
|
+
return actionToTool(tool);
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
console.error(e);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
.filter((tool) => tool !== null);
|
|
23
|
+
};
|
|
24
|
+
export const actionToTool = (tool) => {
|
|
25
|
+
const callTool = async (args) => {
|
|
26
|
+
const data = interrupt(JSON.stringify(args));
|
|
27
|
+
return [data, null];
|
|
28
|
+
};
|
|
29
|
+
const schema = tool.parameters;
|
|
30
|
+
return new DynamicStructuredTool({
|
|
31
|
+
name: tool.name,
|
|
32
|
+
description: tool.description || "",
|
|
33
|
+
schema,
|
|
34
|
+
func: callTool,
|
|
35
|
+
responseFormat: "content_and_artifact",
|
|
36
|
+
});
|
|
37
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AIMessage, HumanMessage } from "@langchain/core/messages";
|
|
2
|
+
export declare class InterruptModal {
|
|
3
|
+
private inputParams;
|
|
4
|
+
constructor(inputParams: {
|
|
5
|
+
action: "prompt" | string;
|
|
6
|
+
});
|
|
7
|
+
rawResponse?: {
|
|
8
|
+
response: string;
|
|
9
|
+
request: {
|
|
10
|
+
message: string;
|
|
11
|
+
action: "prompt" | string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
get response(): {
|
|
15
|
+
answer?: string;
|
|
16
|
+
};
|
|
17
|
+
interrupt(message: string): this;
|
|
18
|
+
isApprove(): string | undefined;
|
|
19
|
+
isReject(): boolean;
|
|
20
|
+
toMessages(options?: {
|
|
21
|
+
AIAskMessage?: boolean;
|
|
22
|
+
}): (false | HumanMessage | AIMessage | undefined)[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AIMessage, HumanMessage } from "@langchain/core/messages";
|
|
2
|
+
import { interrupt } from "@langchain/langgraph";
|
|
3
|
+
export class InterruptModal {
|
|
4
|
+
constructor(inputParams) {
|
|
5
|
+
this.inputParams = inputParams;
|
|
6
|
+
}
|
|
7
|
+
get response() {
|
|
8
|
+
if (!this.rawResponse)
|
|
9
|
+
throw new Error("rawResponse is undefined");
|
|
10
|
+
return JSON.parse(this.rawResponse.response);
|
|
11
|
+
}
|
|
12
|
+
interrupt(message) {
|
|
13
|
+
const inputData = Object.assign({ message }, this.inputParams);
|
|
14
|
+
const input = JSON.stringify(inputData);
|
|
15
|
+
const response = interrupt(input);
|
|
16
|
+
this.rawResponse = {
|
|
17
|
+
request: inputData,
|
|
18
|
+
response,
|
|
19
|
+
};
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
isApprove() {
|
|
23
|
+
return this.response.answer;
|
|
24
|
+
}
|
|
25
|
+
isReject() {
|
|
26
|
+
return !this.response.answer;
|
|
27
|
+
}
|
|
28
|
+
toMessages(options) {
|
|
29
|
+
if (!this.rawResponse)
|
|
30
|
+
throw new Error("rawResponse is undefined");
|
|
31
|
+
return [
|
|
32
|
+
(options === null || options === void 0 ? void 0 : options.AIAskMessage) && new AIMessage(this.rawResponse.request.message),
|
|
33
|
+
new HumanMessage(this.response.answer),
|
|
34
|
+
].filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AnnotationRoot, CompiledStateGraph } from "@langchain/langgraph";
|
|
3
|
+
declare const METADATA_KEY_HANDOFF_DESTINATION = "__handoff_destination";
|
|
4
|
+
interface CreateHandoffToolParams {
|
|
5
|
+
agentName: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
updateState?: (state: any) => Record<string, any>;
|
|
8
|
+
}
|
|
9
|
+
declare const createHandoffTool: ({ agentName, description, updateState }: CreateHandoffToolParams) => import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, {}, {}, any>;
|
|
10
|
+
declare const getHandoffDestinations: <AnnotationRootT extends AnnotationRoot<any>>(agent: CompiledStateGraph<AnnotationRootT["State"], AnnotationRootT["Update"], string, AnnotationRootT["spec"], AnnotationRootT["spec"]>, toolNodeName?: string) => string[];
|
|
11
|
+
export { createHandoffTool, getHandoffDestinations, METADATA_KEY_HANDOFF_DESTINATION };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ToolMessage } from "@langchain/core/messages";
|
|
3
|
+
import { tool } from "@langchain/core/tools";
|
|
4
|
+
import { Command, getCurrentTaskInput, } from "@langchain/langgraph";
|
|
5
|
+
const WHITESPACE_RE = /\s+/g;
|
|
6
|
+
const METADATA_KEY_HANDOFF_DESTINATION = "__handoff_destination";
|
|
7
|
+
function _normalizeAgentName(agentName) {
|
|
8
|
+
/**
|
|
9
|
+
* Normalize an agent name to be used inside the tool name.
|
|
10
|
+
*/
|
|
11
|
+
return agentName.trim().replace(WHITESPACE_RE, "_").toLowerCase();
|
|
12
|
+
}
|
|
13
|
+
// type guard
|
|
14
|
+
function isDynamicTool(tool) {
|
|
15
|
+
return "schema" in tool && "name" in tool && "description" in tool && "responseFormat" in tool;
|
|
16
|
+
}
|
|
17
|
+
const createHandoffTool = ({ agentName, description, updateState }) => {
|
|
18
|
+
/**
|
|
19
|
+
* Create a tool that can handoff control to the requested agent.
|
|
20
|
+
*
|
|
21
|
+
* @param agentName - The name of the agent to handoff control to, i.e.
|
|
22
|
+
* the name of the agent node in the multi-agent graph.
|
|
23
|
+
* Agent names should be simple, clear and unique, preferably in snake_case,
|
|
24
|
+
* although you are only limited to the names accepted by LangGraph
|
|
25
|
+
* nodes as well as the tool names accepted by LLM providers
|
|
26
|
+
* (the tool name will look like this: `transfer_to_<agent_name>`).
|
|
27
|
+
* @param description - Optional description for the handoff tool.
|
|
28
|
+
* @param updateState - Optional function to customize state updates during handoff.
|
|
29
|
+
*/
|
|
30
|
+
const toolName = `transfer_to_${_normalizeAgentName(agentName)}`;
|
|
31
|
+
const toolDescription = description || `Ask agent '${agentName}' for help`;
|
|
32
|
+
const handoffTool = tool(async (_, config) => {
|
|
33
|
+
/**
|
|
34
|
+
* Ask another agent for help.
|
|
35
|
+
*/
|
|
36
|
+
const toolMessage = new ToolMessage({
|
|
37
|
+
content: `Successfully transferred to ${agentName}`,
|
|
38
|
+
name: toolName,
|
|
39
|
+
tool_call_id: config.toolCall.id,
|
|
40
|
+
});
|
|
41
|
+
// inject the current agent state
|
|
42
|
+
const state = getCurrentTaskInput();
|
|
43
|
+
// Base update object containing essential state updates
|
|
44
|
+
const baseUpdate = {
|
|
45
|
+
messages: state.messages.concat(toolMessage),
|
|
46
|
+
activeAgent: agentName,
|
|
47
|
+
};
|
|
48
|
+
// Merge custom updates with base updates if updateState function is provided
|
|
49
|
+
const finalUpdate = updateState ? { ...baseUpdate, ...updateState(state) } : baseUpdate;
|
|
50
|
+
return new Command({
|
|
51
|
+
goto: agentName,
|
|
52
|
+
graph: Command.PARENT,
|
|
53
|
+
update: finalUpdate,
|
|
54
|
+
});
|
|
55
|
+
}, {
|
|
56
|
+
name: toolName,
|
|
57
|
+
schema: z.object({}),
|
|
58
|
+
description: toolDescription,
|
|
59
|
+
});
|
|
60
|
+
handoffTool.metadata = { [METADATA_KEY_HANDOFF_DESTINATION]: agentName };
|
|
61
|
+
return handoffTool;
|
|
62
|
+
};
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const getHandoffDestinations = (agent, toolNodeName = "tools") => {
|
|
65
|
+
/**
|
|
66
|
+
* Get a list of destinations from agent's handoff tools.
|
|
67
|
+
*
|
|
68
|
+
* @param agent - The compiled state graph
|
|
69
|
+
* @param toolNodeName - The name of the tool node in the graph
|
|
70
|
+
*/
|
|
71
|
+
const { nodes } = agent.getGraph();
|
|
72
|
+
if (!(toolNodeName in nodes)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const toolNode = nodes[toolNodeName].data;
|
|
76
|
+
if (!toolNode || !("tools" in toolNode) || !toolNode.tools) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const { tools } = toolNode;
|
|
80
|
+
return tools
|
|
81
|
+
.filter((tool) => isDynamicTool(tool) && tool.metadata !== undefined && METADATA_KEY_HANDOFF_DESTINATION in tool.metadata)
|
|
82
|
+
.map((tool) => tool.metadata[METADATA_KEY_HANDOFF_DESTINATION]);
|
|
83
|
+
};
|
|
84
|
+
export { createHandoffTool, getHandoffDestinations, METADATA_KEY_HANDOFF_DESTINATION };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SwarmState } from "@langchain/langgraph-swarm";
|
|
2
|
+
/**
|
|
3
|
+
* 保留 langgraph-swarm 在 handoff 时丢失的 state
|
|
4
|
+
*/
|
|
5
|
+
export declare const keepAllStateInHandOff: (state: typeof SwarmState.State) => any;
|
|
6
|
+
export declare const createHandoffCommand: <T>(name: string, state: T) => any;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from "@langchain/langgraph";
|
|
2
|
+
/**
|
|
3
|
+
* 保留 langgraph-swarm 在 handoff 时丢失的 state
|
|
4
|
+
*/
|
|
5
|
+
export const keepAllStateInHandOff = (state) => {
|
|
6
|
+
// omit activeAgent and messages
|
|
7
|
+
const { activeAgent, messages, ...rest } = state;
|
|
8
|
+
return {
|
|
9
|
+
...rest,
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export const createHandoffCommand = (name, state) => {
|
|
13
|
+
return new Command({
|
|
14
|
+
goto: name,
|
|
15
|
+
graph: Command.PARENT,
|
|
16
|
+
update: {
|
|
17
|
+
active_agent: name,
|
|
18
|
+
...state,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sequential-thinking.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sequential-thinking.js";
|