@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.
@@ -17,6 +17,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
17
17
  AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
18
18
  AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
19
19
  AgentDefaultTool2["SEARCH"] = "agent_search_files";
20
+ AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
20
21
  AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
21
22
  AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
22
23
  AgentDefaultTool2["BROWSER"] = "agent_browser_action";
@@ -190,11 +191,22 @@ return (
190
191
  },
191
192
  {
192
193
  name: "agent_search_files" /* SEARCH */,
193
- description: "Search for files in a directory that match a regex pattern or glob pattern.",
194
+ 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.",
194
195
  params: {
195
196
  path: "(required) The absolute or relative directory path to search.",
196
- regex: "(required) The regex pattern to match files against.",
197
- file_pattern: "(optional) glob pattern like *.ts."
197
+ regex: "(required) The regex pattern to match file or directory names against.",
198
+ file_pattern: "(optional) glob pattern like *.ts.",
199
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
200
+ }
201
+ },
202
+ {
203
+ name: "agent_search_file_content" /* SEARCH_CONTENT */,
204
+ 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.",
205
+ params: {
206
+ path: "(required) The absolute or relative directory path to search.",
207
+ regex: "(required) The regex pattern to match file content against.",
208
+ file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
209
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
198
210
  }
199
211
  },
200
212
  {
@@ -263,6 +275,7 @@ var READ_ONLY_TOOLS = [
263
275
  "agent_list_files" /* LIST_FILES */,
264
276
  "agent_read_file" /* FILE_READ */,
265
277
  "agent_search_files" /* SEARCH */,
278
+ "agent_search_file_content" /* SEARCH_CONTENT */,
266
279
  "agent_list_code_definition_names" /* LIST_CODE_DEF */,
267
280
  "agent_browser_action" /* BROWSER */,
268
281
  "agent_ask_followup_question" /* ASK */,
@@ -432,6 +445,7 @@ var toolParamNames = [
432
445
  "diff",
433
446
  "regex",
434
447
  "file_pattern",
448
+ "include_node_modules",
435
449
  "recursive",
436
450
  "action",
437
451
  "url",
@@ -470,6 +484,66 @@ var toolParamNames = [
470
484
  "start_line",
471
485
  "end_line"
472
486
  ];
487
+ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
488
+ "txt",
489
+ "md",
490
+ "markdown",
491
+ "json",
492
+ "js",
493
+ "mjs",
494
+ "cjs",
495
+ "ts",
496
+ "tsx",
497
+ "jsx",
498
+ "html",
499
+ "htm",
500
+ "css",
501
+ "scss",
502
+ "sass",
503
+ "less",
504
+ "py",
505
+ "java",
506
+ "c",
507
+ "cpp",
508
+ "cc",
509
+ "cxx",
510
+ "h",
511
+ "hpp",
512
+ "cs",
513
+ "go",
514
+ "rs",
515
+ "rb",
516
+ "php",
517
+ "sh",
518
+ "bash",
519
+ "zsh",
520
+ "bat",
521
+ "cmd",
522
+ "ps1",
523
+ "yaml",
524
+ "yml",
525
+ "toml",
526
+ "ini",
527
+ "cfg",
528
+ "conf",
529
+ "xml",
530
+ "svg",
531
+ "csv",
532
+ "log",
533
+ "sql",
534
+ "vue",
535
+ "svelte",
536
+ "astro",
537
+ "graphql",
538
+ "gql",
539
+ "prisma",
540
+ "env",
541
+ "gitignore",
542
+ "dockerfile",
543
+ "makefile",
544
+ "properties",
545
+ "lock"
546
+ ]);
473
547
  var AgentState = /* @__PURE__ */ ((AgentState2) => {
474
548
  AgentState2["IDLE"] = "idle";
475
549
  AgentState2["THINKING"] = "thinking";
@@ -825,15 +899,36 @@ STDERR: ${result.stderr}` });
825
899
  const path2 = tool.params.path || this.runtime.env.cwd();
826
900
  const regexStr = tool.params.regex;
827
901
  const filePattern = tool.params.file_pattern;
902
+ const includeNodeModules = tool.params.include_node_modules === "true";
828
903
  if (regexStr && path2) {
829
904
  try {
830
905
  let result;
831
906
  if (typeof this.runtime.fs.searchFiles === "function") {
832
907
  result = await this.runtime.fs.searchFiles(path2, regexStr, filePattern);
833
908
  } else {
834
- result = await this.searchFiles(path2, regexStr, filePattern);
909
+ result = await this.searchFiles(path2, regexStr, filePattern, includeNodeModules);
910
+ }
911
+ toolResults.push({ tool, result });
912
+ } catch (e) {
913
+ toolResults.push({ tool, result: `Error: ${e.message}` });
914
+ }
915
+ } else {
916
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
917
+ }
918
+ } else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
919
+ const path2 = tool.params.path || this.runtime.env.cwd();
920
+ const regexStr = tool.params.regex;
921
+ const filePattern = tool.params.file_pattern;
922
+ const includeNodeModules = tool.params.include_node_modules === "true";
923
+ if (regexStr && path2) {
924
+ try {
925
+ let result;
926
+ if (typeof this.runtime.fs.searchFileContent === "function") {
927
+ result = await this.runtime.fs.searchFileContent(path2, regexStr, filePattern);
928
+ } else {
929
+ result = await this.searchFileContent(path2, regexStr, filePattern, includeNodeModules);
835
930
  }
836
- toolResults.push({ tool, result: `${result}` });
931
+ toolResults.push({ tool, result });
837
932
  } catch (e) {
838
933
  toolResults.push({ tool, result: `Error: ${e.message}` });
839
934
  }
@@ -1008,13 +1103,80 @@ ${searchBlock.substring(0, 100)}...`);
1008
1103
  async getHistory() {
1009
1104
  return this.memory.getHistory();
1010
1105
  }
1011
- async searchFiles(dirpath, regex, filePattern) {
1106
+ /**
1107
+ * 判断文件是否为可进行内容搜索的文本类文件
1108
+ */
1109
+ isTextFile(name) {
1110
+ const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
1111
+ if (!ext) {
1112
+ return true;
1113
+ }
1114
+ return TEXT_FILE_EXTENSIONS.has(ext);
1115
+ }
1116
+ /**
1117
+ * 按文件名/目录名搜索,层级优先(BFS):
1118
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
1119
+ */
1120
+ async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
1012
1121
  const matches = [];
1013
- const contentRe = new RegExp(regex);
1014
- const nameRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1122
+ const MAX_RESULTS = 100;
1123
+ const MAX_DEPTH = 8;
1015
1124
  const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1125
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1126
+ const nameRe = new RegExp(regex);
1127
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1128
+ const queue = [{ dir: dirpath, depth: 0 }];
1129
+ while (queue.length > 0 && matches.length < MAX_RESULTS) {
1130
+ const { dir, depth } = queue.shift();
1131
+ if (depth > MAX_DEPTH) {
1132
+ continue;
1133
+ }
1134
+ let entries;
1135
+ try {
1136
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1137
+ } catch {
1138
+ continue;
1139
+ }
1140
+ for (const entry of entries) {
1141
+ if (matches.length >= MAX_RESULTS) {
1142
+ break;
1143
+ }
1144
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1145
+ if (entry.isDirectory()) {
1146
+ if (!shouldSkipDir(entry.name)) {
1147
+ if (nameRe.test(entry.name)) {
1148
+ matches.push(`${child}/`);
1149
+ }
1150
+ queue.push({ dir: child, depth: depth + 1 });
1151
+ }
1152
+ } else if (entry.isFile()) {
1153
+ if (globRe && !globRe.test(entry.name)) {
1154
+ continue;
1155
+ }
1156
+ if (nameRe.test(entry.name)) {
1157
+ matches.push(child);
1158
+ }
1159
+ }
1160
+ }
1161
+ }
1162
+ if (matches.length === 0) {
1163
+ return "No files found.";
1164
+ }
1165
+ return matches.join("\n");
1166
+ }
1167
+ /**
1168
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
1169
+ */
1170
+ async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
1171
+ const matches = [];
1172
+ const MAX_RESULTS = 100;
1173
+ const MAX_DEPTH = 8;
1174
+ const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1175
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1176
+ const contentRe = new RegExp(regex);
1177
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1016
1178
  const walk = async (dir, depth) => {
1017
- if (depth > 8 || matches.length >= 100) {
1179
+ if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
1018
1180
  return;
1019
1181
  }
1020
1182
  let entries;
@@ -1024,21 +1186,24 @@ ${searchBlock.substring(0, 100)}...`);
1024
1186
  return;
1025
1187
  }
1026
1188
  for (const entry of entries) {
1027
- if (matches.length >= 100) {
1189
+ if (matches.length >= MAX_RESULTS) {
1028
1190
  break;
1029
1191
  }
1030
1192
  const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1031
1193
  if (entry.isDirectory()) {
1032
- if (!SKIP_DIRS.has(entry.name)) {
1194
+ if (!shouldSkipDir(entry.name)) {
1033
1195
  await walk(child, depth + 1);
1034
1196
  }
1035
1197
  } else if (entry.isFile()) {
1036
- if (nameRe && !nameRe.test(entry.name)) {
1198
+ if (!this.isTextFile(entry.name)) {
1199
+ continue;
1200
+ }
1201
+ if (globRe && !globRe.test(entry.name)) {
1037
1202
  continue;
1038
1203
  }
1039
1204
  try {
1040
- const content = (await this.runtime.fs.readFile(child, "utf8")).toString();
1041
- if (contentRe.test(content)) {
1205
+ const content = await this.runtime.fs.readFile(child);
1206
+ if (typeof content === "string" && contentRe.test(content)) {
1042
1207
  matches.push(child);
1043
1208
  }
1044
1209
  } catch {
@@ -1047,6 +1212,9 @@ ${searchBlock.substring(0, 100)}...`);
1047
1212
  }
1048
1213
  };
1049
1214
  await walk(dirpath, 0);
1215
+ if (matches.length === 0) {
1216
+ return "No files found with matching content.";
1217
+ }
1050
1218
  return matches.join("\n");
1051
1219
  }
1052
1220
  };