@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.
@@ -24,6 +24,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
24
24
  AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
25
25
  AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
26
26
  AgentDefaultTool2["SEARCH"] = "agent_search_files";
27
+ AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
27
28
  AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
28
29
  AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
29
30
  AgentDefaultTool2["BROWSER"] = "agent_browser_action";
@@ -197,11 +198,22 @@ return (
197
198
  },
198
199
  {
199
200
  name: "agent_search_files" /* SEARCH */,
200
- description: "Search for files in a directory that match a regex pattern or glob pattern.",
201
+ 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.",
201
202
  params: {
202
203
  path: "(required) The absolute or relative directory path to search.",
203
- regex: "(required) The regex pattern to match files against.",
204
- file_pattern: "(optional) glob pattern like *.ts."
204
+ regex: "(required) The regex pattern to match file or directory names against.",
205
+ file_pattern: "(optional) glob pattern like *.ts.",
206
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
207
+ }
208
+ },
209
+ {
210
+ name: "agent_search_file_content" /* SEARCH_CONTENT */,
211
+ 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.",
212
+ params: {
213
+ path: "(required) The absolute or relative directory path to search.",
214
+ regex: "(required) The regex pattern to match file content against.",
215
+ file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
216
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
205
217
  }
206
218
  },
207
219
  {
@@ -270,6 +282,7 @@ var READ_ONLY_TOOLS = [
270
282
  "agent_list_files" /* LIST_FILES */,
271
283
  "agent_read_file" /* FILE_READ */,
272
284
  "agent_search_files" /* SEARCH */,
285
+ "agent_search_file_content" /* SEARCH_CONTENT */,
273
286
  "agent_list_code_definition_names" /* LIST_CODE_DEF */,
274
287
  "agent_browser_action" /* BROWSER */,
275
288
  "agent_ask_followup_question" /* ASK */,
@@ -439,6 +452,7 @@ var toolParamNames = [
439
452
  "diff",
440
453
  "regex",
441
454
  "file_pattern",
455
+ "include_node_modules",
442
456
  "recursive",
443
457
  "action",
444
458
  "url",
@@ -477,6 +491,66 @@ var toolParamNames = [
477
491
  "start_line",
478
492
  "end_line"
479
493
  ];
494
+ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
495
+ "txt",
496
+ "md",
497
+ "markdown",
498
+ "json",
499
+ "js",
500
+ "mjs",
501
+ "cjs",
502
+ "ts",
503
+ "tsx",
504
+ "jsx",
505
+ "html",
506
+ "htm",
507
+ "css",
508
+ "scss",
509
+ "sass",
510
+ "less",
511
+ "py",
512
+ "java",
513
+ "c",
514
+ "cpp",
515
+ "cc",
516
+ "cxx",
517
+ "h",
518
+ "hpp",
519
+ "cs",
520
+ "go",
521
+ "rs",
522
+ "rb",
523
+ "php",
524
+ "sh",
525
+ "bash",
526
+ "zsh",
527
+ "bat",
528
+ "cmd",
529
+ "ps1",
530
+ "yaml",
531
+ "yml",
532
+ "toml",
533
+ "ini",
534
+ "cfg",
535
+ "conf",
536
+ "xml",
537
+ "svg",
538
+ "csv",
539
+ "log",
540
+ "sql",
541
+ "vue",
542
+ "svelte",
543
+ "astro",
544
+ "graphql",
545
+ "gql",
546
+ "prisma",
547
+ "env",
548
+ "gitignore",
549
+ "dockerfile",
550
+ "makefile",
551
+ "properties",
552
+ "lock"
553
+ ]);
480
554
  var AgentState = /* @__PURE__ */ ((AgentState2) => {
481
555
  AgentState2["IDLE"] = "idle";
482
556
  AgentState2["THINKING"] = "thinking";
@@ -832,15 +906,36 @@ STDERR: ${result.stderr}` });
832
906
  const path2 = tool.params.path || this.runtime.env.cwd();
833
907
  const regexStr = tool.params.regex;
834
908
  const filePattern = tool.params.file_pattern;
909
+ const includeNodeModules = tool.params.include_node_modules === "true";
835
910
  if (regexStr && path2) {
836
911
  try {
837
912
  let result;
838
913
  if (typeof this.runtime.fs.searchFiles === "function") {
839
914
  result = await this.runtime.fs.searchFiles(path2, regexStr, filePattern);
840
915
  } else {
841
- result = await this.searchFiles(path2, regexStr, filePattern);
916
+ result = await this.searchFiles(path2, regexStr, filePattern, includeNodeModules);
917
+ }
918
+ toolResults.push({ tool, result });
919
+ } catch (e) {
920
+ toolResults.push({ tool, result: `Error: ${e.message}` });
921
+ }
922
+ } else {
923
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
924
+ }
925
+ } else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
926
+ const path2 = tool.params.path || this.runtime.env.cwd();
927
+ const regexStr = tool.params.regex;
928
+ const filePattern = tool.params.file_pattern;
929
+ const includeNodeModules = tool.params.include_node_modules === "true";
930
+ if (regexStr && path2) {
931
+ try {
932
+ let result;
933
+ if (typeof this.runtime.fs.searchFileContent === "function") {
934
+ result = await this.runtime.fs.searchFileContent(path2, regexStr, filePattern);
935
+ } else {
936
+ result = await this.searchFileContent(path2, regexStr, filePattern, includeNodeModules);
842
937
  }
843
- toolResults.push({ tool, result: `${result}` });
938
+ toolResults.push({ tool, result });
844
939
  } catch (e) {
845
940
  toolResults.push({ tool, result: `Error: ${e.message}` });
846
941
  }
@@ -1015,13 +1110,80 @@ ${searchBlock.substring(0, 100)}...`);
1015
1110
  async getHistory() {
1016
1111
  return this.memory.getHistory();
1017
1112
  }
1018
- async searchFiles(dirpath, regex, filePattern) {
1113
+ /**
1114
+ * 判断文件是否为可进行内容搜索的文本类文件
1115
+ */
1116
+ isTextFile(name) {
1117
+ const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
1118
+ if (!ext) {
1119
+ return true;
1120
+ }
1121
+ return TEXT_FILE_EXTENSIONS.has(ext);
1122
+ }
1123
+ /**
1124
+ * 按文件名/目录名搜索,层级优先(BFS):
1125
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
1126
+ */
1127
+ async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
1019
1128
  const matches = [];
1020
- const contentRe = new RegExp(regex);
1021
- const nameRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1129
+ const MAX_RESULTS = 100;
1130
+ const MAX_DEPTH = 8;
1022
1131
  const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1132
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1133
+ const nameRe = new RegExp(regex);
1134
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1135
+ const queue = [{ dir: dirpath, depth: 0 }];
1136
+ while (queue.length > 0 && matches.length < MAX_RESULTS) {
1137
+ const { dir, depth } = queue.shift();
1138
+ if (depth > MAX_DEPTH) {
1139
+ continue;
1140
+ }
1141
+ let entries;
1142
+ try {
1143
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1144
+ } catch {
1145
+ continue;
1146
+ }
1147
+ for (const entry of entries) {
1148
+ if (matches.length >= MAX_RESULTS) {
1149
+ break;
1150
+ }
1151
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1152
+ if (entry.isDirectory()) {
1153
+ if (!shouldSkipDir(entry.name)) {
1154
+ if (nameRe.test(entry.name)) {
1155
+ matches.push(`${child}/`);
1156
+ }
1157
+ queue.push({ dir: child, depth: depth + 1 });
1158
+ }
1159
+ } else if (entry.isFile()) {
1160
+ if (globRe && !globRe.test(entry.name)) {
1161
+ continue;
1162
+ }
1163
+ if (nameRe.test(entry.name)) {
1164
+ matches.push(child);
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ if (matches.length === 0) {
1170
+ return "No files found.";
1171
+ }
1172
+ return matches.join("\n");
1173
+ }
1174
+ /**
1175
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
1176
+ */
1177
+ async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
1178
+ const matches = [];
1179
+ const MAX_RESULTS = 100;
1180
+ const MAX_DEPTH = 8;
1181
+ const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1182
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1183
+ const contentRe = new RegExp(regex);
1184
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1023
1185
  const walk = async (dir, depth) => {
1024
- if (depth > 8 || matches.length >= 100) {
1186
+ if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
1025
1187
  return;
1026
1188
  }
1027
1189
  let entries;
@@ -1031,21 +1193,24 @@ ${searchBlock.substring(0, 100)}...`);
1031
1193
  return;
1032
1194
  }
1033
1195
  for (const entry of entries) {
1034
- if (matches.length >= 100) {
1196
+ if (matches.length >= MAX_RESULTS) {
1035
1197
  break;
1036
1198
  }
1037
1199
  const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1038
1200
  if (entry.isDirectory()) {
1039
- if (!SKIP_DIRS.has(entry.name)) {
1201
+ if (!shouldSkipDir(entry.name)) {
1040
1202
  await walk(child, depth + 1);
1041
1203
  }
1042
1204
  } else if (entry.isFile()) {
1043
- if (nameRe && !nameRe.test(entry.name)) {
1205
+ if (!this.isTextFile(entry.name)) {
1206
+ continue;
1207
+ }
1208
+ if (globRe && !globRe.test(entry.name)) {
1044
1209
  continue;
1045
1210
  }
1046
1211
  try {
1047
- const content = (await this.runtime.fs.readFile(child, "utf8")).toString();
1048
- if (contentRe.test(content)) {
1212
+ const content = await this.runtime.fs.readFile(child);
1213
+ if (typeof content === "string" && contentRe.test(content)) {
1049
1214
  matches.push(child);
1050
1215
  }
1051
1216
  } catch {
@@ -1054,6 +1219,9 @@ ${searchBlock.substring(0, 100)}...`);
1054
1219
  }
1055
1220
  };
1056
1221
  await walk(dirpath, 0);
1222
+ if (matches.length === 0) {
1223
+ return "No files found with matching content.";
1224
+ }
1057
1225
  return matches.join("\n");
1058
1226
  }
1059
1227
  };