@amical/aiagent-sdk 0.1.8 → 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";
@@ -550,7 +624,7 @@ var ClineAgent = class {
550
624
  }
551
625
  }
552
626
  /**
553
- * 获取当前 Agent 的系统提示词
627
+ * 获取当前 Agent 的系统提示词
554
628
  * 如果 force 为 true,则强制重新获取系统提示词
555
629
  */
556
630
  async getPrompt(force = false) {
@@ -825,15 +899,41 @@ 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;
828
- if (regexStr && this.runtime.fs.searchFiles) {
902
+ const includeNodeModules = tool.params.include_node_modules === "true";
903
+ if (regexStr && path2) {
829
904
  try {
830
- const result = await this.runtime.fs.searchFiles(path2, regexStr, filePattern);
831
- toolResults.push({ tool, result: `${result}` });
905
+ let result;
906
+ if (typeof this.runtime.fs.searchFiles === "function") {
907
+ result = await this.runtime.fs.searchFiles(path2, regexStr, filePattern);
908
+ } else {
909
+ result = await this.searchFiles(path2, regexStr, filePattern, includeNodeModules);
910
+ }
911
+ toolResults.push({ tool, result });
832
912
  } catch (e) {
833
913
  toolResults.push({ tool, result: `Error: ${e.message}` });
834
914
  }
835
915
  } else {
836
- toolResults.push({ tool, result: `Error: searchFiles not supported by runtime or missing regex.` });
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);
930
+ }
931
+ toolResults.push({ tool, result });
932
+ } catch (e) {
933
+ toolResults.push({ tool, result: `Error: ${e.message}` });
934
+ }
935
+ } else {
936
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
837
937
  }
838
938
  } else if (tool.name === "agent_use_mcp_tool" /* MCP_USE */) {
839
939
  const serverName = tool.params.server_name;
@@ -938,9 +1038,14 @@ IMPORTANT: The skill is now loaded. Do NOT call agent_load_skill again for this
938
1038
  }
939
1039
  }
940
1040
  if (this.state === "thinking" /* THINKING */ && toolResults.length > 0) {
941
- const toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
1041
+ let toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
942
1042
  ${typeof tr.result === "string" ? tr.result.trim() : JSON.stringify(tr.result)}
943
1043
  </${TOOL_RESULT_BLOCK}>`).join("\n\n");
1044
+ const lastResult = toolResults[toolResults.length - 1];
1045
+ if (lastResult && lastResult.tool.name !== "agent_attempt_completion" /* ATTEMPT */) {
1046
+ toolResultsContext += `
1047
+ ${this.promptManager.getUsedToolResultInstructions()}`;
1048
+ }
944
1049
  if (this.onStreamChunk) {
945
1050
  this.onStreamChunk({ type: "text", text: toolResultsContext });
946
1051
  }
@@ -998,6 +1103,120 @@ ${searchBlock.substring(0, 100)}...`);
998
1103
  async getHistory() {
999
1104
  return this.memory.getHistory();
1000
1105
  }
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) {
1121
+ const matches = [];
1122
+ const MAX_RESULTS = 100;
1123
+ const MAX_DEPTH = 8;
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;
1178
+ const walk = async (dir, depth) => {
1179
+ if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
1180
+ return;
1181
+ }
1182
+ let entries;
1183
+ try {
1184
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1185
+ } catch {
1186
+ return;
1187
+ }
1188
+ for (const entry of entries) {
1189
+ if (matches.length >= MAX_RESULTS) {
1190
+ break;
1191
+ }
1192
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1193
+ if (entry.isDirectory()) {
1194
+ if (!shouldSkipDir(entry.name)) {
1195
+ await walk(child, depth + 1);
1196
+ }
1197
+ } else if (entry.isFile()) {
1198
+ if (!this.isTextFile(entry.name)) {
1199
+ continue;
1200
+ }
1201
+ if (globRe && !globRe.test(entry.name)) {
1202
+ continue;
1203
+ }
1204
+ try {
1205
+ const content = await this.runtime.fs.readFile(child);
1206
+ if (typeof content === "string" && contentRe.test(content)) {
1207
+ matches.push(child);
1208
+ }
1209
+ } catch {
1210
+ }
1211
+ }
1212
+ }
1213
+ };
1214
+ await walk(dirpath, 0);
1215
+ if (matches.length === 0) {
1216
+ return "No files found with matching content.";
1217
+ }
1218
+ return matches.join("\n");
1219
+ }
1001
1220
  };
1002
1221
  var WebApiHandler = class {
1003
1222
  config;
@@ -1372,6 +1591,21 @@ Otherwise, if you have not completed the task and do not need additional informa
1372
1591
  (This is an automated message, so do not respond to it conversationally.)
1373
1592
  ${this?.getEnvironmentInfoPrompt?.(context)}`;
1374
1593
  }
1594
+ getUsedToolResultInstructions() {
1595
+ return `The above are the results of the tool call. Please continue to complete the remaining tasks.
1596
+
1597
+ # TODO LIST UPDATE REQUIRED - You MUST include the task_progress parameter in your NEXT tool call.
1598
+
1599
+ 1. To create or update a todo list, include the task_progress parameter in the next tool call
1600
+ 2. Review each item and update its status:
1601
+ - Mark completed items with: - [x]
1602
+ - Keep incomplete items as: - [ ]
1603
+ - Add new items if you discover additional steps
1604
+ 3. Modify the list as needed:
1605
+ - Add any new steps you've discovered
1606
+ - Reorder if the sequence has changed
1607
+ 4. Ensure the list accurately reflects the current state`;
1608
+ }
1375
1609
  };
1376
1610
 
1377
1611
  // src/memory/WebMemoryManager.ts
@@ -1477,8 +1711,8 @@ var DefaultWebRuntime = class {
1477
1711
  vol = new Volume();
1478
1712
  memfs = createFsFromVolume(this.vol).promises;
1479
1713
  fs = {
1480
- readFile: async (filepath) => {
1481
- const content = await this.memfs.readFile(filepath, "utf-8");
1714
+ readFile: async (filepath, options = "utf8") => {
1715
+ const content = await this.memfs.readFile(filepath, options);
1482
1716
  return content.toString();
1483
1717
  },
1484
1718
  writeFile: async (filepath, content) => {
@@ -1498,8 +1732,8 @@ var DefaultWebRuntime = class {
1498
1732
  return false;
1499
1733
  }
1500
1734
  },
1501
- readDir: (dirpath) => {
1502
- return this.memfs.readdir(dirpath, { withFileTypes: true });
1735
+ readDir: (dirpath, options) => {
1736
+ return this.memfs.readdir(dirpath, { withFileTypes: true, ...options || {} });
1503
1737
  },
1504
1738
  mkdir: async (dirpath) => {
1505
1739
  await this.memfs.mkdir(dirpath, { recursive: true });