@amical/aiagent-sdk 0.1.9 → 0.1.11
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/index.d.mts +88 -9
- package/dist/index.d.ts +88 -9
- package/dist/index.js +305 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +302 -31
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/nodeRuntime.d.mts +1 -1
- package/dist/runtime/nodeRuntime.d.ts +1 -1
- package/dist/runtime/nodeRuntime.js +309 -31
- package/dist/runtime/nodeRuntime.js.map +1 -1
- package/dist/runtime/nodeRuntime.mjs +306 -32
- package/dist/runtime/nodeRuntime.mjs.map +1 -1
- package/dist/runtime/webRuntime.d.mts +1 -1
- package/dist/runtime/webRuntime.d.ts +1 -1
- package/dist/runtime/webRuntime.js +309 -31
- package/dist/runtime/webRuntime.js.map +1 -1
- package/dist/runtime/webRuntime.mjs +306 -32
- package/dist/runtime/webRuntime.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -49,6 +49,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
|
|
|
49
49
|
AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
|
|
50
50
|
AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
|
|
51
51
|
AgentDefaultTool2["SEARCH"] = "agent_search_files";
|
|
52
|
+
AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
|
|
52
53
|
AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
|
|
53
54
|
AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
|
|
54
55
|
AgentDefaultTool2["BROWSER"] = "agent_browser_action";
|
|
@@ -222,11 +223,22 @@ return (
|
|
|
222
223
|
},
|
|
223
224
|
{
|
|
224
225
|
name: "agent_search_files" /* SEARCH */,
|
|
225
|
-
description: "Search for files in a directory
|
|
226
|
+
description: "Search for files or directories by name in a directory tree, matching the name against a regex (and optionally a glob). Directories are traversed level by level: all matches in the current level are returned before descending into deeper levels. Use this tool only to locate files/directories by name.",
|
|
226
227
|
params: {
|
|
227
228
|
path: "(required) The absolute or relative directory path to search.",
|
|
228
|
-
regex: "(required) The regex pattern to match
|
|
229
|
-
file_pattern: "(optional) glob pattern like *.ts."
|
|
229
|
+
regex: "(required) The regex pattern to match file or directory names against.",
|
|
230
|
+
file_pattern: "(optional) glob pattern like *.ts.",
|
|
231
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "agent_search_file_content" /* SEARCH_CONTENT */,
|
|
236
|
+
description: "Search the contents of files in a directory tree for a regex pattern. Use this tool when you need to find text or code inside files rather than matching file or directory names.",
|
|
237
|
+
params: {
|
|
238
|
+
path: "(required) The absolute or relative directory path to search.",
|
|
239
|
+
regex: "(required) The regex pattern to match file content against.",
|
|
240
|
+
file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
|
|
241
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
230
242
|
}
|
|
231
243
|
},
|
|
232
244
|
{
|
|
@@ -295,6 +307,7 @@ var READ_ONLY_TOOLS = [
|
|
|
295
307
|
"agent_list_files" /* LIST_FILES */,
|
|
296
308
|
"agent_read_file" /* FILE_READ */,
|
|
297
309
|
"agent_search_files" /* SEARCH */,
|
|
310
|
+
"agent_search_file_content" /* SEARCH_CONTENT */,
|
|
298
311
|
"agent_list_code_definition_names" /* LIST_CODE_DEF */,
|
|
299
312
|
"agent_browser_action" /* BROWSER */,
|
|
300
313
|
"agent_ask_followup_question" /* ASK */,
|
|
@@ -464,6 +477,7 @@ var toolParamNames = [
|
|
|
464
477
|
"diff",
|
|
465
478
|
"regex",
|
|
466
479
|
"file_pattern",
|
|
480
|
+
"include_node_modules",
|
|
467
481
|
"recursive",
|
|
468
482
|
"action",
|
|
469
483
|
"url",
|
|
@@ -502,6 +516,104 @@ var toolParamNames = [
|
|
|
502
516
|
"start_line",
|
|
503
517
|
"end_line"
|
|
504
518
|
];
|
|
519
|
+
|
|
520
|
+
// src/shared/custom-tools.ts
|
|
521
|
+
function isCustomToolGroup(tool) {
|
|
522
|
+
return Array.isArray(tool.children) && tool.children.length > 0;
|
|
523
|
+
}
|
|
524
|
+
function collectCustomToolNames(tools) {
|
|
525
|
+
const names = [];
|
|
526
|
+
const visit = (list) => {
|
|
527
|
+
for (const tool of list) {
|
|
528
|
+
names.push(tool.name);
|
|
529
|
+
if (Array.isArray(tool.children) && tool.children.length > 0) {
|
|
530
|
+
visit(tool.children);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
visit(tools);
|
|
535
|
+
return names;
|
|
536
|
+
}
|
|
537
|
+
function renderCustomToolPrompt(tool, cwd = "") {
|
|
538
|
+
const params = tool.params ? Object.entries(tool.params) : [];
|
|
539
|
+
const replaceCwd = (text) => String(text).replaceAll("${context.cwd}", cwd);
|
|
540
|
+
const paramLines = params.map(([name, description]) => `- ${name}: ${replaceCwd(description)}`).join("\n");
|
|
541
|
+
const usageLines = params.map(([name, description]) => `<${name}>${replaceCwd(description)}</${name}>`).join("\n");
|
|
542
|
+
return `### ${tool.name}
|
|
543
|
+
Description: ${tool.description}
|
|
544
|
+
Parameters:
|
|
545
|
+
${paramLines}
|
|
546
|
+
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
|
547
|
+
Usage:
|
|
548
|
+
<${tool.name}>
|
|
549
|
+
${usageLines}
|
|
550
|
+
<task_progress>Checklist here (optional)</task_progress>
|
|
551
|
+
</${tool.name}>
|
|
552
|
+
`;
|
|
553
|
+
}
|
|
554
|
+
function renderCustomToolsPrompt(tools, cwd = "") {
|
|
555
|
+
return tools.map((tool) => renderCustomToolPrompt(tool, cwd)).join("\n");
|
|
556
|
+
}
|
|
557
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
558
|
+
"txt",
|
|
559
|
+
"md",
|
|
560
|
+
"markdown",
|
|
561
|
+
"json",
|
|
562
|
+
"js",
|
|
563
|
+
"mjs",
|
|
564
|
+
"cjs",
|
|
565
|
+
"ts",
|
|
566
|
+
"tsx",
|
|
567
|
+
"jsx",
|
|
568
|
+
"html",
|
|
569
|
+
"htm",
|
|
570
|
+
"css",
|
|
571
|
+
"scss",
|
|
572
|
+
"sass",
|
|
573
|
+
"less",
|
|
574
|
+
"py",
|
|
575
|
+
"java",
|
|
576
|
+
"c",
|
|
577
|
+
"cpp",
|
|
578
|
+
"cc",
|
|
579
|
+
"cxx",
|
|
580
|
+
"h",
|
|
581
|
+
"hpp",
|
|
582
|
+
"cs",
|
|
583
|
+
"go",
|
|
584
|
+
"rs",
|
|
585
|
+
"rb",
|
|
586
|
+
"php",
|
|
587
|
+
"sh",
|
|
588
|
+
"bash",
|
|
589
|
+
"zsh",
|
|
590
|
+
"bat",
|
|
591
|
+
"cmd",
|
|
592
|
+
"ps1",
|
|
593
|
+
"yaml",
|
|
594
|
+
"yml",
|
|
595
|
+
"toml",
|
|
596
|
+
"ini",
|
|
597
|
+
"cfg",
|
|
598
|
+
"conf",
|
|
599
|
+
"xml",
|
|
600
|
+
"svg",
|
|
601
|
+
"csv",
|
|
602
|
+
"log",
|
|
603
|
+
"sql",
|
|
604
|
+
"vue",
|
|
605
|
+
"svelte",
|
|
606
|
+
"astro",
|
|
607
|
+
"graphql",
|
|
608
|
+
"gql",
|
|
609
|
+
"prisma",
|
|
610
|
+
"env",
|
|
611
|
+
"gitignore",
|
|
612
|
+
"dockerfile",
|
|
613
|
+
"makefile",
|
|
614
|
+
"properties",
|
|
615
|
+
"lock"
|
|
616
|
+
]);
|
|
505
617
|
var AgentState = /* @__PURE__ */ ((AgentState2) => {
|
|
506
618
|
AgentState2["IDLE"] = "idle";
|
|
507
619
|
AgentState2["THINKING"] = "thinking";
|
|
@@ -525,9 +637,19 @@ var ClineAgent = class {
|
|
|
525
637
|
skillDir;
|
|
526
638
|
rulesDir;
|
|
527
639
|
customTools;
|
|
640
|
+
/** 当前可用(已展开集合)的顶层工具列表,传给 PromptManager 渲染 */
|
|
641
|
+
activeCustomTools;
|
|
642
|
+
/** 所有已知工具名(含未激活 children),便于查找定义 */
|
|
643
|
+
customToolsByName;
|
|
528
644
|
customToolNames;
|
|
529
645
|
allowDefaultTools;
|
|
530
646
|
customInstructions;
|
|
647
|
+
/** 已激活的工具集入口名 */
|
|
648
|
+
activatedGroups = /* @__PURE__ */ new Set();
|
|
649
|
+
/** activeCustomTools 变更版本号,用于 Prompt 缓存失效 */
|
|
650
|
+
activeToolsVersion = 0;
|
|
651
|
+
/** 缓存 sysPrompt 时记录的版本号 */
|
|
652
|
+
promptActiveToolsVersion = -1;
|
|
531
653
|
sysPrompt;
|
|
532
654
|
noUseTollSysPrompt;
|
|
533
655
|
// 简单的事件回调系统,供宿主环境注册以监听 Agent 内部事件
|
|
@@ -547,31 +669,38 @@ var ClineAgent = class {
|
|
|
547
669
|
this.allowDefaultTools.push("agent_attempt_completion" /* ATTEMPT */);
|
|
548
670
|
}
|
|
549
671
|
this.customInstructions = options.customInstructions;
|
|
672
|
+
this.customToolsByName = /* @__PURE__ */ new Map();
|
|
673
|
+
this.activeCustomTools = [...this.customTools];
|
|
674
|
+
this.customToolNames = new Set(collectCustomToolNames(this.customTools));
|
|
550
675
|
if (this.customTools.length > 0) {
|
|
551
|
-
const dynamicToolNames = /* @__PURE__ */ new Set();
|
|
552
676
|
const customToolParams = /* @__PURE__ */ new Set();
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
677
|
+
const visit = (tools) => {
|
|
678
|
+
for (const customTool of tools) {
|
|
679
|
+
this.customToolsByName.set(customTool.name, customTool);
|
|
680
|
+
if (customTool.params) {
|
|
681
|
+
for (const key in customTool.params) {
|
|
682
|
+
if (!Object.hasOwn(customTool.params, key)) continue;
|
|
683
|
+
customToolParams.add(key);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (Array.isArray(customTool.children) && customTool.children.length > 0) {
|
|
687
|
+
visit(customTool.children);
|
|
559
688
|
}
|
|
560
689
|
}
|
|
561
|
-
}
|
|
690
|
+
};
|
|
691
|
+
visit(this.customTools);
|
|
562
692
|
const defaultToolNames = Object.values(AgentDefaultTool);
|
|
563
|
-
const overlappingTools = Array.from(
|
|
693
|
+
const overlappingTools = Array.from(this.customToolNames).filter((name) => defaultToolNames.includes(name));
|
|
564
694
|
if (overlappingTools.length > 0) {
|
|
565
695
|
throw new Error(`Custom tools and default tools have overlapping names: ${overlappingTools.join(", ")}`);
|
|
566
696
|
}
|
|
567
|
-
if (
|
|
568
|
-
setDynamicToolUseNames("customUser", Array.from(
|
|
697
|
+
if (this.customToolNames.size > 0) {
|
|
698
|
+
setDynamicToolUseNames("customUser", Array.from(this.customToolNames));
|
|
569
699
|
}
|
|
570
700
|
if (customToolParams.size > 0) {
|
|
571
701
|
this.allToolParamNames = Array.from(/* @__PURE__ */ new Set([...this.allToolParamNames, ...Array.from(customToolParams)]));
|
|
572
702
|
}
|
|
573
703
|
}
|
|
574
|
-
this.customToolNames = new Set(this.customTools.map((t) => t.name));
|
|
575
704
|
this.skillDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/skills");
|
|
576
705
|
this.rulesDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/rules");
|
|
577
706
|
}
|
|
@@ -595,10 +724,11 @@ var ClineAgent = class {
|
|
|
595
724
|
shell: this.runtime.env.shell(),
|
|
596
725
|
skills: await this.getSkills(),
|
|
597
726
|
agentRules: await this.getAgentRules(),
|
|
598
|
-
customTools: this.
|
|
727
|
+
customTools: this.activeCustomTools,
|
|
599
728
|
allowDefaultTools: this.allowDefaultTools,
|
|
600
729
|
customInstructions: this.customInstructions
|
|
601
730
|
};
|
|
731
|
+
this.promptActiveToolsVersion = this.activeToolsVersion;
|
|
602
732
|
this.sysPrompt = await this.promptManager.getSystemPrompt(context);
|
|
603
733
|
this.noUseTollSysPrompt = this.promptManager.getNoUseToolInstructions(context);
|
|
604
734
|
return { sysPrompt: this.sysPrompt, noUseTollSysPrompt: this.noUseTollSysPrompt };
|
|
@@ -707,9 +837,9 @@ ${content.trim()}\`\`\``);
|
|
|
707
837
|
* 核心任务循环
|
|
708
838
|
*/
|
|
709
839
|
async loop() {
|
|
710
|
-
const {
|
|
711
|
-
const { customTools, customToolNames } = this;
|
|
840
|
+
const { customToolsByName, customToolNames } = this;
|
|
712
841
|
while (this.state === "thinking" /* THINKING */) {
|
|
842
|
+
const { sysPrompt, noUseTollSysPrompt } = await this.getCurrentPrompt();
|
|
713
843
|
this.loopCount++;
|
|
714
844
|
if (this.loopCount > this.maxLoopCount) {
|
|
715
845
|
await this.memory.appendMessage({
|
|
@@ -754,7 +884,33 @@ ${content.trim()}\`\`\``);
|
|
|
754
884
|
}
|
|
755
885
|
}
|
|
756
886
|
if (customToolNames.has(tool.name)) {
|
|
757
|
-
const customTool =
|
|
887
|
+
const customTool = customToolsByName.get(tool.name);
|
|
888
|
+
if (!customTool) {
|
|
889
|
+
toolResults.push({ tool, result: `Error: Custom tool "${tool.name}" not found.` });
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (isCustomToolGroup(customTool)) {
|
|
893
|
+
let groupResult;
|
|
894
|
+
if (customTool.onCall) {
|
|
895
|
+
try {
|
|
896
|
+
groupResult = await customTool.onCall(tool.params);
|
|
897
|
+
} catch (error) {
|
|
898
|
+
toolResults.push({ tool, result: `Error: ${error.message}` });
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
const childrenPrompt = this.activateCustomToolGroup(customTool);
|
|
903
|
+
const finalPrompt = `# New Available Tools
|
|
904
|
+
|
|
905
|
+
The following are instructions for using the new available tools.
|
|
906
|
+
|
|
907
|
+
${childrenPrompt}`;
|
|
908
|
+
const promptBlock = groupResult !== void 0 ? `${typeof groupResult === "string" ? groupResult : JSON.stringify(groupResult)}
|
|
909
|
+
|
|
910
|
+
${finalPrompt}` : finalPrompt;
|
|
911
|
+
toolResults.push({ tool, result: promptBlock });
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
758
914
|
if (customTool.onCall) {
|
|
759
915
|
try {
|
|
760
916
|
const res = await customTool.onCall(tool.params);
|
|
@@ -857,15 +1013,36 @@ STDERR: ${result.stderr}` });
|
|
|
857
1013
|
const path3 = tool.params.path || this.runtime.env.cwd();
|
|
858
1014
|
const regexStr = tool.params.regex;
|
|
859
1015
|
const filePattern = tool.params.file_pattern;
|
|
1016
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
860
1017
|
if (regexStr && path3) {
|
|
861
1018
|
try {
|
|
862
1019
|
let result;
|
|
863
1020
|
if (typeof this.runtime.fs.searchFiles === "function") {
|
|
864
1021
|
result = await this.runtime.fs.searchFiles(path3, regexStr, filePattern);
|
|
865
1022
|
} else {
|
|
866
|
-
result = await this.searchFiles(path3, regexStr, filePattern);
|
|
1023
|
+
result = await this.searchFiles(path3, regexStr, filePattern, includeNodeModules);
|
|
1024
|
+
}
|
|
1025
|
+
toolResults.push({ tool, result });
|
|
1026
|
+
} catch (e) {
|
|
1027
|
+
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
1028
|
+
}
|
|
1029
|
+
} else {
|
|
1030
|
+
toolResults.push({ tool, result: `Error: miss path or regex params` });
|
|
1031
|
+
}
|
|
1032
|
+
} else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
|
|
1033
|
+
const path3 = tool.params.path || this.runtime.env.cwd();
|
|
1034
|
+
const regexStr = tool.params.regex;
|
|
1035
|
+
const filePattern = tool.params.file_pattern;
|
|
1036
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
1037
|
+
if (regexStr && path3) {
|
|
1038
|
+
try {
|
|
1039
|
+
let result;
|
|
1040
|
+
if (typeof this.runtime.fs.searchFileContent === "function") {
|
|
1041
|
+
result = await this.runtime.fs.searchFileContent(path3, regexStr, filePattern);
|
|
1042
|
+
} else {
|
|
1043
|
+
result = await this.searchFileContent(path3, regexStr, filePattern, includeNodeModules);
|
|
867
1044
|
}
|
|
868
|
-
toolResults.push({ tool, result
|
|
1045
|
+
toolResults.push({ tool, result });
|
|
869
1046
|
} catch (e) {
|
|
870
1047
|
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
871
1048
|
}
|
|
@@ -994,6 +1171,27 @@ ${this.promptManager.getUsedToolResultInstructions()}`;
|
|
|
994
1171
|
}
|
|
995
1172
|
}
|
|
996
1173
|
}
|
|
1174
|
+
/**
|
|
1175
|
+
* 激活自定义工具集:将入口的 children 注册到活跃工具列表并返回渲染后的 prompt。
|
|
1176
|
+
*/
|
|
1177
|
+
activateCustomToolGroup(group) {
|
|
1178
|
+
if (this.activatedGroups.has(group.name)) {
|
|
1179
|
+
return renderCustomToolsPrompt(group.children || [], this.runtime.env.cwd());
|
|
1180
|
+
}
|
|
1181
|
+
this.activatedGroups.add(group.name);
|
|
1182
|
+
this.activeCustomTools = [...this.activeCustomTools, ...group.children || []];
|
|
1183
|
+
this.activeToolsVersion++;
|
|
1184
|
+
return renderCustomToolsPrompt(group.children || [], this.runtime.env.cwd());
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* 检查自上次获取 prompt 后是否有工具集被激活,若有则刷新缓存。
|
|
1188
|
+
*/
|
|
1189
|
+
async getCurrentPrompt() {
|
|
1190
|
+
if (this.promptActiveToolsVersion !== this.activeToolsVersion) {
|
|
1191
|
+
return this.getPrompt(true);
|
|
1192
|
+
}
|
|
1193
|
+
return this.getPrompt();
|
|
1194
|
+
}
|
|
997
1195
|
/**
|
|
998
1196
|
* 简单的 Diff 解析与替换辅助方法
|
|
999
1197
|
*/
|
|
@@ -1040,13 +1238,80 @@ ${searchBlock.substring(0, 100)}...`);
|
|
|
1040
1238
|
async getHistory() {
|
|
1041
1239
|
return this.memory.getHistory();
|
|
1042
1240
|
}
|
|
1043
|
-
|
|
1241
|
+
/**
|
|
1242
|
+
* 判断文件是否为可进行内容搜索的文本类文件
|
|
1243
|
+
*/
|
|
1244
|
+
isTextFile(name) {
|
|
1245
|
+
const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
|
|
1246
|
+
if (!ext) {
|
|
1247
|
+
return true;
|
|
1248
|
+
}
|
|
1249
|
+
return TEXT_FILE_EXTENSIONS.has(ext);
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* 按文件名/目录名搜索,层级优先(BFS):
|
|
1253
|
+
* 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
|
|
1254
|
+
*/
|
|
1255
|
+
async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1044
1256
|
const matches = [];
|
|
1045
|
-
const
|
|
1046
|
-
const
|
|
1257
|
+
const MAX_RESULTS = 100;
|
|
1258
|
+
const MAX_DEPTH = 8;
|
|
1259
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1260
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1261
|
+
const nameRe = new RegExp(regex);
|
|
1262
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1263
|
+
const queue = [{ dir: dirpath, depth: 0 }];
|
|
1264
|
+
while (queue.length > 0 && matches.length < MAX_RESULTS) {
|
|
1265
|
+
const { dir, depth } = queue.shift();
|
|
1266
|
+
if (depth > MAX_DEPTH) {
|
|
1267
|
+
continue;
|
|
1268
|
+
}
|
|
1269
|
+
let entries;
|
|
1270
|
+
try {
|
|
1271
|
+
entries = await this.runtime.fs.readDir(dir, { recursive: false });
|
|
1272
|
+
} catch {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
for (const entry of entries) {
|
|
1276
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1277
|
+
break;
|
|
1278
|
+
}
|
|
1279
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1280
|
+
if (entry.isDirectory()) {
|
|
1281
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1282
|
+
if (nameRe.test(entry.name)) {
|
|
1283
|
+
matches.push(`${child}/`);
|
|
1284
|
+
}
|
|
1285
|
+
queue.push({ dir: child, depth: depth + 1 });
|
|
1286
|
+
}
|
|
1287
|
+
} else if (entry.isFile()) {
|
|
1288
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
if (nameRe.test(entry.name)) {
|
|
1292
|
+
matches.push(child);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (matches.length === 0) {
|
|
1298
|
+
return "No files found.";
|
|
1299
|
+
}
|
|
1300
|
+
return matches.join("\n");
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
|
|
1304
|
+
*/
|
|
1305
|
+
async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1306
|
+
const matches = [];
|
|
1307
|
+
const MAX_RESULTS = 100;
|
|
1308
|
+
const MAX_DEPTH = 8;
|
|
1047
1309
|
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1310
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1311
|
+
const contentRe = new RegExp(regex);
|
|
1312
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1048
1313
|
const walk = async (dir, depth) => {
|
|
1049
|
-
if (depth >
|
|
1314
|
+
if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
|
|
1050
1315
|
return;
|
|
1051
1316
|
}
|
|
1052
1317
|
let entries;
|
|
@@ -1056,21 +1321,24 @@ ${searchBlock.substring(0, 100)}...`);
|
|
|
1056
1321
|
return;
|
|
1057
1322
|
}
|
|
1058
1323
|
for (const entry of entries) {
|
|
1059
|
-
if (matches.length >=
|
|
1324
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1060
1325
|
break;
|
|
1061
1326
|
}
|
|
1062
1327
|
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1063
1328
|
if (entry.isDirectory()) {
|
|
1064
|
-
if (!
|
|
1329
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1065
1330
|
await walk(child, depth + 1);
|
|
1066
1331
|
}
|
|
1067
1332
|
} else if (entry.isFile()) {
|
|
1068
|
-
if (
|
|
1333
|
+
if (!this.isTextFile(entry.name)) {
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1069
1337
|
continue;
|
|
1070
1338
|
}
|
|
1071
1339
|
try {
|
|
1072
|
-
const content =
|
|
1073
|
-
if (contentRe.test(content)) {
|
|
1340
|
+
const content = await this.runtime.fs.readFile(child);
|
|
1341
|
+
if (typeof content === "string" && contentRe.test(content)) {
|
|
1074
1342
|
matches.push(child);
|
|
1075
1343
|
}
|
|
1076
1344
|
} catch {
|
|
@@ -1079,6 +1347,9 @@ ${searchBlock.substring(0, 100)}...`);
|
|
|
1079
1347
|
}
|
|
1080
1348
|
};
|
|
1081
1349
|
await walk(dirpath, 0);
|
|
1350
|
+
if (matches.length === 0) {
|
|
1351
|
+
return "No files found with matching content.";
|
|
1352
|
+
}
|
|
1082
1353
|
return matches.join("\n");
|
|
1083
1354
|
}
|
|
1084
1355
|
};
|
|
@@ -1282,10 +1553,11 @@ ${context.customInstructions}
|
|
|
1282
1553
|
if (allowDefaultTools) {
|
|
1283
1554
|
useDefaultTools = defaultTools.filter((tool) => allowDefaultTools.includes(tool.name));
|
|
1284
1555
|
}
|
|
1556
|
+
const renderedCustomTools = renderCustomToolsPrompt(customTools, context.cwd);
|
|
1285
1557
|
return `# Available Tools
|
|
1286
1558
|
You can use the following tools by formatting your output as XML blocks. Only use ONE tool per message, and ALWAYS wait for the user's response with the execution result before proceeding.
|
|
1287
1559
|
|
|
1288
|
-
${[...useDefaultTools
|
|
1560
|
+
${[...useDefaultTools].map((tool) => {
|
|
1289
1561
|
return `### ${tool.name}
|
|
1290
1562
|
Description: ${tool.description}
|
|
1291
1563
|
Parameters:
|
|
@@ -1298,6 +1570,8 @@ ${Object.entries(tool.params).map(([name, description]) => `<${name}>${descripti
|
|
|
1298
1570
|
</${tool.name}>
|
|
1299
1571
|
`;
|
|
1300
1572
|
}).join("\n")}
|
|
1573
|
+
${renderedCustomTools ? `
|
|
1574
|
+
${renderedCustomTools}` : ""}
|
|
1301
1575
|
|
|
1302
1576
|
# Tool Use Examples
|
|
1303
1577
|
${useDefaultTools.filter((item) => Boolean(item.example)).map((item) => item.example).join("\n")}}
|
|
@@ -1745,10 +2019,14 @@ exports.NodePromptManager = NodePromptManager;
|
|
|
1745
2019
|
exports.READ_ONLY_TOOLS = READ_ONLY_TOOLS;
|
|
1746
2020
|
exports.TOOL_RESULT_BLOCK = TOOL_RESULT_BLOCK;
|
|
1747
2021
|
exports.VERSION = VERSION;
|
|
2022
|
+
exports.collectCustomToolNames = collectCustomToolNames;
|
|
1748
2023
|
exports.createNodeAgent = createNodeAgent;
|
|
1749
2024
|
exports.defaultTools = defaultTools;
|
|
1750
2025
|
exports.getToolUseNames = getToolUseNames;
|
|
2026
|
+
exports.isCustomToolGroup = isCustomToolGroup;
|
|
1751
2027
|
exports.parseAssistantMessageV2 = parseAssistantMessageV2;
|
|
2028
|
+
exports.renderCustomToolPrompt = renderCustomToolPrompt;
|
|
2029
|
+
exports.renderCustomToolsPrompt = renderCustomToolsPrompt;
|
|
1752
2030
|
exports.setDynamicToolUseNames = setDynamicToolUseNames;
|
|
1753
2031
|
exports.toolParamNames = toolParamNames;
|
|
1754
2032
|
exports.toolUseNames = toolUseNames;
|