@langgraph-js/sdk 3.4.0 → 3.5.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/dist/LangGraphClient.d.ts +21 -9
- package/dist/LangGraphClient.js +15 -20
- package/dist/MessageProcessor.d.ts +8 -20
- package/dist/MessageProcessor.js +48 -80
- package/dist/TestKit.d.ts +3 -3
- package/dist/ToolManager.js +3 -6
- package/dist/artifacts/types.d.ts +5 -1
- package/dist/tool/createTool.d.ts +6 -6
- package/dist/tool/createTool.js +3 -0
- package/package.json +2 -2
- package/src/LangGraphClient.ts +35 -21
- package/src/MessageProcessor.ts +65 -113
- package/src/ToolManager.ts +3 -6
- package/src/tool/createTool.ts +8 -6
|
@@ -18,7 +18,6 @@ export type RenderMessage = Message & {
|
|
|
18
18
|
};
|
|
19
19
|
}[];
|
|
20
20
|
};
|
|
21
|
-
sub_agent_messages?: RenderMessage[];
|
|
22
21
|
usage_metadata?: {
|
|
23
22
|
total_tokens: number;
|
|
24
23
|
input_tokens: number;
|
|
@@ -28,6 +27,7 @@ export type RenderMessage = Message & {
|
|
|
28
27
|
response_metadata?: {
|
|
29
28
|
create_time: string;
|
|
30
29
|
};
|
|
30
|
+
sub_messages?: RenderMessage[];
|
|
31
31
|
/** 耗时 */
|
|
32
32
|
spend_time?: number;
|
|
33
33
|
/** 渲染时的唯一 id,聚合而来*/
|
|
@@ -43,6 +43,20 @@ export type SendMessageOptions = {
|
|
|
43
43
|
command?: Command;
|
|
44
44
|
joinRunId?: string;
|
|
45
45
|
};
|
|
46
|
+
export type InterruptData = {
|
|
47
|
+
id: string;
|
|
48
|
+
value: {
|
|
49
|
+
actionRequests: {
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
args: any;
|
|
53
|
+
}[];
|
|
54
|
+
reviewConfigs: {
|
|
55
|
+
actionName: string;
|
|
56
|
+
allowedDecisions: ("approve" | "edit" | "reject")[];
|
|
57
|
+
}[];
|
|
58
|
+
};
|
|
59
|
+
}[];
|
|
46
60
|
export interface LangGraphClientConfig {
|
|
47
61
|
apiUrl?: string;
|
|
48
62
|
apiKey?: string;
|
|
@@ -119,8 +133,6 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
119
133
|
run_id: string;
|
|
120
134
|
};
|
|
121
135
|
stopController: AbortController | null;
|
|
122
|
-
/** 用于存储 subAgent 状态数据的键 */
|
|
123
|
-
subAgentsKey: string;
|
|
124
136
|
/** Message 处理器 */
|
|
125
137
|
private messageProcessor;
|
|
126
138
|
constructor(config: LangGraphClientConfig);
|
|
@@ -128,14 +140,13 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
128
140
|
get assistants(): {
|
|
129
141
|
search(query?: {
|
|
130
142
|
graphId?: string;
|
|
131
|
-
metadata
|
|
132
|
-
* Specify a custom fetch implementation.
|
|
133
|
-
*
|
|
134
|
-
* By default we expect the `fetch` is available in the global scope.
|
|
135
|
-
*/: import("@langchain/langgraph-sdk").Metadata;
|
|
143
|
+
metadata?: import("@langchain/langgraph-sdk").Metadata;
|
|
136
144
|
limit?: number;
|
|
137
145
|
offset?: number;
|
|
138
|
-
sortBy
|
|
146
|
+
sortBy? /**
|
|
147
|
+
* The maximum number of retries that can be made for a single call,
|
|
148
|
+
* with an exponential backoff between each attempt. Defaults to 6.
|
|
149
|
+
*/: import("@langgraph-js/pure-graph/dist/types.js").AssistantSortBy;
|
|
139
150
|
sortOrder?: import("@langgraph-js/pure-graph/dist/types.js").SortOrder;
|
|
140
151
|
}): Promise<Assistant[]>;
|
|
141
152
|
getGraph(assistantId: string, options?: {
|
|
@@ -223,6 +234,7 @@ export declare class LangGraphClient<TStateType = unknown> extends EventEmitter<
|
|
|
223
234
|
messages: Message[];
|
|
224
235
|
}>;
|
|
225
236
|
messagesMetadata: {};
|
|
237
|
+
humanInTheLoop: InterruptData | null;
|
|
226
238
|
/**
|
|
227
239
|
* @zh 发送消息到 LangGraph 后端。
|
|
228
240
|
* @en Sends a message to the LangGraph backend.
|
package/dist/LangGraphClient.js
CHANGED
|
@@ -15,14 +15,13 @@ export class LangGraphClient extends EventEmitter {
|
|
|
15
15
|
this.availableAssistants = [];
|
|
16
16
|
this.graphState = {};
|
|
17
17
|
this.stopController = null;
|
|
18
|
-
/** 用于存储 subAgent 状态数据的键 */
|
|
19
|
-
this.subAgentsKey = "task_store";
|
|
20
18
|
this.messagesMetadata = {};
|
|
19
|
+
this.humanInTheLoop = null;
|
|
21
20
|
/** 当前子图位置,但是依赖 stream,不太适合稳定使用*/
|
|
22
21
|
this.graphPosition = "";
|
|
23
22
|
this.extraParams = {};
|
|
24
23
|
this.client = config.client;
|
|
25
|
-
this.messageProcessor = new MessageProcessor(
|
|
24
|
+
this.messageProcessor = new MessageProcessor();
|
|
26
25
|
}
|
|
27
26
|
/** 代理 assistants 属性到内部 client */
|
|
28
27
|
get assistants() {
|
|
@@ -210,7 +209,6 @@ export class LangGraphClient extends EventEmitter {
|
|
|
210
209
|
* @en Sends a message to the LangGraph backend.
|
|
211
210
|
*/
|
|
212
211
|
async sendMessage(input, { joinRunId, extraParams, _debug, command } = {}) {
|
|
213
|
-
var _a;
|
|
214
212
|
if (!this.currentAssistant) {
|
|
215
213
|
throw new Error("Thread or Assistant not initialized");
|
|
216
214
|
}
|
|
@@ -277,7 +275,10 @@ export class LangGraphClient extends EventEmitter {
|
|
|
277
275
|
}
|
|
278
276
|
else if (chunk.event === "values") {
|
|
279
277
|
const data = chunk.data;
|
|
280
|
-
if (data.
|
|
278
|
+
if (data.__interrupt__) {
|
|
279
|
+
this.humanInTheLoop = data.__interrupt__;
|
|
280
|
+
}
|
|
281
|
+
else if (data.messages) {
|
|
281
282
|
const isResume = !!(command === null || command === void 0 ? void 0 : command.resume);
|
|
282
283
|
const isLongerThanLocal = data.messages.length >= this.messageProcessor.getGraphMessages().length;
|
|
283
284
|
// resume 情况下,长度低于前端 message 的统统不接受
|
|
@@ -290,10 +291,6 @@ export class LangGraphClient extends EventEmitter {
|
|
|
290
291
|
continue;
|
|
291
292
|
}
|
|
292
293
|
else if (chunk.event.startsWith("values|")) {
|
|
293
|
-
// 这个 values 必然是子 values
|
|
294
|
-
if ((_a = chunk.data) === null || _a === void 0 ? void 0 : _a.messages) {
|
|
295
|
-
this.messageProcessor.mergeSubGraphMessagesToStreamingMessages(chunk.data.messages);
|
|
296
|
-
}
|
|
297
294
|
this.graphPosition = chunk.event.split("|")[1];
|
|
298
295
|
}
|
|
299
296
|
}
|
|
@@ -328,17 +325,15 @@ export class LangGraphClient extends EventEmitter {
|
|
|
328
325
|
// 如果最后一条消息是前端工具消息,则调用工具
|
|
329
326
|
if (lastMessage.type === "ai" && ((_a = lastMessage.tool_calls) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
330
327
|
const result = lastMessage.tool_calls.map((tool) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return this.callFETool(toolMessage, tool.args);
|
|
341
|
-
}
|
|
328
|
+
const toolMessage = {
|
|
329
|
+
...tool,
|
|
330
|
+
tool_call_id: tool.id,
|
|
331
|
+
/** @ts-ignore */
|
|
332
|
+
tool_input: JSON.stringify(tool.args),
|
|
333
|
+
additional_kwargs: {},
|
|
334
|
+
};
|
|
335
|
+
// json 校验
|
|
336
|
+
return this.callFETool(toolMessage, tool.args);
|
|
342
337
|
});
|
|
343
338
|
this.currentThread.status = "interrupted"; // 修复某些机制下,状态不为 interrupted 与后端有差异
|
|
344
339
|
return Promise.all(result);
|
|
@@ -13,12 +13,11 @@ export declare class StreamingMessageType {
|
|
|
13
13
|
* @en The MessageProcessor class is used to uniformly handle Message-related logic and avoid duplicate processing.
|
|
14
14
|
*/
|
|
15
15
|
export declare class MessageProcessor {
|
|
16
|
-
private subAgentsKey;
|
|
17
16
|
/** 流式消息缓存 */
|
|
18
17
|
private streamingMessage;
|
|
19
18
|
/** 图发过来的更新信息 */
|
|
20
19
|
private graphMessages;
|
|
21
|
-
constructor(
|
|
20
|
+
constructor();
|
|
22
21
|
/**
|
|
23
22
|
* @zh 获取流式消息
|
|
24
23
|
* @en Get streaming messages
|
|
@@ -54,11 +53,6 @@ export declare class MessageProcessor {
|
|
|
54
53
|
* @en Combine graphMessages and streamingMessage and return a new message array
|
|
55
54
|
*/
|
|
56
55
|
combineGraphMessagesWithStreamingMessages(): RenderMessage[];
|
|
57
|
-
/**
|
|
58
|
-
* @zh 子图的数据需要通过 merge 的方式重新进行合并更新
|
|
59
|
-
* @en Subgraph data needs to be merged and updated through merge method
|
|
60
|
-
*/
|
|
61
|
-
mergeSubGraphMessagesToStreamingMessages(messages: Message[]): void;
|
|
62
56
|
/**
|
|
63
57
|
* @zh 克隆消息对象
|
|
64
58
|
* @en Clone message object
|
|
@@ -74,27 +68,21 @@ export declare class MessageProcessor {
|
|
|
74
68
|
* @en Composes tool messages, associating AI tool calls with tool execution results.
|
|
75
69
|
*/
|
|
76
70
|
composeToolMessages(messages: RenderMessage[]): RenderMessage[];
|
|
77
|
-
/**
|
|
78
|
-
* @zh 转换 subAgent 消息为工具的子消息
|
|
79
|
-
* @en Convert subAgent messages to tool sub-messages
|
|
80
|
-
*/
|
|
81
|
-
convertSubAgentMessages(messages: RenderMessage[], graphState: any, messagesMetadata: Record<string, {
|
|
82
|
-
subagent_id?: string;
|
|
83
|
-
}>): RenderMessage[];
|
|
84
71
|
/**
|
|
85
72
|
* @zh 生成用于 UI 中的流式渲染的消息
|
|
86
73
|
* @en Generate messages used for streaming rendering in the UI
|
|
87
74
|
*/
|
|
88
75
|
renderMessages(graphState: any, getGraphNodeNow: () => {
|
|
89
76
|
name: string;
|
|
90
|
-
}, messagesMetadata: Record<string,
|
|
91
|
-
|
|
92
|
-
|
|
77
|
+
}, messagesMetadata: Record<string, any>): RenderMessage[];
|
|
78
|
+
foldTreeMessages(messages: RenderMessage[], graphState?: {
|
|
79
|
+
task_store?: Record<string, {
|
|
80
|
+
messages: RenderMessage[];
|
|
81
|
+
}>;
|
|
82
|
+
}, messagesMetadata?: Record<string, any>): RenderMessage[];
|
|
93
83
|
/**
|
|
94
84
|
* @zh 统一的消息处理入口,按顺序执行所有处理步骤
|
|
95
85
|
* @en Unified message processing entry point, executing all processing steps in order
|
|
96
86
|
*/
|
|
97
|
-
processMessages(messages: RenderMessage[], graphState
|
|
98
|
-
subagent_id?: string;
|
|
99
|
-
}>): RenderMessage[];
|
|
87
|
+
processMessages(messages: RenderMessage[], graphState?: any, messagesMetadata?: Record<string, any>): RenderMessage[];
|
|
100
88
|
}
|
package/dist/MessageProcessor.js
CHANGED
|
@@ -17,12 +17,11 @@ export class StreamingMessageType {
|
|
|
17
17
|
* @en The MessageProcessor class is used to uniformly handle Message-related logic and avoid duplicate processing.
|
|
18
18
|
*/
|
|
19
19
|
export class MessageProcessor {
|
|
20
|
-
constructor(
|
|
20
|
+
constructor() {
|
|
21
21
|
/** 流式消息缓存 */
|
|
22
22
|
this.streamingMessage = [];
|
|
23
23
|
/** 图发过来的更新信息 */
|
|
24
24
|
this.graphMessages = [];
|
|
25
|
-
this.subAgentsKey = subAgentsKey;
|
|
26
25
|
}
|
|
27
26
|
/**
|
|
28
27
|
* @zh 获取流式消息
|
|
@@ -89,26 +88,6 @@ export class MessageProcessor {
|
|
|
89
88
|
...idMap.values(),
|
|
90
89
|
];
|
|
91
90
|
}
|
|
92
|
-
/**
|
|
93
|
-
* @zh 子图的数据需要通过 merge 的方式重新进行合并更新
|
|
94
|
-
* @en Subgraph data needs to be merged and updated through merge method
|
|
95
|
-
*/
|
|
96
|
-
mergeSubGraphMessagesToStreamingMessages(messages) {
|
|
97
|
-
const map = new Map(messages.filter((i) => i.id).map((i) => [i.id, i]));
|
|
98
|
-
this.streamingMessage.forEach((i) => {
|
|
99
|
-
if (map.has(i.id)) {
|
|
100
|
-
const newValue = map.get(i.id);
|
|
101
|
-
Object.assign(i, newValue);
|
|
102
|
-
map.delete(i.id);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
// 剩余的 message 一定不在 streamMessage 中
|
|
106
|
-
map.forEach((i) => {
|
|
107
|
-
if (i.type === "tool" && i.tool_call_id) {
|
|
108
|
-
this.streamingMessage.push(i);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
91
|
/**
|
|
113
92
|
* @zh 克隆消息对象
|
|
114
93
|
* @en Clone message object
|
|
@@ -190,59 +169,6 @@ export class MessageProcessor {
|
|
|
190
169
|
}
|
|
191
170
|
return result;
|
|
192
171
|
}
|
|
193
|
-
/**
|
|
194
|
-
* @zh 转换 subAgent 消息为工具的子消息
|
|
195
|
-
* @en Convert subAgent messages to tool sub-messages
|
|
196
|
-
*/
|
|
197
|
-
convertSubAgentMessages(messages, graphState, messagesMetadata) {
|
|
198
|
-
const origin_task_store = graphState[this.subAgentsKey];
|
|
199
|
-
if (!origin_task_store)
|
|
200
|
-
return messages;
|
|
201
|
-
const task_store = JSON.parse(JSON.stringify(origin_task_store));
|
|
202
|
-
/** 获取 subAgent 消息的 id,用于流式过程中对数据进行标记 */
|
|
203
|
-
messages
|
|
204
|
-
.filter((i) => {
|
|
205
|
-
var _a, _b;
|
|
206
|
-
return ((_a = messagesMetadata[i.id]) === null || _a === void 0 ? void 0 : _a.subagent_id) || ((_b = i.node_name) === null || _b === void 0 ? void 0 : _b.startsWith("subagent_"));
|
|
207
|
-
})
|
|
208
|
-
.forEach((i) => {
|
|
209
|
-
var _a;
|
|
210
|
-
const tool_call_id = ((_a = messagesMetadata[i.id]) === null || _a === void 0 ? void 0 : _a.subagent_id) || i.node_name.replace("subagent_", "");
|
|
211
|
-
const store = task_store[tool_call_id];
|
|
212
|
-
if (store) {
|
|
213
|
-
// 根据 id 进行去重
|
|
214
|
-
const exists = store.messages.some((msg) => msg.id === i.id);
|
|
215
|
-
if (!exists) {
|
|
216
|
-
store.messages.push(i);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
task_store[tool_call_id] = {
|
|
221
|
-
messages: [i],
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
const ignoreIds = new Set();
|
|
226
|
-
Object.values(task_store).forEach((task) => {
|
|
227
|
-
task.messages.forEach((message) => {
|
|
228
|
-
ignoreIds.add(message.id);
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
const result = [];
|
|
232
|
-
for (const message of messages) {
|
|
233
|
-
if (message.type === "tool" && message.tool_call_id) {
|
|
234
|
-
const task = task_store[message.tool_call_id];
|
|
235
|
-
if (task) {
|
|
236
|
-
// 递归处理子消息,但避免重复处理
|
|
237
|
-
message.sub_agent_messages = this.processMessages(task.messages, task, messagesMetadata);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (message.id && ignoreIds.has(message.id))
|
|
241
|
-
continue;
|
|
242
|
-
result.push(message);
|
|
243
|
-
}
|
|
244
|
-
return result;
|
|
245
|
-
}
|
|
246
172
|
/**
|
|
247
173
|
* @zh 生成用于 UI 中的流式渲染的消息
|
|
248
174
|
* @en Generate messages used for streaming rendering in the UI
|
|
@@ -307,6 +233,51 @@ export class MessageProcessor {
|
|
|
307
233
|
}
|
|
308
234
|
return this.processMessages(result, graphState, messagesMetadata);
|
|
309
235
|
}
|
|
236
|
+
foldTreeMessages(messages, graphState, messagesMetadata) {
|
|
237
|
+
const state_sub_messages = Object.entries((graphState === null || graphState === void 0 ? void 0 : graphState.task_store) || {}).map(([key, value]) => [key, value.messages]);
|
|
238
|
+
const state_sub_messages_map = new Map(state_sub_messages);
|
|
239
|
+
const nonRootMessageId = new Set();
|
|
240
|
+
const parentPointer = new Map(Object.entries(messagesMetadata || {})
|
|
241
|
+
.map(([childId, metadata]) => {
|
|
242
|
+
if (metadata === null || metadata === void 0 ? void 0 : metadata.parent_id) {
|
|
243
|
+
nonRootMessageId.add(childId);
|
|
244
|
+
return [childId, metadata === null || metadata === void 0 ? void 0 : metadata.parent_id];
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
})
|
|
248
|
+
.filter((i) => i !== undefined));
|
|
249
|
+
// 第一遍遍历:构建 childrenMap,将子消息归类到父消息下
|
|
250
|
+
const childrenMap = state_sub_messages_map;
|
|
251
|
+
const rootMessages = [];
|
|
252
|
+
for (const message of messages) {
|
|
253
|
+
const isRoot = !nonRootMessageId.has(message.id);
|
|
254
|
+
if (!isRoot) {
|
|
255
|
+
// 处理子消息
|
|
256
|
+
const parentId = parentPointer.get(message.id);
|
|
257
|
+
const children = childrenMap.get(parentId);
|
|
258
|
+
if (children) {
|
|
259
|
+
children.push(message);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
childrenMap.set(parentId, [message]);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
// 收集根消息
|
|
267
|
+
rootMessages.push(message);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// 第二遍遍历:为所有根消息赋值 sub_messages
|
|
271
|
+
for (const rootMessage of rootMessages) {
|
|
272
|
+
rootMessage.sub_messages = childrenMap.get(rootMessage.id) || [];
|
|
273
|
+
if (rootMessage.type === "tool" && childrenMap.has(rootMessage.tool_call_id)) {
|
|
274
|
+
rootMessage.sub_messages.unshift(...childrenMap.get(rootMessage.tool_call_id));
|
|
275
|
+
// 根据 id 去重
|
|
276
|
+
rootMessage.sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return rootMessages;
|
|
280
|
+
}
|
|
310
281
|
/**
|
|
311
282
|
* @zh 统一的消息处理入口,按顺序执行所有处理步骤
|
|
312
283
|
* @en Unified message processing entry point, executing all processing steps in order
|
|
@@ -316,10 +287,7 @@ export class MessageProcessor {
|
|
|
316
287
|
const composedMessages = this.composeToolMessages(messages);
|
|
317
288
|
// 2. 附加信息
|
|
318
289
|
const messagesWithInfo = this.attachInfoForMessage(composedMessages);
|
|
319
|
-
// 3.
|
|
320
|
-
|
|
321
|
-
return this.convertSubAgentMessages(messagesWithInfo, graphState, messagesMetadata);
|
|
322
|
-
}
|
|
323
|
-
return messagesWithInfo;
|
|
290
|
+
// 3. 折叠树状消息(如果提供了 messagesMetadata)
|
|
291
|
+
return this.foldTreeMessages(messagesWithInfo, graphState, messagesMetadata);
|
|
324
292
|
}
|
|
325
293
|
}
|
package/dist/TestKit.d.ts
CHANGED
|
@@ -178,7 +178,6 @@ export declare class TestLangGraphChat {
|
|
|
178
178
|
};
|
|
179
179
|
}[];
|
|
180
180
|
};
|
|
181
|
-
sub_agent_messages?: RenderMessage[];
|
|
182
181
|
usage_metadata?: {
|
|
183
182
|
total_tokens: number;
|
|
184
183
|
input_tokens: number;
|
|
@@ -188,6 +187,7 @@ export declare class TestLangGraphChat {
|
|
|
188
187
|
response_metadata?: {
|
|
189
188
|
create_time: string;
|
|
190
189
|
};
|
|
190
|
+
sub_messages?: RenderMessage[];
|
|
191
191
|
spend_time?: number;
|
|
192
192
|
unique_id?: string;
|
|
193
193
|
done?: boolean;
|
|
@@ -252,7 +252,6 @@ export declare class TestLangGraphChat {
|
|
|
252
252
|
};
|
|
253
253
|
}[];
|
|
254
254
|
};
|
|
255
|
-
sub_agent_messages?: RenderMessage[];
|
|
256
255
|
usage_metadata?: {
|
|
257
256
|
total_tokens: number;
|
|
258
257
|
input_tokens: number;
|
|
@@ -262,6 +261,7 @@ export declare class TestLangGraphChat {
|
|
|
262
261
|
response_metadata?: {
|
|
263
262
|
create_time: string;
|
|
264
263
|
};
|
|
264
|
+
sub_messages?: RenderMessage[];
|
|
265
265
|
spend_time?: number;
|
|
266
266
|
unique_id?: string;
|
|
267
267
|
done?: boolean;
|
|
@@ -299,7 +299,6 @@ export declare class TestLangGraphChat {
|
|
|
299
299
|
};
|
|
300
300
|
}[];
|
|
301
301
|
};
|
|
302
|
-
sub_agent_messages?: RenderMessage[];
|
|
303
302
|
usage_metadata?: {
|
|
304
303
|
total_tokens: number;
|
|
305
304
|
input_tokens: number;
|
|
@@ -309,6 +308,7 @@ export declare class TestLangGraphChat {
|
|
|
309
308
|
response_metadata?: {
|
|
310
309
|
create_time: string;
|
|
311
310
|
};
|
|
311
|
+
sub_messages?: RenderMessage[];
|
|
312
312
|
spend_time?: number;
|
|
313
313
|
unique_id?: string;
|
|
314
314
|
done?: boolean;
|
package/dist/ToolManager.js
CHANGED
|
@@ -14,8 +14,8 @@ export class ToolManager {
|
|
|
14
14
|
* @en Registers a tool.
|
|
15
15
|
*/
|
|
16
16
|
bindTool(tool) {
|
|
17
|
-
if (this.tools.has(tool.name)) {
|
|
18
|
-
|
|
17
|
+
if (this.tools.has(tool.name) && tool.name !== "__default__") {
|
|
18
|
+
console.warn(`Tool with name ${tool.name} already exists`);
|
|
19
19
|
}
|
|
20
20
|
this.tools.set(tool.name, tool);
|
|
21
21
|
}
|
|
@@ -67,10 +67,7 @@ export class ToolManager {
|
|
|
67
67
|
*/
|
|
68
68
|
async callTool(name, args, context) {
|
|
69
69
|
var _a;
|
|
70
|
-
const tool = this.getTool(name);
|
|
71
|
-
if (!tool) {
|
|
72
|
-
throw new Error(`Tool with name ${name} not found`);
|
|
73
|
-
}
|
|
70
|
+
const tool = this.getTool(name) || this.getTool("__default__");
|
|
74
71
|
return await ((_a = tool.execute) === null || _a === void 0 ? void 0 : _a.call(tool, args, context));
|
|
75
72
|
}
|
|
76
73
|
/**
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const ArtifactCommandSchema: {
|
|
3
|
-
command: z.ZodEnum<
|
|
3
|
+
command: z.ZodEnum<{
|
|
4
|
+
create: "create";
|
|
5
|
+
update: "update";
|
|
6
|
+
rewrite: "rewrite";
|
|
7
|
+
}>;
|
|
4
8
|
id: z.ZodString;
|
|
5
9
|
title: z.ZodString;
|
|
6
10
|
type: z.ZodString;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z, ZodRawShape
|
|
1
|
+
import { z, ZodRawShape } from "zod";
|
|
2
2
|
import { Action, Parameter } from "./copilotkit-actions.js";
|
|
3
3
|
import { Message } from "@langchain/langgraph-sdk";
|
|
4
4
|
import { ToolRenderData } from "./ToolUI.js";
|
|
@@ -11,8 +11,8 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
|
|
|
11
11
|
execute?: ToolCallback<Args>;
|
|
12
12
|
/** 工具执行成功后触发的附加消息 */
|
|
13
13
|
callbackMessage?: (result: CallToolResult) => Message[];
|
|
14
|
-
handler?: (args: z.
|
|
15
|
-
render?: (tool: ToolRenderData<z.
|
|
14
|
+
handler?: (args: z.infer<z.ZodObject<Args>>, context?: any) => ResponseType | Promise<ResponseType>;
|
|
15
|
+
render?: (tool: ToolRenderData<z.infer<z.ZodObject<Args>>, ResponseType>) => Child;
|
|
16
16
|
onlyRender?: boolean;
|
|
17
17
|
/** 只允许指定的 agent 使用该工具,如果未指定,则所有 agent 都可以使用 */
|
|
18
18
|
allowAgent?: string[];
|
|
@@ -21,7 +21,7 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
|
|
|
21
21
|
/** 是否是纯净的 json schema 参数,而不是 zod 参数 */
|
|
22
22
|
isPureParams?: boolean;
|
|
23
23
|
}
|
|
24
|
-
export type ToolCallback<Args extends ZodRawShape> = (args: z.
|
|
24
|
+
export type ToolCallback<Args extends ZodRawShape> = (args: z.infer<z.ZodObject<Args>>, context?: any) => CallToolResult | Promise<CallToolResult>;
|
|
25
25
|
export type CallToolResult = string | {
|
|
26
26
|
type: "text";
|
|
27
27
|
text: string;
|
|
@@ -70,7 +70,7 @@ export declare const createJSONDefineTool: <Args extends ZodRawShape>(tool: Unio
|
|
|
70
70
|
[key: string]: import("zod-to-json-schema").JsonSchema7Type;
|
|
71
71
|
} | undefined;
|
|
72
72
|
}) | ({
|
|
73
|
-
type: ("string" | "number" | "boolean" | "
|
|
73
|
+
type: ("string" | "number" | "boolean" | "null" | "integer") | ("string" | "number" | "boolean" | "null" | "integer")[];
|
|
74
74
|
} & {
|
|
75
75
|
title?: string;
|
|
76
76
|
default?: any;
|
|
@@ -149,7 +149,7 @@ export declare const createJSONDefineTool: <Args extends ZodRawShape>(tool: Unio
|
|
|
149
149
|
} | undefined;
|
|
150
150
|
});
|
|
151
151
|
};
|
|
152
|
-
export declare const createMCPTool: <Args extends ZodRawShape>(tool: UnionTool<Args>) => (string | Args | ((args: z.
|
|
152
|
+
export declare const createMCPTool: <Args extends ZodRawShape>(tool: UnionTool<Args>) => (string | Args | ((args: z.infer<z.ZodObject<Args>>) => Promise<{
|
|
153
153
|
content: {
|
|
154
154
|
type: string;
|
|
155
155
|
text: string;
|
package/dist/tool/createTool.js
CHANGED
|
@@ -17,6 +17,9 @@ export const createUITool = (tool) => {
|
|
|
17
17
|
if (typeof result === "string") {
|
|
18
18
|
return [{ type: "text", text: result }];
|
|
19
19
|
}
|
|
20
|
+
else if (result.decisions) {
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
20
23
|
return [{ type: "text", text: JSON.stringify(result) }];
|
|
21
24
|
}
|
|
22
25
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langgraph-js/sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.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",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"jsonrepair": "^3.12.0",
|
|
50
50
|
"nanostores": "^1.0.1",
|
|
51
51
|
"ts-debounce": "^4.0.0",
|
|
52
|
-
"zod": "^
|
|
52
|
+
"zod": "^4",
|
|
53
53
|
"zod-to-json-schema": "^3.24.5"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
package/src/LangGraphClient.ts
CHANGED
|
@@ -21,7 +21,6 @@ export type RenderMessage = Message & {
|
|
|
21
21
|
};
|
|
22
22
|
}[];
|
|
23
23
|
};
|
|
24
|
-
sub_agent_messages?: RenderMessage[];
|
|
25
24
|
usage_metadata?: {
|
|
26
25
|
total_tokens: number;
|
|
27
26
|
input_tokens: number;
|
|
@@ -31,6 +30,8 @@ export type RenderMessage = Message & {
|
|
|
31
30
|
response_metadata?: {
|
|
32
31
|
create_time: string;
|
|
33
32
|
};
|
|
33
|
+
// 子消息
|
|
34
|
+
sub_messages?: RenderMessage[];
|
|
34
35
|
/** 耗时 */
|
|
35
36
|
spend_time?: number;
|
|
36
37
|
/** 渲染时的唯一 id,聚合而来*/
|
|
@@ -44,6 +45,20 @@ export type SendMessageOptions = {
|
|
|
44
45
|
command?: Command;
|
|
45
46
|
joinRunId?: string;
|
|
46
47
|
};
|
|
48
|
+
export type InterruptData = {
|
|
49
|
+
id: string;
|
|
50
|
+
value: {
|
|
51
|
+
actionRequests: {
|
|
52
|
+
name: string;
|
|
53
|
+
description: string;
|
|
54
|
+
args: any;
|
|
55
|
+
}[];
|
|
56
|
+
reviewConfigs: {
|
|
57
|
+
actionName: string;
|
|
58
|
+
allowedDecisions: ("approve" | "edit" | "reject")[];
|
|
59
|
+
}[];
|
|
60
|
+
};
|
|
61
|
+
}[];
|
|
47
62
|
export interface LangGraphClientConfig {
|
|
48
63
|
apiUrl?: string;
|
|
49
64
|
apiKey?: string;
|
|
@@ -101,15 +116,13 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
101
116
|
graphState: any = {};
|
|
102
117
|
currentRun?: { run_id: string };
|
|
103
118
|
stopController: AbortController | null = null;
|
|
104
|
-
/** 用于存储 subAgent 状态数据的键 */
|
|
105
|
-
subAgentsKey = "task_store";
|
|
106
119
|
/** Message 处理器 */
|
|
107
120
|
private messageProcessor: MessageProcessor;
|
|
108
121
|
|
|
109
122
|
constructor(config: LangGraphClientConfig) {
|
|
110
123
|
super();
|
|
111
124
|
this.client = config.client;
|
|
112
|
-
this.messageProcessor = new MessageProcessor(
|
|
125
|
+
this.messageProcessor = new MessageProcessor();
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
/** 代理 assistants 属性到内部 client */
|
|
@@ -305,6 +318,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
305
318
|
return state;
|
|
306
319
|
}
|
|
307
320
|
public messagesMetadata = {};
|
|
321
|
+
public humanInTheLoop: InterruptData | null = null;
|
|
308
322
|
/**
|
|
309
323
|
* @zh 发送消息到 LangGraph 后端。
|
|
310
324
|
* @en Sends a message to the LangGraph backend.
|
|
@@ -358,6 +372,7 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
358
372
|
this.emit("start", {
|
|
359
373
|
event: "start",
|
|
360
374
|
});
|
|
375
|
+
|
|
361
376
|
for await (const chunk of streamResponse) {
|
|
362
377
|
streamRecord.push(chunk);
|
|
363
378
|
if (chunk.event === "metadata") {
|
|
@@ -374,9 +389,14 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
374
389
|
this.emit("message", chunk);
|
|
375
390
|
continue;
|
|
376
391
|
} else if (chunk.event === "values") {
|
|
377
|
-
const data = chunk.data as {
|
|
392
|
+
const data = chunk.data as {
|
|
393
|
+
__interrupt__?: InterruptData;
|
|
394
|
+
messages: Message[];
|
|
395
|
+
};
|
|
378
396
|
|
|
379
|
-
if (data.
|
|
397
|
+
if (data.__interrupt__) {
|
|
398
|
+
this.humanInTheLoop = data.__interrupt__;
|
|
399
|
+
} else if (data.messages) {
|
|
380
400
|
const isResume = !!command?.resume;
|
|
381
401
|
const isLongerThanLocal = data.messages.length >= this.messageProcessor.getGraphMessages().length;
|
|
382
402
|
// resume 情况下,长度低于前端 message 的统统不接受
|
|
@@ -388,10 +408,6 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
388
408
|
}
|
|
389
409
|
continue;
|
|
390
410
|
} else if (chunk.event.startsWith("values|")) {
|
|
391
|
-
// 这个 values 必然是子 values
|
|
392
|
-
if (chunk.data?.messages) {
|
|
393
|
-
this.messageProcessor.mergeSubGraphMessagesToStreamingMessages(chunk.data.messages);
|
|
394
|
-
}
|
|
395
411
|
this.graphPosition = chunk.event.split("|")[1];
|
|
396
412
|
}
|
|
397
413
|
}
|
|
@@ -426,17 +442,15 @@ export class LangGraphClient<TStateType = unknown> extends EventEmitter<LangGrap
|
|
|
426
442
|
// 如果最后一条消息是前端工具消息,则调用工具
|
|
427
443
|
if (lastMessage.type === "ai" && lastMessage.tool_calls?.length) {
|
|
428
444
|
const result = lastMessage.tool_calls.map((tool) => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return this.callFETool(toolMessage, tool.args);
|
|
439
|
-
}
|
|
445
|
+
const toolMessage: ToolMessage = {
|
|
446
|
+
...tool,
|
|
447
|
+
tool_call_id: tool.id!,
|
|
448
|
+
/** @ts-ignore */
|
|
449
|
+
tool_input: JSON.stringify(tool.args),
|
|
450
|
+
additional_kwargs: {},
|
|
451
|
+
};
|
|
452
|
+
// json 校验
|
|
453
|
+
return this.callFETool(toolMessage, tool.args);
|
|
440
454
|
});
|
|
441
455
|
this.currentThread!.status = "interrupted"; // 修复某些机制下,状态不为 interrupted 与后端有差异
|
|
442
456
|
return Promise.all(result);
|
package/src/MessageProcessor.ts
CHANGED
|
@@ -21,15 +21,12 @@ export class StreamingMessageType {
|
|
|
21
21
|
* @en The MessageProcessor class is used to uniformly handle Message-related logic and avoid duplicate processing.
|
|
22
22
|
*/
|
|
23
23
|
export class MessageProcessor {
|
|
24
|
-
private subAgentsKey: string;
|
|
25
24
|
/** 流式消息缓存 */
|
|
26
25
|
private streamingMessage: RenderMessage[] = [];
|
|
27
26
|
/** 图发过来的更新信息 */
|
|
28
27
|
private graphMessages: RenderMessage[] = [];
|
|
29
28
|
|
|
30
|
-
constructor(
|
|
31
|
-
this.subAgentsKey = subAgentsKey;
|
|
32
|
-
}
|
|
29
|
+
constructor() {}
|
|
33
30
|
|
|
34
31
|
/**
|
|
35
32
|
* @zh 获取流式消息
|
|
@@ -103,27 +100,6 @@ export class MessageProcessor {
|
|
|
103
100
|
];
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
/**
|
|
107
|
-
* @zh 子图的数据需要通过 merge 的方式重新进行合并更新
|
|
108
|
-
* @en Subgraph data needs to be merged and updated through merge method
|
|
109
|
-
*/
|
|
110
|
-
mergeSubGraphMessagesToStreamingMessages(messages: Message[]): void {
|
|
111
|
-
const map = new Map(messages.filter((i) => i.id).map((i) => [i.id!, i]));
|
|
112
|
-
this.streamingMessage.forEach((i) => {
|
|
113
|
-
if (map.has(i.id!)) {
|
|
114
|
-
const newValue = map.get(i.id!)!;
|
|
115
|
-
Object.assign(i, newValue);
|
|
116
|
-
map.delete(i.id!);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
// 剩余的 message 一定不在 streamMessage 中
|
|
120
|
-
map.forEach((i) => {
|
|
121
|
-
if (i.type === "tool" && i.tool_call_id) {
|
|
122
|
-
this.streamingMessage.push(i as RenderMessage);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
103
|
/**
|
|
128
104
|
* @zh 克隆消息对象
|
|
129
105
|
* @en Clone message object
|
|
@@ -212,82 +188,11 @@ export class MessageProcessor {
|
|
|
212
188
|
return result;
|
|
213
189
|
}
|
|
214
190
|
|
|
215
|
-
/**
|
|
216
|
-
* @zh 转换 subAgent 消息为工具的子消息
|
|
217
|
-
* @en Convert subAgent messages to tool sub-messages
|
|
218
|
-
*/
|
|
219
|
-
convertSubAgentMessages(
|
|
220
|
-
messages: RenderMessage[],
|
|
221
|
-
graphState: any,
|
|
222
|
-
messagesMetadata: Record<
|
|
223
|
-
string,
|
|
224
|
-
{
|
|
225
|
-
subagent_id?: string;
|
|
226
|
-
}
|
|
227
|
-
>
|
|
228
|
-
): RenderMessage[] {
|
|
229
|
-
const origin_task_store = graphState[this.subAgentsKey];
|
|
230
|
-
if (!origin_task_store) return messages;
|
|
231
|
-
|
|
232
|
-
const task_store = JSON.parse(JSON.stringify(origin_task_store));
|
|
233
|
-
|
|
234
|
-
/** 获取 subAgent 消息的 id,用于流式过程中对数据进行标记 */
|
|
235
|
-
messages
|
|
236
|
-
.filter((i) => {
|
|
237
|
-
return messagesMetadata[i.id!]?.subagent_id || i.node_name?.startsWith("subagent_");
|
|
238
|
-
})
|
|
239
|
-
.forEach((i) => {
|
|
240
|
-
const tool_call_id = messagesMetadata[i.id!]?.subagent_id || i.node_name!.replace("subagent_", "");
|
|
241
|
-
const store = task_store[tool_call_id];
|
|
242
|
-
if (store) {
|
|
243
|
-
// 根据 id 进行去重
|
|
244
|
-
const exists = (store.messages as RenderMessage[]).some((msg) => msg.id === i.id);
|
|
245
|
-
if (!exists) {
|
|
246
|
-
(store.messages as RenderMessage[]).push(i);
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
task_store[tool_call_id] = {
|
|
250
|
-
messages: [i],
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
const ignoreIds = new Set<string>();
|
|
256
|
-
Object.values(task_store).forEach((task: any) => {
|
|
257
|
-
task.messages.forEach((message: RenderMessage) => {
|
|
258
|
-
ignoreIds.add(message.id!);
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
const result: RenderMessage[] = [];
|
|
263
|
-
for (const message of messages) {
|
|
264
|
-
if (message.type === "tool" && message.tool_call_id) {
|
|
265
|
-
const task = task_store[message.tool_call_id];
|
|
266
|
-
if (task) {
|
|
267
|
-
// 递归处理子消息,但避免重复处理
|
|
268
|
-
message.sub_agent_messages = this.processMessages(task.messages, task, messagesMetadata);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
if (message.id && ignoreIds.has(message.id)) continue;
|
|
272
|
-
result.push(message);
|
|
273
|
-
}
|
|
274
|
-
return result;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
191
|
/**
|
|
278
192
|
* @zh 生成用于 UI 中的流式渲染的消息
|
|
279
193
|
* @en Generate messages used for streaming rendering in the UI
|
|
280
194
|
*/
|
|
281
|
-
renderMessages(
|
|
282
|
-
graphState: any,
|
|
283
|
-
getGraphNodeNow: () => { name: string },
|
|
284
|
-
messagesMetadata: Record<
|
|
285
|
-
string,
|
|
286
|
-
{
|
|
287
|
-
subagent_id?: string;
|
|
288
|
-
}
|
|
289
|
-
>
|
|
290
|
-
): RenderMessage[] {
|
|
195
|
+
renderMessages(graphState: any, getGraphNodeNow: () => { name: string }, messagesMetadata: Record<string, any>): RenderMessage[] {
|
|
291
196
|
const previousMessage = new Map<string, Message>();
|
|
292
197
|
const closedToolCallIds = new Set<string>();
|
|
293
198
|
const result: Message[] = [];
|
|
@@ -349,31 +254,78 @@ export class MessageProcessor {
|
|
|
349
254
|
return this.processMessages(result as RenderMessage[], graphState, messagesMetadata);
|
|
350
255
|
}
|
|
351
256
|
|
|
257
|
+
foldTreeMessages(
|
|
258
|
+
messages: RenderMessage[],
|
|
259
|
+
graphState?: {
|
|
260
|
+
task_store?: Record<
|
|
261
|
+
string,
|
|
262
|
+
{
|
|
263
|
+
messages: RenderMessage[];
|
|
264
|
+
}
|
|
265
|
+
>;
|
|
266
|
+
},
|
|
267
|
+
messagesMetadata?: Record<string, any>
|
|
268
|
+
): RenderMessage[] {
|
|
269
|
+
const state_sub_messages = Object.entries(graphState?.task_store || {}).map(([key, value]) => [key, value.messages] as [string, RenderMessage[]]);
|
|
270
|
+
const state_sub_messages_map = new Map<string, RenderMessage[]>(state_sub_messages);
|
|
271
|
+
|
|
272
|
+
const nonRootMessageId = new Set<string>();
|
|
273
|
+
const parentPointer = new Map(
|
|
274
|
+
Object.entries(messagesMetadata || {})
|
|
275
|
+
.map(([childId, metadata]) => {
|
|
276
|
+
if (metadata?.parent_id) {
|
|
277
|
+
nonRootMessageId.add(childId);
|
|
278
|
+
return [childId, metadata?.parent_id];
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
})
|
|
282
|
+
.filter((i): i is [string, string] => i !== undefined)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// 第一遍遍历:构建 childrenMap,将子消息归类到父消息下
|
|
286
|
+
const childrenMap = state_sub_messages_map;
|
|
287
|
+
const rootMessages: RenderMessage[] = [];
|
|
288
|
+
|
|
289
|
+
for (const message of messages) {
|
|
290
|
+
const isRoot = !nonRootMessageId.has(message.id!);
|
|
291
|
+
if (!isRoot) {
|
|
292
|
+
// 处理子消息
|
|
293
|
+
const parentId = parentPointer.get(message.id!)!;
|
|
294
|
+
const children = childrenMap.get(parentId);
|
|
295
|
+
if (children) {
|
|
296
|
+
children.push(message);
|
|
297
|
+
} else {
|
|
298
|
+
childrenMap.set(parentId, [message]);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
// 收集根消息
|
|
302
|
+
rootMessages.push(message);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// 第二遍遍历:为所有根消息赋值 sub_messages
|
|
307
|
+
for (const rootMessage of rootMessages) {
|
|
308
|
+
rootMessage.sub_messages = childrenMap.get(rootMessage.id!) || [];
|
|
309
|
+
if (rootMessage.type === "tool" && childrenMap.has(rootMessage.tool_call_id)) {
|
|
310
|
+
rootMessage.sub_messages.unshift(...childrenMap.get(rootMessage.tool_call_id)!);
|
|
311
|
+
// 根据 id 去重
|
|
312
|
+
rootMessage.sub_messages = rootMessage.sub_messages.filter((i, index, self) => self.findIndex((t) => t.id === i.id) === index);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return rootMessages;
|
|
316
|
+
}
|
|
352
317
|
/**
|
|
353
318
|
* @zh 统一的消息处理入口,按顺序执行所有处理步骤
|
|
354
319
|
* @en Unified message processing entry point, executing all processing steps in order
|
|
355
320
|
*/
|
|
356
|
-
processMessages(
|
|
357
|
-
messages: RenderMessage[],
|
|
358
|
-
graphState: any,
|
|
359
|
-
messagesMetadata: Record<
|
|
360
|
-
string,
|
|
361
|
-
{
|
|
362
|
-
subagent_id?: string;
|
|
363
|
-
}
|
|
364
|
-
>
|
|
365
|
-
): RenderMessage[] {
|
|
321
|
+
processMessages(messages: RenderMessage[], graphState?: any, messagesMetadata?: Record<string, any>): RenderMessage[] {
|
|
366
322
|
// 1. 组合工具消息
|
|
367
323
|
const composedMessages = this.composeToolMessages(messages);
|
|
368
324
|
|
|
369
325
|
// 2. 附加信息
|
|
370
326
|
const messagesWithInfo = this.attachInfoForMessage(composedMessages);
|
|
371
327
|
|
|
372
|
-
// 3.
|
|
373
|
-
|
|
374
|
-
return this.convertSubAgentMessages(messagesWithInfo, graphState, messagesMetadata);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return messagesWithInfo;
|
|
328
|
+
// 3. 折叠树状消息(如果提供了 messagesMetadata)
|
|
329
|
+
return this.foldTreeMessages(messagesWithInfo, graphState, messagesMetadata);
|
|
378
330
|
}
|
|
379
331
|
}
|
package/src/ToolManager.ts
CHANGED
|
@@ -15,8 +15,8 @@ export class ToolManager {
|
|
|
15
15
|
* @en Registers a tool.
|
|
16
16
|
*/
|
|
17
17
|
bindTool(tool: UnionTool<any>) {
|
|
18
|
-
if (this.tools.has(tool.name)) {
|
|
19
|
-
|
|
18
|
+
if (this.tools.has(tool.name) && tool.name !== "__default__") {
|
|
19
|
+
console.warn(`Tool with name ${tool.name} already exists`);
|
|
20
20
|
}
|
|
21
21
|
this.tools.set(tool.name, tool);
|
|
22
22
|
}
|
|
@@ -73,10 +73,7 @@ export class ToolManager {
|
|
|
73
73
|
* @en Calls the tool with the specified name.
|
|
74
74
|
*/
|
|
75
75
|
async callTool(name: string, args: any, context: { client: LangGraphClient; message: ToolMessage }) {
|
|
76
|
-
const tool = this.getTool(name)
|
|
77
|
-
if (!tool) {
|
|
78
|
-
throw new Error(`Tool with name ${name} not found`);
|
|
79
|
-
}
|
|
76
|
+
const tool = this.getTool(name) || this.getTool("__default__")!;
|
|
80
77
|
return await tool.execute?.(args, context);
|
|
81
78
|
}
|
|
82
79
|
|
package/src/tool/createTool.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { actionParametersToJsonSchema, convertJsonSchemaToZodRawShape } from "./utils.js";
|
|
2
|
-
import { z, ZodRawShape
|
|
2
|
+
import { z, ZodRawShape } from "zod";
|
|
3
3
|
import { Action, Parameter } from "./copilotkit-actions.js";
|
|
4
4
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
5
5
|
import { Message } from "@langchain/langgraph-sdk";
|
|
@@ -14,8 +14,8 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
|
|
|
14
14
|
execute?: ToolCallback<Args>;
|
|
15
15
|
/** 工具执行成功后触发的附加消息 */
|
|
16
16
|
callbackMessage?: (result: CallToolResult) => Message[];
|
|
17
|
-
handler?: (args: z.
|
|
18
|
-
render?: (tool: ToolRenderData<z.
|
|
17
|
+
handler?: (args: z.infer<z.ZodObject<Args>>, context?: any) => ResponseType | Promise<ResponseType>;
|
|
18
|
+
render?: (tool: ToolRenderData<z.infer<z.ZodObject<Args>>, ResponseType>) => Child;
|
|
19
19
|
onlyRender?: boolean;
|
|
20
20
|
/** 只允许指定的 agent 使用该工具,如果未指定,则所有 agent 都可以使用 */
|
|
21
21
|
allowAgent?: string[];
|
|
@@ -24,7 +24,7 @@ export interface UnionTool<Args extends ZodRawShape, Child extends Object = Obje
|
|
|
24
24
|
/** 是否是纯净的 json schema 参数,而不是 zod 参数 */
|
|
25
25
|
isPureParams?: boolean;
|
|
26
26
|
}
|
|
27
|
-
export type ToolCallback<Args extends ZodRawShape> = (args: z.
|
|
27
|
+
export type ToolCallback<Args extends ZodRawShape> = (args: z.infer<z.ZodObject<Args>>, context?: any) => CallToolResult | Promise<CallToolResult>;
|
|
28
28
|
|
|
29
29
|
export type CallToolResult = string | { type: "text"; text: string }[];
|
|
30
30
|
|
|
@@ -44,6 +44,8 @@ export const createUITool = <Args extends ZodRawShape, Child extends Object = {}
|
|
|
44
44
|
const result = await tool.handler?.(args, context);
|
|
45
45
|
if (typeof result === "string") {
|
|
46
46
|
return [{ type: "text", text: result }];
|
|
47
|
+
} else if (result.decisions) {
|
|
48
|
+
return result;
|
|
47
49
|
}
|
|
48
50
|
return [{ type: "text", text: JSON.stringify(result) }];
|
|
49
51
|
} catch (error) {
|
|
@@ -80,7 +82,7 @@ export const createFETool = <const T extends Parameter[], Args extends ZodRawSha
|
|
|
80
82
|
allowGraph: tool.allowGraph,
|
|
81
83
|
async execute(args, context) {
|
|
82
84
|
try {
|
|
83
|
-
const result = await tool.handler?.(args, context);
|
|
85
|
+
const result = await tool.handler?.(args as any, context);
|
|
84
86
|
if (typeof result === "string") {
|
|
85
87
|
return [{ type: "text", text: result }];
|
|
86
88
|
}
|
|
@@ -106,7 +108,7 @@ export const createMCPTool = <Args extends ZodRawShape>(tool: UnionTool<Args>) =
|
|
|
106
108
|
tool.name,
|
|
107
109
|
tool.description,
|
|
108
110
|
tool.parameters,
|
|
109
|
-
async (args: z.
|
|
111
|
+
async (args: z.infer<z.ZodObject<Args>>) => {
|
|
110
112
|
try {
|
|
111
113
|
const result = await tool.execute?.(args);
|
|
112
114
|
if (typeof result === "string") {
|