@saber2pr/ai-agent 0.0.65 → 0.0.66
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.js +4 -1
- package/lib/tools/builtin.d.ts +1 -1
- package/lib/tools/builtin.js +3 -1
- package/lib/tools/loader/batch_run_tools.d.ts +2 -0
- package/lib/tools/loader/batch_run_tools.js +56 -0
- package/lib/tools/loader/get_all_tools_schema.js +18 -7
- package/lib/types/type.d.ts +1 -0
- package/lib/utils/convertToLangChainTool.d.ts +2 -1
- package/lib/utils/createTool.d.ts +3 -2
- package/lib/utils/createTool.js +2 -2
- package/lib/utils/formatSchema.js +34 -10
- package/lib/utils/generateToolMarkdown.d.ts +0 -4
- package/lib/utils/generateToolMarkdown.js +30 -9
- package/lib/utils/getSystemPromptTemplate.js +1 -0
- package/package.json +1 -1
package/lib/core/agent-graph.js
CHANGED
|
@@ -185,7 +185,10 @@ class McpGraphAgent {
|
|
|
185
185
|
if (this.options.filterTools) {
|
|
186
186
|
allToolInfos = allToolInfos.filter(this.options.filterTools);
|
|
187
187
|
}
|
|
188
|
-
this.langchainTools = allToolInfos.map((t) => (0, convertToLangChainTool_1.convertToLangChainTool)(t, {
|
|
188
|
+
this.langchainTools = allToolInfos.map((t) => (0, convertToLangChainTool_1.convertToLangChainTool)(t, {
|
|
189
|
+
allTools: allToolInfos,
|
|
190
|
+
agentOptions: this.options,
|
|
191
|
+
}));
|
|
189
192
|
this.toolNode = new prebuilt_1.ToolNode(this.langchainTools);
|
|
190
193
|
return {
|
|
191
194
|
builtinToolInfos,
|
package/lib/tools/builtin.d.ts
CHANGED
package/lib/tools/builtin.js
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createDefaultBuiltinTools = createDefaultBuiltinTools;
|
|
4
4
|
const filesystem_1 = require("./filesystem");
|
|
5
|
-
const get_all_tools_schema_1 = require("./loader/get_all_tools_schema");
|
|
6
5
|
const ts_lsp_1 = require("./ts-lsp");
|
|
6
|
+
const get_all_tools_schema_1 = require("./loader/get_all_tools_schema");
|
|
7
|
+
const batch_run_tools_1 = require("./loader/batch_run_tools");
|
|
7
8
|
function createDefaultBuiltinTools(context) {
|
|
8
9
|
const { options } = context;
|
|
9
10
|
return [
|
|
10
11
|
...(0, ts_lsp_1.getTsLspTools)(options?.targetDir || process.cwd()),
|
|
11
12
|
...(0, filesystem_1.getFilesystemTools)(options?.targetDir || process.cwd()),
|
|
12
13
|
get_all_tools_schema_1.getAllToolsSchema,
|
|
14
|
+
batch_run_tools_1.batchRunTools,
|
|
13
15
|
];
|
|
14
16
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.batchRunTools = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const createTool_1 = require("../../utils/createTool");
|
|
6
|
+
const kit_1 = require("../../utils/kit");
|
|
7
|
+
exports.batchRunTools = (0, createTool_1.createTool)({
|
|
8
|
+
name: 'batch_run_tools',
|
|
9
|
+
// 使用更具指令性的英文描述
|
|
10
|
+
description: `Execute multiple tools in parallel. Use this for independent tasks such as reading multiple files, applying unrelated edits to different files, or fetching diagnostics simultaneously. CRITICAL: DO NOT apply multiple edits to the same file within a single batch to avoid write conflicts.`,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
actions: zod_1.z.array(zod_1.z.object({
|
|
13
|
+
// 字段名和描述对齐 AI 习惯
|
|
14
|
+
tool_name: zod_1.z.string().describe('The name of the tool to execute.'),
|
|
15
|
+
args: zod_1.z.any().describe('The JSON object containing arguments for the specific tool.')
|
|
16
|
+
})).describe('A list of tool-calling actions to be executed concurrently.')
|
|
17
|
+
}),
|
|
18
|
+
handler: async ({ actions }, context) => {
|
|
19
|
+
// 1. 获取所有可用工具的映射
|
|
20
|
+
const toolMap = (0, kit_1.getArray)(context?.allTools).reduce((acc, tool) => ({ ...acc, [tool.function.name]: tool }), {});
|
|
21
|
+
if (Object.keys(toolMap).length === 0) {
|
|
22
|
+
return 'Error: Failed to retrieve tool execution context.';
|
|
23
|
+
}
|
|
24
|
+
// 2. 并行执行所有 Action
|
|
25
|
+
const results = await Promise.all(actions.map(async (action) => {
|
|
26
|
+
const { tool_name, args } = action;
|
|
27
|
+
const tool = toolMap[tool_name];
|
|
28
|
+
if (!tool) {
|
|
29
|
+
return {
|
|
30
|
+
tool_name,
|
|
31
|
+
status: 'error',
|
|
32
|
+
output: `Tool not found: ${tool_name}`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
// 特别注意:这里调用的是 _handler,请确保参数 args 的结构与子工具 Zod 定义一致
|
|
37
|
+
const output = await tool._handler(args, context);
|
|
38
|
+
return {
|
|
39
|
+
tool_name,
|
|
40
|
+
status: 'success',
|
|
41
|
+
output
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
tool_name,
|
|
47
|
+
status: 'error',
|
|
48
|
+
output: error?.message || String(error)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
// 3. 格式化输出结果
|
|
53
|
+
// 虽然参数改成了英文,但返回给 AI 的结果标题可以保留清晰的结构
|
|
54
|
+
return results.map(res => `### Tool: ${res.tool_name} (${res.status})\n${res.output}\n---`).join('\n');
|
|
55
|
+
}
|
|
56
|
+
});
|
|
@@ -9,25 +9,36 @@ const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
|
|
|
9
9
|
const createTool_1 = require("../../utils/createTool");
|
|
10
10
|
const generateToolMarkdown_1 = require("../../utils/generateToolMarkdown");
|
|
11
11
|
const kit_1 = require("../../utils/kit");
|
|
12
|
+
const getSystemPromptTemplate_1 = require("../../utils/getSystemPromptTemplate");
|
|
12
13
|
exports.getAllToolsSchema = (0, createTool_1.createTool)({
|
|
13
|
-
name:
|
|
14
|
+
name: "get_all_tools_schema",
|
|
14
15
|
description: 'Use this tool when you encounter a "tool not found" error or are unsure about the parameter schema. It retrieves the full definitions and JSON schemas for all available tools in the current environment.',
|
|
15
16
|
parameters: zod_1.z.object({
|
|
16
|
-
toolName: zod_1.z
|
|
17
|
+
toolName: zod_1.z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Optional: Specify a tool name to get its detailed schema. If omitted, returns all available tools."),
|
|
17
21
|
}),
|
|
18
22
|
// 增加第二个参数 context
|
|
19
23
|
handler: async ({ toolName }, context) => {
|
|
20
24
|
// 这里的 context.allTools 是在运行时从 Agent 实例传入的
|
|
21
25
|
const availableTools = (0, kit_1.getArray)(context?.allTools);
|
|
22
26
|
const targetTools = toolName
|
|
23
|
-
? availableTools.filter(t => t.function.name === toolName)
|
|
27
|
+
? availableTools.filter((t) => t.function.name === toolName)
|
|
24
28
|
: availableTools;
|
|
25
|
-
|
|
29
|
+
let remainPrompt = "";
|
|
30
|
+
if (context?.agentOptions) {
|
|
31
|
+
// 如果AI忘记了工具用法,说明出现了记忆模糊,这里把系统提示词再补充上,加强记忆
|
|
32
|
+
const systemPrompt = (0, getSystemPromptTemplate_1.getSystemPromptTemplate)(context.agentOptions.targetDir);
|
|
33
|
+
remainPrompt = `${systemPrompt || ""}\n${context?.agentOptions?.extraSystemPrompt || ""}`;
|
|
34
|
+
}
|
|
35
|
+
const toolsMarkdown = (0, generateToolMarkdown_1.generateToolMarkdown)(targetTools.map((item) => ({
|
|
26
36
|
...item,
|
|
27
37
|
function: {
|
|
28
38
|
...item.function,
|
|
29
|
-
parameters: (0, zod_to_json_schema_1.default)(item.function.parameters)
|
|
30
|
-
}
|
|
39
|
+
parameters: (0, zod_to_json_schema_1.default)(item.function.parameters),
|
|
40
|
+
},
|
|
31
41
|
})));
|
|
32
|
-
|
|
42
|
+
return `${remainPrompt}\n${toolsMarkdown}`;
|
|
43
|
+
},
|
|
33
44
|
});
|
package/lib/types/type.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
2
|
-
import { ToolInfo } from '../types/type';
|
|
2
|
+
import { GraphAgentOptions, ToolInfo } from '../types/type';
|
|
3
3
|
export declare function convertToLangChainTool(info: ToolInfo, context: {
|
|
4
4
|
allTools: ToolInfo[];
|
|
5
|
+
agentOptions: GraphAgentOptions;
|
|
5
6
|
}): DynamicStructuredTool<import("zod").ZodObject<any, import("zod").UnknownKeysParam, import("zod").ZodTypeAny, {
|
|
6
7
|
[x: string]: any;
|
|
7
8
|
}, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { ToolInfo } from
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { GraphAgentOptions, ToolInfo } from "../types/type";
|
|
3
3
|
export interface CreateToolOptions {
|
|
4
4
|
name: string;
|
|
5
5
|
description: string;
|
|
@@ -9,6 +9,7 @@ export interface CreateToolOptions {
|
|
|
9
9
|
parameters: z.ZodObject<any>;
|
|
10
10
|
handler: (args: any, context: {
|
|
11
11
|
allTools: ToolInfo[];
|
|
12
|
+
agentOptions?: GraphAgentOptions;
|
|
12
13
|
}) => Promise<string>;
|
|
13
14
|
}
|
|
14
15
|
export declare function createTool(options: CreateToolOptions): ToolInfo;
|
package/lib/utils/createTool.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createTool = createTool;
|
|
4
4
|
function createTool(options) {
|
|
5
5
|
return {
|
|
6
|
-
type:
|
|
6
|
+
type: "function",
|
|
7
7
|
function: {
|
|
8
8
|
name: options.name,
|
|
9
9
|
description: options.description,
|
|
@@ -12,7 +12,7 @@ function createTool(options) {
|
|
|
12
12
|
_handler: async (input, context) => {
|
|
13
13
|
// 兼容处理:如果 input 是字符串,尝试解析为 JSON 对象
|
|
14
14
|
let args = input;
|
|
15
|
-
if (typeof input ===
|
|
15
|
+
if (typeof input === "string") {
|
|
16
16
|
try {
|
|
17
17
|
args = JSON.parse(input);
|
|
18
18
|
}
|
|
@@ -6,18 +6,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.formatSchema = formatSchema;
|
|
7
7
|
const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
|
|
8
8
|
function formatSchema(schema) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const jsonSchema = (0, zod_to_json_schema_1.default)(schema);
|
|
10
|
+
// 递归处理函数
|
|
11
|
+
const processProperties = (properties, required = [], level = 0) => {
|
|
12
|
+
if (!properties || typeof properties !== 'object')
|
|
13
|
+
return '';
|
|
14
|
+
const indent = ' '.repeat(level);
|
|
12
15
|
const lines = [];
|
|
13
|
-
for (const key in
|
|
14
|
-
|
|
16
|
+
for (const key in properties) {
|
|
17
|
+
const prop = properties[key];
|
|
18
|
+
const isRequired = required.includes(key);
|
|
19
|
+
// 1. 基础描述
|
|
20
|
+
let line = `${indent}- ${key}: ${prop.type || 'any'}${isRequired ? ' (required)' : ''}`;
|
|
21
|
+
if (prop.description)
|
|
22
|
+
line += ` - ${prop.description}`;
|
|
23
|
+
lines.push(line);
|
|
24
|
+
// 2. 递归处理数组 (Items)
|
|
25
|
+
if (prop.type === 'array' && prop.items) {
|
|
26
|
+
lines.push(`${indent} Items:`);
|
|
27
|
+
if (prop.items.type === 'object' && prop.items.properties) {
|
|
28
|
+
lines.push(processProperties(prop.items.properties, prop.items.required, level + 2));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
lines.push(`${indent} - Type: ${prop.items.type || 'any'}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 3. 递归处理嵌套对象 (Object)
|
|
35
|
+
if (prop.type === 'object' && prop.properties) {
|
|
36
|
+
lines.push(processProperties(prop.properties, prop.required, level + 1));
|
|
37
|
+
}
|
|
15
38
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
39
|
+
return lines.join('\n');
|
|
40
|
+
};
|
|
41
|
+
if (jsonSchema.properties) {
|
|
42
|
+
const result = processProperties(jsonSchema.properties, jsonSchema.required, 2); // 保持你原来的缩进感
|
|
43
|
+
return result || 'No parameters';
|
|
20
44
|
}
|
|
21
45
|
const keys = Object.keys(schema.shape);
|
|
22
|
-
return keys.join(', ');
|
|
46
|
+
return keys.length > 0 ? keys.join(', ') : 'No parameters';
|
|
23
47
|
}
|
|
@@ -7,20 +7,41 @@ const kit_1 = require("./kit");
|
|
|
7
7
|
* 将工具定义从 Zod Schema 转换为极简 Markdown 格式
|
|
8
8
|
* 目的:显著节省 System Prompt 的 Token,同时保持 LLM 理解力
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* 递归解析 JSON Schema 并生成简化的 Markdown
|
|
12
|
+
*/
|
|
13
|
+
function parseSchemaRecursive(schema, indent = '') {
|
|
14
|
+
if (!schema)
|
|
15
|
+
return '';
|
|
16
|
+
let res = '';
|
|
17
|
+
// 1. 处理对象类型 (Object)
|
|
18
|
+
if (schema.type === 'object' && schema.properties) {
|
|
19
|
+
Object.entries(schema.properties).forEach(([key, val]) => {
|
|
20
|
+
const isReq = schema.required?.includes(key);
|
|
21
|
+
const type = val.type || (val.anyOf ? 'any' : 'unknown');
|
|
22
|
+
const desc = val.description ? `: ${val.description}` : '';
|
|
23
|
+
res += `${indent}- \`${key}\` (${type}${isReq ? ', required' : ''})${desc}\n`;
|
|
24
|
+
// 递归处理嵌套对象或数组
|
|
25
|
+
res += parseSchemaRecursive(val, indent + ' ');
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// 2. 处理数组类型 (Array)
|
|
29
|
+
else if (schema.type === 'array' && schema.items) {
|
|
30
|
+
// 标注数组项的结构
|
|
31
|
+
res += `${indent} *Items:* \n${parseSchemaRecursive(schema.items, indent + ' ')}`;
|
|
32
|
+
}
|
|
33
|
+
return res;
|
|
34
|
+
}
|
|
10
35
|
function generateToolMarkdown(tools) {
|
|
11
36
|
let markdown = "## Tool Definitions\n\n";
|
|
12
37
|
(0, kit_1.getArray)(tools).forEach((tool) => {
|
|
38
|
+
// 假设 cleanToolDefinition 返回的是符合 JSON Schema 规范的对象
|
|
13
39
|
const { name, description, parameters } = (0, cleanToolDefinition_1.cleanToolDefinition)(tool);
|
|
14
40
|
markdown += `- **${name}**: ${description}\n`;
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const isRequired = requiredFields.includes(paramName);
|
|
20
|
-
const type = schema.type.replace('Zod', '').toLowerCase();
|
|
21
|
-
const desc = schema.description || schema.title || '';
|
|
22
|
-
markdown += ` - \`${paramName}\` (${type}${isRequired ? ', required' : ''})${desc ? `: ${desc}` : ''}\n`;
|
|
23
|
-
});
|
|
41
|
+
// 从根部开始递归解析参数
|
|
42
|
+
if (parameters && parameters.type === 'object') {
|
|
43
|
+
markdown += parseSchemaRecursive(parameters, ' ');
|
|
44
|
+
}
|
|
24
45
|
markdown += "\n";
|
|
25
46
|
});
|
|
26
47
|
return markdown;
|
|
@@ -11,6 +11,7 @@ Before providing any output or calling a tool, you **MUST** conduct a deep logic
|
|
|
11
11
|
1. **Pure JSON Arguments**: Arguments must be a valid JSON object. NEVER wrap the entire JSON object in a string or quotes.
|
|
12
12
|
2. **No Double Escaping**: Do not double-escape characters within the JSON.
|
|
13
13
|
3. **No Idle Operations**: If the task is complete or no tool is needed, DO NOT output any "Action" structure. Never use "None", "null", or empty strings as a tool name.
|
|
14
|
+
4. **Important Note**: For optimal efficiency, when performing multiple operations, use batch_run_tools to invoke all relevant tools in parallel, rather than sequentially. Prioritize parallel tool invocation whenever possible. For example, when reading three files, run three tool invocations in parallel to read all three files into the context simultaneously. When running multiple read-only commands (such as read_file_range, grep_search, or read_text_file), always run all commands in parallel. Use parallel tool invocations whenever possible, rather than running too many tools sequentially.
|
|
14
15
|
|
|
15
16
|
# 🎯 Core Instructions
|
|
16
17
|
1. **Termination Criterion**: Once you have read the requested files, answered the questions, or completed the code implementation, you must provide the final response immediately.
|