@amical/aiagent-sdk 0.1.9 → 0.1.10

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.
@@ -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 that match a regex pattern or glob pattern.",
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 files against.",
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,66 @@ var toolParamNames = [
502
516
  "start_line",
503
517
  "end_line"
504
518
  ];
519
+ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
520
+ "txt",
521
+ "md",
522
+ "markdown",
523
+ "json",
524
+ "js",
525
+ "mjs",
526
+ "cjs",
527
+ "ts",
528
+ "tsx",
529
+ "jsx",
530
+ "html",
531
+ "htm",
532
+ "css",
533
+ "scss",
534
+ "sass",
535
+ "less",
536
+ "py",
537
+ "java",
538
+ "c",
539
+ "cpp",
540
+ "cc",
541
+ "cxx",
542
+ "h",
543
+ "hpp",
544
+ "cs",
545
+ "go",
546
+ "rs",
547
+ "rb",
548
+ "php",
549
+ "sh",
550
+ "bash",
551
+ "zsh",
552
+ "bat",
553
+ "cmd",
554
+ "ps1",
555
+ "yaml",
556
+ "yml",
557
+ "toml",
558
+ "ini",
559
+ "cfg",
560
+ "conf",
561
+ "xml",
562
+ "svg",
563
+ "csv",
564
+ "log",
565
+ "sql",
566
+ "vue",
567
+ "svelte",
568
+ "astro",
569
+ "graphql",
570
+ "gql",
571
+ "prisma",
572
+ "env",
573
+ "gitignore",
574
+ "dockerfile",
575
+ "makefile",
576
+ "properties",
577
+ "lock"
578
+ ]);
505
579
  var AgentState = /* @__PURE__ */ ((AgentState2) => {
506
580
  AgentState2["IDLE"] = "idle";
507
581
  AgentState2["THINKING"] = "thinking";
@@ -857,15 +931,36 @@ STDERR: ${result.stderr}` });
857
931
  const path3 = tool.params.path || this.runtime.env.cwd();
858
932
  const regexStr = tool.params.regex;
859
933
  const filePattern = tool.params.file_pattern;
934
+ const includeNodeModules = tool.params.include_node_modules === "true";
860
935
  if (regexStr && path3) {
861
936
  try {
862
937
  let result;
863
938
  if (typeof this.runtime.fs.searchFiles === "function") {
864
939
  result = await this.runtime.fs.searchFiles(path3, regexStr, filePattern);
865
940
  } else {
866
- result = await this.searchFiles(path3, regexStr, filePattern);
941
+ result = await this.searchFiles(path3, regexStr, filePattern, includeNodeModules);
942
+ }
943
+ toolResults.push({ tool, result });
944
+ } catch (e) {
945
+ toolResults.push({ tool, result: `Error: ${e.message}` });
946
+ }
947
+ } else {
948
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
949
+ }
950
+ } else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
951
+ const path3 = tool.params.path || this.runtime.env.cwd();
952
+ const regexStr = tool.params.regex;
953
+ const filePattern = tool.params.file_pattern;
954
+ const includeNodeModules = tool.params.include_node_modules === "true";
955
+ if (regexStr && path3) {
956
+ try {
957
+ let result;
958
+ if (typeof this.runtime.fs.searchFileContent === "function") {
959
+ result = await this.runtime.fs.searchFileContent(path3, regexStr, filePattern);
960
+ } else {
961
+ result = await this.searchFileContent(path3, regexStr, filePattern, includeNodeModules);
867
962
  }
868
- toolResults.push({ tool, result: `${result}` });
963
+ toolResults.push({ tool, result });
869
964
  } catch (e) {
870
965
  toolResults.push({ tool, result: `Error: ${e.message}` });
871
966
  }
@@ -1040,13 +1135,80 @@ ${searchBlock.substring(0, 100)}...`);
1040
1135
  async getHistory() {
1041
1136
  return this.memory.getHistory();
1042
1137
  }
1043
- async searchFiles(dirpath, regex, filePattern) {
1138
+ /**
1139
+ * 判断文件是否为可进行内容搜索的文本类文件
1140
+ */
1141
+ isTextFile(name) {
1142
+ const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
1143
+ if (!ext) {
1144
+ return true;
1145
+ }
1146
+ return TEXT_FILE_EXTENSIONS.has(ext);
1147
+ }
1148
+ /**
1149
+ * 按文件名/目录名搜索,层级优先(BFS):
1150
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
1151
+ */
1152
+ async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
1044
1153
  const matches = [];
1045
- const contentRe = new RegExp(regex);
1046
- const nameRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1154
+ const MAX_RESULTS = 100;
1155
+ const MAX_DEPTH = 8;
1047
1156
  const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1157
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1158
+ const nameRe = new RegExp(regex);
1159
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1160
+ const queue = [{ dir: dirpath, depth: 0 }];
1161
+ while (queue.length > 0 && matches.length < MAX_RESULTS) {
1162
+ const { dir, depth } = queue.shift();
1163
+ if (depth > MAX_DEPTH) {
1164
+ continue;
1165
+ }
1166
+ let entries;
1167
+ try {
1168
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1169
+ } catch {
1170
+ continue;
1171
+ }
1172
+ for (const entry of entries) {
1173
+ if (matches.length >= MAX_RESULTS) {
1174
+ break;
1175
+ }
1176
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1177
+ if (entry.isDirectory()) {
1178
+ if (!shouldSkipDir(entry.name)) {
1179
+ if (nameRe.test(entry.name)) {
1180
+ matches.push(`${child}/`);
1181
+ }
1182
+ queue.push({ dir: child, depth: depth + 1 });
1183
+ }
1184
+ } else if (entry.isFile()) {
1185
+ if (globRe && !globRe.test(entry.name)) {
1186
+ continue;
1187
+ }
1188
+ if (nameRe.test(entry.name)) {
1189
+ matches.push(child);
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1194
+ if (matches.length === 0) {
1195
+ return "No files found.";
1196
+ }
1197
+ return matches.join("\n");
1198
+ }
1199
+ /**
1200
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
1201
+ */
1202
+ async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
1203
+ const matches = [];
1204
+ const MAX_RESULTS = 100;
1205
+ const MAX_DEPTH = 8;
1206
+ const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1207
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1208
+ const contentRe = new RegExp(regex);
1209
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1048
1210
  const walk = async (dir, depth) => {
1049
- if (depth > 8 || matches.length >= 100) {
1211
+ if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
1050
1212
  return;
1051
1213
  }
1052
1214
  let entries;
@@ -1056,21 +1218,24 @@ ${searchBlock.substring(0, 100)}...`);
1056
1218
  return;
1057
1219
  }
1058
1220
  for (const entry of entries) {
1059
- if (matches.length >= 100) {
1221
+ if (matches.length >= MAX_RESULTS) {
1060
1222
  break;
1061
1223
  }
1062
1224
  const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1063
1225
  if (entry.isDirectory()) {
1064
- if (!SKIP_DIRS.has(entry.name)) {
1226
+ if (!shouldSkipDir(entry.name)) {
1065
1227
  await walk(child, depth + 1);
1066
1228
  }
1067
1229
  } else if (entry.isFile()) {
1068
- if (nameRe && !nameRe.test(entry.name)) {
1230
+ if (!this.isTextFile(entry.name)) {
1231
+ continue;
1232
+ }
1233
+ if (globRe && !globRe.test(entry.name)) {
1069
1234
  continue;
1070
1235
  }
1071
1236
  try {
1072
- const content = (await this.runtime.fs.readFile(child, "utf8")).toString();
1073
- if (contentRe.test(content)) {
1237
+ const content = await this.runtime.fs.readFile(child);
1238
+ if (typeof content === "string" && contentRe.test(content)) {
1074
1239
  matches.push(child);
1075
1240
  }
1076
1241
  } catch {
@@ -1079,6 +1244,9 @@ ${searchBlock.substring(0, 100)}...`);
1079
1244
  }
1080
1245
  };
1081
1246
  await walk(dirpath, 0);
1247
+ if (matches.length === 0) {
1248
+ return "No files found with matching content.";
1249
+ }
1082
1250
  return matches.join("\n");
1083
1251
  }
1084
1252
  };