@saber2pr/ai-agent 0.0.47 → 0.0.50
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/lib/core/agent-graph.d.ts +2 -2
- package/lib/core/agent-graph.js +16 -7
- package/lib/model/AgentGraphModel.d.ts +9 -2
- package/lib/model/AgentGraphModel.js +28 -6
- package/lib/tools/filesystem/index.js +4 -15
- package/lib/utils/kit.d.ts +1 -0
- package/lib/utils/kit.js +5 -0
- package/package.json +1 -1
|
@@ -43,12 +43,12 @@ export default class McpGraphAgent<T extends AgentGraphModel = any> {
|
|
|
43
43
|
private loadMcpConfigs;
|
|
44
44
|
private initMcpTools;
|
|
45
45
|
private prepareTools;
|
|
46
|
-
ensureInitialized(): Promise<
|
|
46
|
+
ensureInitialized(): Promise<T>;
|
|
47
47
|
private closeMcpClients;
|
|
48
48
|
private showLoading;
|
|
49
49
|
private startLoading;
|
|
50
50
|
private stopLoading;
|
|
51
|
-
getModel
|
|
51
|
+
private getModel;
|
|
52
52
|
private askForConfig;
|
|
53
53
|
chat(query?: string): Promise<void>;
|
|
54
54
|
/**
|
package/lib/core/agent-graph.js
CHANGED
|
@@ -180,17 +180,29 @@ class McpGraphAgent {
|
|
|
180
180
|
const allToolInfos = [...builtinToolInfos, ...(this.options.tools || []), ...mcpToolInfos];
|
|
181
181
|
this.langchainTools = allToolInfos.map(t => (0, convertToLangChainTool_1.convertToLangChainTool)(t));
|
|
182
182
|
this.toolNode = new prebuilt_1.ToolNode(this.langchainTools);
|
|
183
|
+
return {
|
|
184
|
+
builtinToolInfos,
|
|
185
|
+
mcpToolInfos,
|
|
186
|
+
tools: this.options.tools,
|
|
187
|
+
langchainTools: this.langchainTools,
|
|
188
|
+
};
|
|
183
189
|
}
|
|
184
190
|
// ✅ 修改:初始化逻辑
|
|
185
191
|
async ensureInitialized() {
|
|
186
|
-
if (this.model && this.langchainTools.length > 0)
|
|
187
|
-
return;
|
|
192
|
+
if (this.model && this.langchainTools.length > 0) {
|
|
193
|
+
return this.getModel();
|
|
194
|
+
}
|
|
195
|
+
;
|
|
188
196
|
// 1. 加载所有工具(含 MCP)
|
|
189
|
-
await this.prepareTools();
|
|
197
|
+
const toolsInfo = await this.prepareTools();
|
|
190
198
|
// 2. 初始化模型
|
|
191
|
-
await this.getModel();
|
|
199
|
+
const apiModel = await this.getModel();
|
|
200
|
+
if (toolsInfo.mcpToolInfos && apiModel.setMcpTools) {
|
|
201
|
+
apiModel.setMcpTools(toolsInfo.mcpToolInfos);
|
|
202
|
+
}
|
|
192
203
|
// 3. 打印工具状态
|
|
193
204
|
this.printLoadedTools();
|
|
205
|
+
return apiModel;
|
|
194
206
|
}
|
|
195
207
|
// ✅ 新增:关闭连接
|
|
196
208
|
async closeMcpClients() {
|
|
@@ -268,7 +280,6 @@ class McpGraphAgent {
|
|
|
268
280
|
async chat(query = '开始代码审计') {
|
|
269
281
|
try {
|
|
270
282
|
await this.ensureInitialized();
|
|
271
|
-
await this.getModel();
|
|
272
283
|
const app = await this.createGraph();
|
|
273
284
|
const graphStream = await app.stream({
|
|
274
285
|
messages: [new messages_1.HumanMessage(query)],
|
|
@@ -298,7 +309,6 @@ class McpGraphAgent {
|
|
|
298
309
|
this.streamEnabled = true;
|
|
299
310
|
try {
|
|
300
311
|
await this.ensureInitialized();
|
|
301
|
-
await this.getModel();
|
|
302
312
|
const app = await this.createGraph();
|
|
303
313
|
const graphStream = await app.stream({
|
|
304
314
|
messages: [new messages_1.HumanMessage(query)],
|
|
@@ -322,7 +332,6 @@ class McpGraphAgent {
|
|
|
322
332
|
}
|
|
323
333
|
async start() {
|
|
324
334
|
await this.ensureInitialized();
|
|
325
|
-
await this.getModel();
|
|
326
335
|
const app = await this.createGraph();
|
|
327
336
|
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
328
337
|
rl.on('SIGINT', () => {
|
|
@@ -11,9 +11,16 @@ export interface AgentGraphLLMResponse {
|
|
|
11
11
|
export type StreamChunkCallback = (chunk: string) => void;
|
|
12
12
|
export declare abstract class AgentGraphModel extends BaseChatModel {
|
|
13
13
|
protected boundTools?: any[];
|
|
14
|
+
private mcpEnabled?;
|
|
15
|
+
private mcpTools?;
|
|
16
|
+
setMcpTools(tools: any[]): void;
|
|
17
|
+
setMcpEnabled(enabled?: boolean): void;
|
|
18
|
+
getMcpEnabled(): boolean;
|
|
19
|
+
getMcpTools(): any[];
|
|
20
|
+
private isMcpTool;
|
|
14
21
|
constructor(fields?: BaseChatModelParams);
|
|
15
22
|
bindTools(tools: any[]): any;
|
|
16
|
-
abstract callApi(prompt: string): Promise<AgentGraphLLMResponse>;
|
|
23
|
+
abstract callApi(prompt: string, lastMsg: BaseMessage): Promise<AgentGraphLLMResponse>;
|
|
17
24
|
/**
|
|
18
25
|
* 流式调用 API,子类可覆盖以实现真正的 SSE 流式传输。
|
|
19
26
|
* 默认回退到 callApi 非流式调用。
|
|
@@ -21,7 +28,7 @@ export declare abstract class AgentGraphModel extends BaseChatModel {
|
|
|
21
28
|
* @param onChunk 每收到一段文本时的回调
|
|
22
29
|
* @returns 完整的响应结果
|
|
23
30
|
*/
|
|
24
|
-
callApiStream(prompt: string, onChunk: StreamChunkCallback): Promise<AgentGraphLLMResponse>;
|
|
31
|
+
callApiStream(prompt: string, lastMsg: BaseMessage, onChunk: StreamChunkCallback): Promise<AgentGraphLLMResponse>;
|
|
25
32
|
_generate(messages: BaseMessage[]): Promise<ChatResult>;
|
|
26
33
|
private parseToolCalls;
|
|
27
34
|
/**
|
|
@@ -5,9 +5,28 @@ const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
|
5
5
|
const messages_1 = require("@langchain/core/messages");
|
|
6
6
|
const function_calling_1 = require("@langchain/core/utils/function_calling");
|
|
7
7
|
const cleanToolDefinition_1 = require("../utils/cleanToolDefinition");
|
|
8
|
+
const kit_1 = require("../utils/kit");
|
|
8
9
|
class AgentGraphModel extends chat_models_1.BaseChatModel {
|
|
10
|
+
setMcpTools(tools) {
|
|
11
|
+
this.mcpTools = tools;
|
|
12
|
+
}
|
|
13
|
+
setMcpEnabled(enabled = true) {
|
|
14
|
+
this.mcpEnabled = enabled;
|
|
15
|
+
}
|
|
16
|
+
getMcpEnabled() {
|
|
17
|
+
return this.mcpEnabled;
|
|
18
|
+
}
|
|
19
|
+
getMcpTools() {
|
|
20
|
+
return this.mcpTools;
|
|
21
|
+
}
|
|
22
|
+
isMcpTool(tool) {
|
|
23
|
+
const mcpTools = (0, kit_1.getArray)(this.mcpTools);
|
|
24
|
+
return mcpTools.some(t => { var _a, _b; return ((_a = t === null || t === void 0 ? void 0 : t.function) === null || _a === void 0 ? void 0 : _a.name) === ((_b = tool === null || tool === void 0 ? void 0 : tool.function) === null || _b === void 0 ? void 0 : _b.name); });
|
|
25
|
+
}
|
|
9
26
|
constructor(fields) {
|
|
10
27
|
super(fields || {});
|
|
28
|
+
this.mcpEnabled = true;
|
|
29
|
+
this.mcpTools = [];
|
|
11
30
|
}
|
|
12
31
|
bindTools(tools) {
|
|
13
32
|
this.boundTools = tools.map(t => (0, function_calling_1.convertToOpenAITool)(t));
|
|
@@ -20,14 +39,15 @@ class AgentGraphModel extends chat_models_1.BaseChatModel {
|
|
|
20
39
|
* @param onChunk 每收到一段文本时的回调
|
|
21
40
|
* @returns 完整的响应结果
|
|
22
41
|
*/
|
|
23
|
-
async callApiStream(prompt, onChunk) {
|
|
24
|
-
const result = await this.callApi(prompt);
|
|
42
|
+
async callApiStream(prompt, lastMsg, onChunk) {
|
|
43
|
+
const result = await this.callApi(prompt, lastMsg);
|
|
25
44
|
onChunk(result.text);
|
|
26
45
|
return result;
|
|
27
46
|
}
|
|
28
47
|
async _generate(messages) {
|
|
29
48
|
const fullPrompt = this.serializeMessages(messages);
|
|
30
|
-
const
|
|
49
|
+
const lastMsg = messages[messages.length - 1];
|
|
50
|
+
const response = await this.callApi(fullPrompt, lastMsg);
|
|
31
51
|
let { text, reasoning } = response;
|
|
32
52
|
// 1. 处理思考内容
|
|
33
53
|
if (!reasoning && text.includes('<think>')) {
|
|
@@ -111,7 +131,8 @@ class AgentGraphModel extends chat_models_1.BaseChatModel {
|
|
|
111
131
|
*/
|
|
112
132
|
async streamGenerate(messages, onChunk) {
|
|
113
133
|
const fullPrompt = this.serializeMessages(messages);
|
|
114
|
-
const
|
|
134
|
+
const lastMsg = messages[messages.length - 1];
|
|
135
|
+
const response = await this.callApiStream(fullPrompt, lastMsg, onChunk);
|
|
115
136
|
let { text, reasoning } = response;
|
|
116
137
|
// 1. 处理思考内容
|
|
117
138
|
if (!reasoning && text.includes('<think>')) {
|
|
@@ -152,8 +173,9 @@ class AgentGraphModel extends chat_models_1.BaseChatModel {
|
|
|
152
173
|
const content = typeof m.content === 'string' ? m.content : JSON.stringify(m.content, null, 2);
|
|
153
174
|
return `${m._getType().toUpperCase()}: ${content}`;
|
|
154
175
|
};
|
|
155
|
-
const
|
|
156
|
-
|
|
176
|
+
const tools = this.getMcpEnabled() ? (0, kit_1.getArray)(this.boundTools) : (0, kit_1.getArray)(this.boundTools).filter(tool => !this.isMcpTool(tool));
|
|
177
|
+
const toolsContext = tools.length
|
|
178
|
+
? `\n[Tools]\n${JSON.stringify(tools.map(cleanToolDefinition_1.cleanToolDefinition), null, 2)}`
|
|
157
179
|
: '';
|
|
158
180
|
return `
|
|
159
181
|
${format(systemMsg)}
|
|
@@ -153,10 +153,7 @@ const getFilesystemTools = (targetDir) => {
|
|
|
153
153
|
});
|
|
154
154
|
const createDirectoryTool = (0, createTool_1.createTool)({
|
|
155
155
|
name: 'create_directory',
|
|
156
|
-
description: '
|
|
157
|
-
'nested directories in one operation. If the directory already exists, ' +
|
|
158
|
-
'this operation will succeed silently. Perfect for setting up directory ' +
|
|
159
|
-
'structures for projects or ensuring required paths exist. Only works within allowed directories.',
|
|
156
|
+
description: '递归创建目录。支持多级嵌套。若目录已存在则静默成功。仅限允许目录。',
|
|
160
157
|
parameters: CreateDirectoryArgsSchema,
|
|
161
158
|
handler: async (args) => {
|
|
162
159
|
const validPath = await (0, lib_1.validatePath)(targetDir, args.path);
|
|
@@ -167,10 +164,7 @@ const getFilesystemTools = (targetDir) => {
|
|
|
167
164
|
});
|
|
168
165
|
const listDirectoryWithSizesTool = (0, createTool_1.createTool)({
|
|
169
166
|
name: 'list_directory',
|
|
170
|
-
description: '
|
|
171
|
-
'Results clearly distinguish between files and directories with [FILE] and [DIR] ' +
|
|
172
|
-
'prefixes. This tool is useful for understanding directory structure and ' +
|
|
173
|
-
'finding specific files within a directory. Only works within allowed directories.',
|
|
167
|
+
description: '列出目录内容。返回带 [FILE]/[DIR] 前缀的条目、大小及汇总。支持按名称或大小排序。',
|
|
174
168
|
parameters: ListDirectoryWithSizesArgsSchema,
|
|
175
169
|
handler: async (args) => {
|
|
176
170
|
const validPath = await (0, lib_1.validatePath)(targetDir, args.path);
|
|
@@ -257,10 +251,7 @@ const getFilesystemTools = (targetDir) => {
|
|
|
257
251
|
});
|
|
258
252
|
const moveFileTool = (0, createTool_1.createTool)({
|
|
259
253
|
name: 'move_file',
|
|
260
|
-
description: '
|
|
261
|
-
'and rename them in a single operation. If the destination exists, the ' +
|
|
262
|
-
'operation will fail. Works across different directories and can be used ' +
|
|
263
|
-
'for simple renaming within the same directory. Both source and destination must be within allowed directories.',
|
|
254
|
+
description: '移动或重命名文件/目录。目标路径若已存在则失败。源与目标均须在允许目录内。',
|
|
264
255
|
parameters: MoveFileArgsSchema,
|
|
265
256
|
handler: async (args) => {
|
|
266
257
|
const validSourcePath = await (0, lib_1.validatePath)(targetDir, args.source);
|
|
@@ -272,9 +263,7 @@ const getFilesystemTools = (targetDir) => {
|
|
|
272
263
|
});
|
|
273
264
|
const searchFilesTool = (0, createTool_1.createTool)({
|
|
274
265
|
name: 'search_files',
|
|
275
|
-
description: '
|
|
276
|
-
'Returns a list of files that match the pattern. Only works within allowed directories.' +
|
|
277
|
-
'Used only for filename search',
|
|
266
|
+
description: '在指定路径下搜索匹配模式的文件名。返回匹配的相对路径列表。',
|
|
278
267
|
parameters: SearchFilesArgsSchema,
|
|
279
268
|
handler: async (args) => {
|
|
280
269
|
const combinedExcludes = [...DEFAULT_IGNORE, ...(args.excludePatterns || [])];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getArray: <T = any>(array: T[]) => T[];
|
package/lib/utils/kit.js
ADDED