@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.
- package/dist/index.d.mts +36 -7
- package/dist/index.d.ts +36 -7
- package/dist/index.js +228 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +228 -9
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/nodeRuntime.d.mts +3 -3
- package/dist/runtime/nodeRuntime.d.ts +3 -3
- package/dist/runtime/nodeRuntime.js +256 -19
- package/dist/runtime/nodeRuntime.js.map +1 -1
- package/dist/runtime/nodeRuntime.mjs +255 -18
- package/dist/runtime/nodeRuntime.mjs.map +1 -1
- package/dist/runtime/webRuntime.d.mts +3 -2
- package/dist/runtime/webRuntime.d.ts +3 -2
- package/dist/runtime/webRuntime.js +247 -13
- package/dist/runtime/webRuntime.js.map +1 -1
- package/dist/runtime/webRuntime.mjs +247 -13
- package/dist/runtime/webRuntime.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { streamText } from 'ai';
|
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
5
|
import { createDifyProvider } from 'dify-ai-provider';
|
|
6
6
|
import * as fs2 from 'fs/promises';
|
|
7
|
-
import * as
|
|
7
|
+
import * as path from 'path';
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import { exec } from 'child_process';
|
|
10
10
|
import { promisify } from 'util';
|
|
@@ -22,6 +22,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
|
|
|
22
22
|
AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
|
|
23
23
|
AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
|
|
24
24
|
AgentDefaultTool2["SEARCH"] = "agent_search_files";
|
|
25
|
+
AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
|
|
25
26
|
AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
|
|
26
27
|
AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
|
|
27
28
|
AgentDefaultTool2["BROWSER"] = "agent_browser_action";
|
|
@@ -195,11 +196,22 @@ return (
|
|
|
195
196
|
},
|
|
196
197
|
{
|
|
197
198
|
name: "agent_search_files" /* SEARCH */,
|
|
198
|
-
description: "Search for files in a directory
|
|
199
|
+
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.",
|
|
199
200
|
params: {
|
|
200
201
|
path: "(required) The absolute or relative directory path to search.",
|
|
201
|
-
regex: "(required) The regex pattern to match
|
|
202
|
-
file_pattern: "(optional) glob pattern like *.ts."
|
|
202
|
+
regex: "(required) The regex pattern to match file or directory names against.",
|
|
203
|
+
file_pattern: "(optional) glob pattern like *.ts.",
|
|
204
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "agent_search_file_content" /* SEARCH_CONTENT */,
|
|
209
|
+
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.",
|
|
210
|
+
params: {
|
|
211
|
+
path: "(required) The absolute or relative directory path to search.",
|
|
212
|
+
regex: "(required) The regex pattern to match file content against.",
|
|
213
|
+
file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
|
|
214
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
203
215
|
}
|
|
204
216
|
},
|
|
205
217
|
{
|
|
@@ -268,6 +280,7 @@ var READ_ONLY_TOOLS = [
|
|
|
268
280
|
"agent_list_files" /* LIST_FILES */,
|
|
269
281
|
"agent_read_file" /* FILE_READ */,
|
|
270
282
|
"agent_search_files" /* SEARCH */,
|
|
283
|
+
"agent_search_file_content" /* SEARCH_CONTENT */,
|
|
271
284
|
"agent_list_code_definition_names" /* LIST_CODE_DEF */,
|
|
272
285
|
"agent_browser_action" /* BROWSER */,
|
|
273
286
|
"agent_ask_followup_question" /* ASK */,
|
|
@@ -437,6 +450,7 @@ var toolParamNames = [
|
|
|
437
450
|
"diff",
|
|
438
451
|
"regex",
|
|
439
452
|
"file_pattern",
|
|
453
|
+
"include_node_modules",
|
|
440
454
|
"recursive",
|
|
441
455
|
"action",
|
|
442
456
|
"url",
|
|
@@ -475,6 +489,66 @@ var toolParamNames = [
|
|
|
475
489
|
"start_line",
|
|
476
490
|
"end_line"
|
|
477
491
|
];
|
|
492
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
493
|
+
"txt",
|
|
494
|
+
"md",
|
|
495
|
+
"markdown",
|
|
496
|
+
"json",
|
|
497
|
+
"js",
|
|
498
|
+
"mjs",
|
|
499
|
+
"cjs",
|
|
500
|
+
"ts",
|
|
501
|
+
"tsx",
|
|
502
|
+
"jsx",
|
|
503
|
+
"html",
|
|
504
|
+
"htm",
|
|
505
|
+
"css",
|
|
506
|
+
"scss",
|
|
507
|
+
"sass",
|
|
508
|
+
"less",
|
|
509
|
+
"py",
|
|
510
|
+
"java",
|
|
511
|
+
"c",
|
|
512
|
+
"cpp",
|
|
513
|
+
"cc",
|
|
514
|
+
"cxx",
|
|
515
|
+
"h",
|
|
516
|
+
"hpp",
|
|
517
|
+
"cs",
|
|
518
|
+
"go",
|
|
519
|
+
"rs",
|
|
520
|
+
"rb",
|
|
521
|
+
"php",
|
|
522
|
+
"sh",
|
|
523
|
+
"bash",
|
|
524
|
+
"zsh",
|
|
525
|
+
"bat",
|
|
526
|
+
"cmd",
|
|
527
|
+
"ps1",
|
|
528
|
+
"yaml",
|
|
529
|
+
"yml",
|
|
530
|
+
"toml",
|
|
531
|
+
"ini",
|
|
532
|
+
"cfg",
|
|
533
|
+
"conf",
|
|
534
|
+
"xml",
|
|
535
|
+
"svg",
|
|
536
|
+
"csv",
|
|
537
|
+
"log",
|
|
538
|
+
"sql",
|
|
539
|
+
"vue",
|
|
540
|
+
"svelte",
|
|
541
|
+
"astro",
|
|
542
|
+
"graphql",
|
|
543
|
+
"gql",
|
|
544
|
+
"prisma",
|
|
545
|
+
"env",
|
|
546
|
+
"gitignore",
|
|
547
|
+
"dockerfile",
|
|
548
|
+
"makefile",
|
|
549
|
+
"properties",
|
|
550
|
+
"lock"
|
|
551
|
+
]);
|
|
478
552
|
var AgentState = /* @__PURE__ */ ((AgentState2) => {
|
|
479
553
|
AgentState2["IDLE"] = "idle";
|
|
480
554
|
AgentState2["THINKING"] = "thinking";
|
|
@@ -555,7 +629,7 @@ var ClineAgent = class {
|
|
|
555
629
|
}
|
|
556
630
|
}
|
|
557
631
|
/**
|
|
558
|
-
* 获取当前 Agent 的系统提示词
|
|
632
|
+
* 获取当前 Agent 的系统提示词
|
|
559
633
|
* 如果 force 为 true,则强制重新获取系统提示词
|
|
560
634
|
*/
|
|
561
635
|
async getPrompt(force = false) {
|
|
@@ -830,15 +904,41 @@ STDERR: ${result.stderr}` });
|
|
|
830
904
|
const path3 = tool.params.path || this.runtime.env.cwd();
|
|
831
905
|
const regexStr = tool.params.regex;
|
|
832
906
|
const filePattern = tool.params.file_pattern;
|
|
833
|
-
|
|
907
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
908
|
+
if (regexStr && path3) {
|
|
834
909
|
try {
|
|
835
|
-
|
|
836
|
-
|
|
910
|
+
let result;
|
|
911
|
+
if (typeof this.runtime.fs.searchFiles === "function") {
|
|
912
|
+
result = await this.runtime.fs.searchFiles(path3, regexStr, filePattern);
|
|
913
|
+
} else {
|
|
914
|
+
result = await this.searchFiles(path3, regexStr, filePattern, includeNodeModules);
|
|
915
|
+
}
|
|
916
|
+
toolResults.push({ tool, result });
|
|
837
917
|
} catch (e) {
|
|
838
918
|
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
839
919
|
}
|
|
840
920
|
} else {
|
|
841
|
-
toolResults.push({ tool, result: `Error:
|
|
921
|
+
toolResults.push({ tool, result: `Error: miss path or regex params` });
|
|
922
|
+
}
|
|
923
|
+
} else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
|
|
924
|
+
const path3 = tool.params.path || this.runtime.env.cwd();
|
|
925
|
+
const regexStr = tool.params.regex;
|
|
926
|
+
const filePattern = tool.params.file_pattern;
|
|
927
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
928
|
+
if (regexStr && path3) {
|
|
929
|
+
try {
|
|
930
|
+
let result;
|
|
931
|
+
if (typeof this.runtime.fs.searchFileContent === "function") {
|
|
932
|
+
result = await this.runtime.fs.searchFileContent(path3, regexStr, filePattern);
|
|
933
|
+
} else {
|
|
934
|
+
result = await this.searchFileContent(path3, regexStr, filePattern, includeNodeModules);
|
|
935
|
+
}
|
|
936
|
+
toolResults.push({ tool, result });
|
|
937
|
+
} catch (e) {
|
|
938
|
+
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
toolResults.push({ tool, result: `Error: miss path or regex params` });
|
|
842
942
|
}
|
|
843
943
|
} else if (tool.name === "agent_use_mcp_tool" /* MCP_USE */) {
|
|
844
944
|
const serverName = tool.params.server_name;
|
|
@@ -943,9 +1043,14 @@ IMPORTANT: The skill is now loaded. Do NOT call agent_load_skill again for this
|
|
|
943
1043
|
}
|
|
944
1044
|
}
|
|
945
1045
|
if (this.state === "thinking" /* THINKING */ && toolResults.length > 0) {
|
|
946
|
-
|
|
1046
|
+
let toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
|
|
947
1047
|
${typeof tr.result === "string" ? tr.result.trim() : JSON.stringify(tr.result)}
|
|
948
1048
|
</${TOOL_RESULT_BLOCK}>`).join("\n\n");
|
|
1049
|
+
const lastResult = toolResults[toolResults.length - 1];
|
|
1050
|
+
if (lastResult && lastResult.tool.name !== "agent_attempt_completion" /* ATTEMPT */) {
|
|
1051
|
+
toolResultsContext += `
|
|
1052
|
+
${this.promptManager.getUsedToolResultInstructions()}`;
|
|
1053
|
+
}
|
|
949
1054
|
if (this.onStreamChunk) {
|
|
950
1055
|
this.onStreamChunk({ type: "text", text: toolResultsContext });
|
|
951
1056
|
}
|
|
@@ -1003,6 +1108,120 @@ ${searchBlock.substring(0, 100)}...`);
|
|
|
1003
1108
|
async getHistory() {
|
|
1004
1109
|
return this.memory.getHistory();
|
|
1005
1110
|
}
|
|
1111
|
+
/**
|
|
1112
|
+
* 判断文件是否为可进行内容搜索的文本类文件
|
|
1113
|
+
*/
|
|
1114
|
+
isTextFile(name) {
|
|
1115
|
+
const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
|
|
1116
|
+
if (!ext) {
|
|
1117
|
+
return true;
|
|
1118
|
+
}
|
|
1119
|
+
return TEXT_FILE_EXTENSIONS.has(ext);
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* 按文件名/目录名搜索,层级优先(BFS):
|
|
1123
|
+
* 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
|
|
1124
|
+
*/
|
|
1125
|
+
async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1126
|
+
const matches = [];
|
|
1127
|
+
const MAX_RESULTS = 100;
|
|
1128
|
+
const MAX_DEPTH = 8;
|
|
1129
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1130
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1131
|
+
const nameRe = new RegExp(regex);
|
|
1132
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1133
|
+
const queue = [{ dir: dirpath, depth: 0 }];
|
|
1134
|
+
while (queue.length > 0 && matches.length < MAX_RESULTS) {
|
|
1135
|
+
const { dir, depth } = queue.shift();
|
|
1136
|
+
if (depth > MAX_DEPTH) {
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
let entries;
|
|
1140
|
+
try {
|
|
1141
|
+
entries = await this.runtime.fs.readDir(dir, { recursive: false });
|
|
1142
|
+
} catch {
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
for (const entry of entries) {
|
|
1146
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1150
|
+
if (entry.isDirectory()) {
|
|
1151
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1152
|
+
if (nameRe.test(entry.name)) {
|
|
1153
|
+
matches.push(`${child}/`);
|
|
1154
|
+
}
|
|
1155
|
+
queue.push({ dir: child, depth: depth + 1 });
|
|
1156
|
+
}
|
|
1157
|
+
} else if (entry.isFile()) {
|
|
1158
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
if (nameRe.test(entry.name)) {
|
|
1162
|
+
matches.push(child);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
if (matches.length === 0) {
|
|
1168
|
+
return "No files found.";
|
|
1169
|
+
}
|
|
1170
|
+
return matches.join("\n");
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
|
|
1174
|
+
*/
|
|
1175
|
+
async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1176
|
+
const matches = [];
|
|
1177
|
+
const MAX_RESULTS = 100;
|
|
1178
|
+
const MAX_DEPTH = 8;
|
|
1179
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1180
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1181
|
+
const contentRe = new RegExp(regex);
|
|
1182
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1183
|
+
const walk = async (dir, depth) => {
|
|
1184
|
+
if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
let entries;
|
|
1188
|
+
try {
|
|
1189
|
+
entries = await this.runtime.fs.readDir(dir, { recursive: false });
|
|
1190
|
+
} catch {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
for (const entry of entries) {
|
|
1194
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1195
|
+
break;
|
|
1196
|
+
}
|
|
1197
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1198
|
+
if (entry.isDirectory()) {
|
|
1199
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1200
|
+
await walk(child, depth + 1);
|
|
1201
|
+
}
|
|
1202
|
+
} else if (entry.isFile()) {
|
|
1203
|
+
if (!this.isTextFile(entry.name)) {
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
const content = await this.runtime.fs.readFile(child);
|
|
1211
|
+
if (typeof content === "string" && contentRe.test(content)) {
|
|
1212
|
+
matches.push(child);
|
|
1213
|
+
}
|
|
1214
|
+
} catch {
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
await walk(dirpath, 0);
|
|
1220
|
+
if (matches.length === 0) {
|
|
1221
|
+
return "No files found with matching content.";
|
|
1222
|
+
}
|
|
1223
|
+
return matches.join("\n");
|
|
1224
|
+
}
|
|
1006
1225
|
};
|
|
1007
1226
|
var NodeApiHandler = class {
|
|
1008
1227
|
config;
|
|
@@ -1377,6 +1596,21 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|
|
1377
1596
|
(This is an automated message, so do not respond to it conversationally.)
|
|
1378
1597
|
${this?.getEnvironmentInfoPrompt?.(context)}`;
|
|
1379
1598
|
}
|
|
1599
|
+
getUsedToolResultInstructions() {
|
|
1600
|
+
return `The above are the results of the tool call. Please continue to complete the remaining tasks.
|
|
1601
|
+
|
|
1602
|
+
# TODO LIST UPDATE REQUIRED - You MUST include the task_progress parameter in your NEXT tool call.
|
|
1603
|
+
|
|
1604
|
+
1. To create or update a todo list, include the task_progress parameter in the next tool call
|
|
1605
|
+
2. Review each item and update its status:
|
|
1606
|
+
- Mark completed items with: - [x]
|
|
1607
|
+
- Keep incomplete items as: - [ ]
|
|
1608
|
+
- Add new items if you discover additional steps
|
|
1609
|
+
3. Modify the list as needed:
|
|
1610
|
+
- Add any new steps you've discovered
|
|
1611
|
+
- Reorder if the sequence has changed
|
|
1612
|
+
4. Ensure the list accurately reflects the current state`;
|
|
1613
|
+
}
|
|
1380
1614
|
};
|
|
1381
1615
|
var NodeMemoryManager = class {
|
|
1382
1616
|
filePath;
|
|
@@ -1386,14 +1620,14 @@ var NodeMemoryManager = class {
|
|
|
1386
1620
|
* @param maxMessages 保留的最大消息数量,用于简单的历史截断(默认 150)
|
|
1387
1621
|
*/
|
|
1388
1622
|
constructor(dbPath, maxMessages = 150) {
|
|
1389
|
-
this.filePath =
|
|
1623
|
+
this.filePath = path.resolve(dbPath);
|
|
1390
1624
|
this.maxMessages = maxMessages;
|
|
1391
1625
|
}
|
|
1392
1626
|
async ensureFile() {
|
|
1393
1627
|
try {
|
|
1394
1628
|
await fs2.access(this.filePath);
|
|
1395
1629
|
} catch {
|
|
1396
|
-
const dir =
|
|
1630
|
+
const dir = path.dirname(this.filePath);
|
|
1397
1631
|
await fs2.mkdir(dir, { recursive: true });
|
|
1398
1632
|
await fs2.writeFile(this.filePath, "[]", "utf-8");
|
|
1399
1633
|
}
|
|
@@ -1569,10 +1803,13 @@ var NodeMcpManager = class {
|
|
|
1569
1803
|
var execAsync = promisify(exec);
|
|
1570
1804
|
var DefaultNodeRuntime = class {
|
|
1571
1805
|
fs = {
|
|
1572
|
-
readFile: async (filepath) => fs2.readFile(filepath,
|
|
1806
|
+
readFile: async (filepath, options = "utf8") => fs2.readFile(filepath, options),
|
|
1573
1807
|
writeFile: async (filepath, content) => {
|
|
1574
|
-
|
|
1575
|
-
|
|
1808
|
+
const dir = filepath.substring(0, filepath.lastIndexOf("/"));
|
|
1809
|
+
if (dir && dir !== filepath) {
|
|
1810
|
+
await fs2.mkdir(dir, { recursive: true });
|
|
1811
|
+
}
|
|
1812
|
+
await fs2.writeFile(filepath, content, "utf8");
|
|
1576
1813
|
},
|
|
1577
1814
|
deleteFile: (filepath) => fs2.unlink(filepath),
|
|
1578
1815
|
deleteDirectory: (dirpath) => fs2.rm(dirpath, { recursive: true, force: true }),
|
|
@@ -1584,13 +1821,13 @@ var DefaultNodeRuntime = class {
|
|
|
1584
1821
|
return false;
|
|
1585
1822
|
}
|
|
1586
1823
|
},
|
|
1587
|
-
readDir: (dirpath) => fs2.readdir(dirpath, { withFileTypes: true }),
|
|
1824
|
+
readDir: (dirpath, options) => fs2.readdir(dirpath, { withFileTypes: true, ...options || {} }),
|
|
1588
1825
|
mkdir: async (dirpath) => {
|
|
1589
1826
|
await fs2.mkdir(dirpath, { recursive: true });
|
|
1590
1827
|
}
|
|
1591
1828
|
};
|
|
1592
1829
|
path = {
|
|
1593
|
-
join: (...paths) =>
|
|
1830
|
+
join: (...paths) => path.join(...paths)
|
|
1594
1831
|
};
|
|
1595
1832
|
env = {
|
|
1596
1833
|
get: (key) => process.env[key],
|
|
@@ -1612,7 +1849,7 @@ var DefaultNodeRuntime = class {
|
|
|
1612
1849
|
function createNodeAgent(options) {
|
|
1613
1850
|
const runtime = new DefaultNodeRuntime();
|
|
1614
1851
|
const api = new NodeApiHandler(options.apiConfig);
|
|
1615
|
-
const memory = options.memory || new NodeMemoryManager(options.dbPath ||
|
|
1852
|
+
const memory = options.memory || new NodeMemoryManager(options.dbPath || path.join(runtime.env.cwd(), ".cline_memory.json"));
|
|
1616
1853
|
const customTools = options.customTools || [];
|
|
1617
1854
|
const customToolNames = new Set(customTools.map((t) => t.name));
|
|
1618
1855
|
const promptManager = new NodePromptManager();
|