evoltagent 1.1.1 → 1.1.2

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.js ADDED
@@ -0,0 +1,4829 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+
12
+ // src/utils/connections.ts
13
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
14
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
15
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
16
+
17
+ // src/schemas/toolCall.ts
18
+ import { randomUUID } from "crypto";
19
+ var Toolcall = class {
20
+ name;
21
+ input;
22
+ isExtractedSuccess;
23
+ failedExtractedReason;
24
+ executedState;
25
+ executedContent;
26
+ toolCallId;
27
+ type;
28
+ rawContentFromLlm;
29
+ constructor(config2) {
30
+ this.name = config2.name;
31
+ this.input = config2.input || {};
32
+ this.isExtractedSuccess = config2.isExtractedSuccess ?? true;
33
+ this.failedExtractedReason = config2.failedExtractedReason;
34
+ this.executedState = config2.executedState || "pending";
35
+ this.executedContent = config2.executedContent;
36
+ this.toolCallId = config2.toolCallId || randomUUID();
37
+ this.type = config2.type || "system";
38
+ this.rawContentFromLlm = config2.rawContentFromLlm;
39
+ }
40
+ /**
41
+ * Toolcall extraction result description
42
+ */
43
+ extractedResult() {
44
+ if (this.type === "TaskCompletion") {
45
+ return this.rawContentFromLlm || "";
46
+ }
47
+ if (this.type === "user") {
48
+ if (!this.isExtractedSuccess) {
49
+ return [
50
+ {
51
+ role: "assistant",
52
+ tool_calls: [
53
+ {
54
+ id: `user_tool_${this.toolCallId}`,
55
+ type: "function",
56
+ function: {
57
+ name: this.name,
58
+ arguments: this.rawContentFromLlm
59
+ }
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ role: "tool",
65
+ tool_call_id: `user_tool_${this.toolCallId}`,
66
+ name: this.name,
67
+ content: this.failedExtractedReason || "Unknown reason"
68
+ }
69
+ ];
70
+ }
71
+ logger.debug(`User Toolcall: ${this.name}(${JSON.stringify(this.input)})`);
72
+ return {
73
+ role: "assistant",
74
+ tool_calls: [
75
+ {
76
+ id: `user_tool_${this.toolCallId}`,
77
+ type: "function",
78
+ function: {
79
+ name: this.name,
80
+ arguments: JSON.stringify(this.input)
81
+ }
82
+ }
83
+ ]
84
+ };
85
+ }
86
+ if (!this.isExtractedSuccess) {
87
+ return `Toolcall ${this.name} failed to extract: ${this.failedExtractedReason || "Unknown reason"}`;
88
+ }
89
+ if (this.name) {
90
+ const inputStr = Object.entries(this.input).map(([k, v]) => `<${k}>${v}</${k}>`).join("");
91
+ return `<${this.name}>${inputStr}</${this.name}>`;
92
+ }
93
+ return `Invalid Toolcall: name ${this.name}, arguments ${JSON.stringify(this.input)}.`;
94
+ }
95
+ /**
96
+ * Toolcall execution result: Feedback to LLM
97
+ */
98
+ executedResult() {
99
+ if (this.type === "TaskCompletion") {
100
+ return "The task has been completed.";
101
+ }
102
+ if (this.type === "user") {
103
+ if (!this.isExtractedSuccess) {
104
+ return "";
105
+ }
106
+ return {
107
+ role: "tool",
108
+ tool_call_id: this.toolCallId,
109
+ // Use the original tool_call_id without prefix
110
+ name: this.name,
111
+ content: (this.executedContent || "No execution result found.").trim()
112
+ };
113
+ }
114
+ if (this.name.startsWith("ThinkTool.execute") || this.name.startsWith("TodoListTool.write")) {
115
+ return (this.executedContent || "No thinking result found.").trim();
116
+ }
117
+ let toolcallDescription = "";
118
+ let observation = "";
119
+ if (this.name.startsWith("FileEditor.write")) {
120
+ toolcallDescription = `FileEditor.write(${this.input.path})`;
121
+ } else {
122
+ toolcallDescription = `${this.name}(${JSON.stringify(this.input)})`;
123
+ }
124
+ observation += `Executed content: ${(this.executedContent || "None").trim()}
125
+ `;
126
+ return `Toolcall: ${toolcallDescription}
127
+ Observation: ${observation}`;
128
+ }
129
+ };
130
+
131
+ // src/utils/toolUtil.ts
132
+ function isWriteJsonFile(argumentsTxt, toolName) {
133
+ if (!toolName.startsWith("FileEditor.") && !toolName.startsWith("ApiTool.")) {
134
+ return false;
135
+ }
136
+ const pattern = /\.json\s*<\/(path|filePath|apiFilePath)>/;
137
+ return pattern.test(argumentsTxt);
138
+ }
139
+ function unescapeHtmlEntities(str) {
140
+ let result = str;
141
+ result = result.replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
142
+ result = result.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
143
+ result = result.replace(/&(?:quot|amp|lt|gt|apos);/g, (match) => {
144
+ const entities = {
145
+ "&quot;": '"',
146
+ "&amp;": "&",
147
+ "&lt;": "<",
148
+ "&gt;": ">",
149
+ "&apos;": "'"
150
+ };
151
+ return entities[match] || match;
152
+ });
153
+ return result;
154
+ }
155
+ function convertStrToObject(txt, toolName, argNames) {
156
+ const result = {};
157
+ const startTag = `<${toolName}>`;
158
+ const endTag = `</${toolName}>`;
159
+ const toolPattern = new RegExp(`${escapeRegExp(startTag)}(.*?)${escapeRegExp(endTag)}`, "s");
160
+ const toolMatch = toolPattern.exec(txt);
161
+ if (!toolMatch) {
162
+ return result;
163
+ }
164
+ const innerContent = toolMatch[1];
165
+ for (const argName of argNames) {
166
+ const argStartTag = `<${argName}>`;
167
+ const argEndTag = `</${argName}>`;
168
+ const argPattern = new RegExp(`${escapeRegExp(argStartTag)}(.*?)${escapeRegExp(argEndTag)}`, "s");
169
+ const argMatch = argPattern.exec(innerContent);
170
+ if (argMatch) {
171
+ let value = argMatch[1].trim();
172
+ value = unescapeHtmlEntities(value);
173
+ if (isWriteJsonFile(txt, toolName)) {
174
+ result[argName] = value;
175
+ continue;
176
+ }
177
+ try {
178
+ const parsedValue = JSON.parse(value);
179
+ result[argName] = parsedValue;
180
+ } catch {
181
+ result[argName] = value;
182
+ }
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ function extractToolcallsFromStr(txt, toolStore) {
188
+ const matches = [];
189
+ for (const toolName of Object.keys(toolStore)) {
190
+ const pattern = new RegExp(`<${escapeRegExp(toolName)}>(.*?)</${escapeRegExp(toolName)}>`, "gs");
191
+ let match;
192
+ while ((match = pattern.exec(txt)) !== null) {
193
+ const argumentsTxt = match[1].trim();
194
+ if (!isWriteJsonFile(argumentsTxt, toolName) && argumentsTxt.startsWith("{") && argumentsTxt.endsWith("}")) {
195
+ matches.push([
196
+ match.index,
197
+ new Toolcall({
198
+ name: toolName,
199
+ input: {},
200
+ isExtractedSuccess: false,
201
+ type: "system",
202
+ rawContentFromLlm: txt
203
+ })
204
+ ]);
205
+ continue;
206
+ }
207
+ const rawInput = `<${toolName}>${argumentsTxt}</${toolName}>`;
208
+ let pythonObjectInput = {};
209
+ if (rawInput) {
210
+ const argNames = toolStore[toolName].argNames || [];
211
+ pythonObjectInput = convertStrToObject(rawInput, toolName, argNames);
212
+ }
213
+ matches.push([
214
+ match.index,
215
+ new Toolcall({
216
+ name: toolName,
217
+ input: pythonObjectInput,
218
+ type: "system"
219
+ })
220
+ ]);
221
+ }
222
+ }
223
+ matches.sort((a, b) => a[0] - b[0]);
224
+ return matches.map(([, tc]) => tc);
225
+ }
226
+ async function executeSingleTool(toolcall, toolStore) {
227
+ if (!Array.isArray(toolStore)) {
228
+ toolStore = [toolStore];
229
+ }
230
+ if (!toolcall.isExtractedSuccess) {
231
+ return toolcall;
232
+ }
233
+ try {
234
+ if (toolcall.name && !toolcall.name.startsWith("FileEditor.") && !toolcall.name.startsWith("ThinkTool.")) {
235
+ logger.info(`Executing Tool ${toolcall.name} with arguments: ${JSON.stringify(toolcall.input)}`);
236
+ }
237
+ for (const ts of toolStore) {
238
+ let toolCall;
239
+ let argNames = [];
240
+ if (typeof ts.hasTool === "function" && ts.hasTool(toolcall.name)) {
241
+ const toolDesc = ts.getTool(toolcall.name);
242
+ toolCall = toolDesc ? toolDesc.execute : void 0;
243
+ argNames = toolDesc ? toolDesc.argNames : [];
244
+ } else if (toolcall.name in ts) {
245
+ toolCall = ts[toolcall.name].execute;
246
+ argNames = ts[toolcall.name].argNames || [];
247
+ }
248
+ if (toolCall) {
249
+ let result;
250
+ if (typeof toolCall === "function") {
251
+ if (argNames && argNames.length > 0) {
252
+ const args = argNames.map((name) => toolcall.input[name]);
253
+ result = await toolCall(...args);
254
+ } else {
255
+ result = await toolCall(toolcall.input);
256
+ }
257
+ } else {
258
+ logger.error(`Tool ${toolcall.name} is not callable`);
259
+ toolcall.executedContent = `Tool '${toolcall.name}' is not callable`;
260
+ toolcall.executedState = "failed";
261
+ return toolcall;
262
+ }
263
+ toolcall.executedContent = String(result);
264
+ toolcall.executedState = "success";
265
+ return toolcall;
266
+ }
267
+ }
268
+ toolcall.executedContent = `Tool '${toolcall.name}' not found in tool_store. Please check the tool name.`;
269
+ toolcall.executedState = "failed";
270
+ return toolcall;
271
+ } catch (error) {
272
+ const errorMsg = `Error executing tool: ${error}`;
273
+ toolcall.executedContent = errorMsg;
274
+ toolcall.executedState = "failed";
275
+ return toolcall;
276
+ }
277
+ }
278
+ function escapeRegExp(string) {
279
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
280
+ }
281
+
282
+ // src/utils/logger.ts
283
+ import * as winston from "winston";
284
+ import * as fs from "fs";
285
+ import * as dotenv from "dotenv";
286
+ dotenv.config();
287
+ var getDisableLog = () => {
288
+ return process.env.DISABLE_LOG == "true" || !("DISABLE_LOG" in process.env);
289
+ };
290
+ var winstonLevels = {
291
+ error: 0,
292
+ warn: 1,
293
+ info: 2,
294
+ http: 3,
295
+ verbose: 4,
296
+ debug: 5,
297
+ silly: 6
298
+ };
299
+ var getLogLevel = () => {
300
+ const envLevel = process.env.LOG_LEVEL?.toLowerCase() || "error";
301
+ const levelMapping = {
302
+ fatal: "error",
303
+ trace: "debug"
304
+ };
305
+ return levelMapping[envLevel] || envLevel;
306
+ };
307
+ var loguruFormat = winston.format.combine(
308
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
309
+ winston.format.errors({ stack: true }),
310
+ winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
311
+ const formattedLevel = level.toUpperCase().padEnd(7);
312
+ const caller = meta.caller || meta[0]?.caller;
313
+ const location = caller ? `${String(caller).padEnd(35)} | ` : "";
314
+ const msg = stack || message;
315
+ return `${timestamp} | ${formattedLevel} | ${location}${msg}`;
316
+ })
317
+ );
318
+ var loguruFormatColored = winston.format.combine(
319
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
320
+ winston.format.errors({ stack: true }),
321
+ winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
322
+ const levelUpper = level.toUpperCase().padEnd(7);
323
+ let coloredLevel = levelUpper;
324
+ if (level === "error") {
325
+ coloredLevel = `\x1B[31m${levelUpper}\x1B[39m`;
326
+ } else if (level === "warn") {
327
+ coloredLevel = `\x1B[33m${levelUpper}\x1B[39m`;
328
+ } else if (level === "info") {
329
+ coloredLevel = `\x1B[36m${levelUpper}\x1B[39m`;
330
+ } else if (level === "debug") {
331
+ coloredLevel = `\x1B[34m${levelUpper}\x1B[39m`;
332
+ }
333
+ const caller = meta.caller || meta[0]?.caller;
334
+ const location = caller ? `\x1B[90m${String(caller).padEnd(35)}\x1B[39m | ` : "";
335
+ const msg = stack || message;
336
+ return `${timestamp} | ${coloredLevel} | ${location}${msg}`;
337
+ })
338
+ );
339
+ var createLoggerTransports = () => {
340
+ if (getDisableLog()) {
341
+ return [];
342
+ }
343
+ const output = process.env.LOG_OUTPUT;
344
+ if (!output || output === "console") {
345
+ return [
346
+ new winston.transports.Console({
347
+ level: getLogLevel(),
348
+ format: loguruFormatColored,
349
+ stderrLevels: ["error"]
350
+ // Only error goes to stderr
351
+ })
352
+ ];
353
+ } else if (output === "stdout") {
354
+ return [
355
+ new winston.transports.Stream({
356
+ stream: process.stdout,
357
+ format: loguruFormat
358
+ })
359
+ ];
360
+ } else if (output === "stderr") {
361
+ return [
362
+ new winston.transports.Stream({
363
+ stream: process.stderr,
364
+ format: loguruFormat
365
+ })
366
+ ];
367
+ } else {
368
+ return [
369
+ new winston.transports.Console({
370
+ level: getLogLevel(),
371
+ format: loguruFormatColored,
372
+ stderrLevels: ["error"]
373
+ // Only error goes to stderr
374
+ }),
375
+ new winston.transports.File({
376
+ filename: output,
377
+ format: loguruFormat
378
+ })
379
+ ];
380
+ }
381
+ };
382
+ var logger2 = winston.createLogger({
383
+ levels: winstonLevels,
384
+ level: getLogLevel(),
385
+ transports: createLoggerTransports()
386
+ });
387
+ winston.addColors({
388
+ error: "red",
389
+ warn: "yellow",
390
+ info: "cyan",
391
+ http: "green",
392
+ verbose: "blue",
393
+ debug: "blue",
394
+ silly: "magenta"
395
+ });
396
+ function captureCallerInfo() {
397
+ const stack = new Error().stack;
398
+ if (!stack) return "";
399
+ const lines = stack.split("\n");
400
+ for (let i = 3; i < lines.length; i++) {
401
+ const line = lines[i];
402
+ const match = line.match(/\(([^)]+):(\d+):\d+\)/) || line.match(/at\s+([^()\s]+):(\d+):\d+/);
403
+ if (match && match[1]) {
404
+ const fullPath = match[1];
405
+ const lineNum = match[2];
406
+ if (fullPath.includes("node_modules") || fullPath.endsWith("logger.ts") || fullPath.endsWith("logger.js")) {
407
+ continue;
408
+ }
409
+ const workspaceRoot = process.cwd();
410
+ let displayPath = fullPath;
411
+ if (fullPath.startsWith(workspaceRoot)) {
412
+ displayPath = fullPath.substring(workspaceRoot.length + 1);
413
+ } else {
414
+ const parts = fullPath.split(/[/\\]/);
415
+ displayPath = parts[parts.length - 1];
416
+ }
417
+ return `${displayPath}:${lineNum}`;
418
+ }
419
+ }
420
+ return "";
421
+ }
422
+ var dummyLogger = {
423
+ error: () => {
424
+ },
425
+ warn: () => {
426
+ },
427
+ info: () => {
428
+ },
429
+ debug: () => {
430
+ },
431
+ http: () => {
432
+ },
433
+ verbose: () => {
434
+ },
435
+ silly: () => {
436
+ }
437
+ };
438
+ var enhancedLogger = {
439
+ error: (message, ...meta) => {
440
+ const caller = captureCallerInfo();
441
+ logger2.error(message, { ...meta, caller });
442
+ },
443
+ warn: (message, ...meta) => {
444
+ const caller = captureCallerInfo();
445
+ logger2.warn(message, { ...meta, caller });
446
+ },
447
+ info: (message, ...meta) => {
448
+ const caller = captureCallerInfo();
449
+ logger2.info(message, { ...meta, caller });
450
+ },
451
+ debug: (message, ...meta) => {
452
+ const caller = captureCallerInfo();
453
+ logger2.debug(message, { ...meta, caller });
454
+ },
455
+ http: (message, ...meta) => {
456
+ const caller = captureCallerInfo();
457
+ logger2.http(message, { ...meta, caller });
458
+ },
459
+ verbose: (message, ...meta) => {
460
+ const caller = captureCallerInfo();
461
+ logger2.verbose(message, { ...meta, caller });
462
+ },
463
+ silly: (message, ...meta) => {
464
+ const caller = captureCallerInfo();
465
+ logger2.silly(message, { ...meta, caller });
466
+ }
467
+ };
468
+ var streamLogger = {
469
+ /**
470
+ * Write content directly to stdout without formatting
471
+ * Used for streaming output where content comes in chunks
472
+ */
473
+ info: (message) => {
474
+ if (!getDisableLog()) {
475
+ process.stdout.write(message);
476
+ if (process.env.LOG_OUTPUT) {
477
+ fs.appendFileSync(process.env.LOG_OUTPUT, message);
478
+ }
479
+ }
480
+ },
481
+ /**
482
+ * Write error content to stderr
483
+ */
484
+ error: (message) => {
485
+ if (!getDisableLog()) {
486
+ process.stderr.write(message);
487
+ if (process.env.LOG_OUTPUT) {
488
+ fs.appendFileSync(process.env.LOG_OUTPUT, message);
489
+ }
490
+ }
491
+ },
492
+ /**
493
+ * Write content with newline
494
+ */
495
+ log: (message) => {
496
+ if (!getDisableLog()) {
497
+ process.stdout.write(message + "\n");
498
+ if (process.env.LOG_OUTPUT) {
499
+ fs.appendFileSync(process.env.LOG_OUTPUT, message + "\n");
500
+ }
501
+ }
502
+ },
503
+ debug: (message) => {
504
+ if (!getDisableLog()) {
505
+ process.stdout.write(message);
506
+ if (process.env.LOG_OUTPUT) {
507
+ fs.appendFileSync(process.env.LOG_OUTPUT, message);
508
+ }
509
+ }
510
+ }
511
+ };
512
+ var logger_default = { enhancedLogger, dummyLogger, streamLogger, getDisableLog };
513
+
514
+ // src/utils/index.ts
515
+ var logger = logger_default.getDisableLog() ? logger_default.dummyLogger : logger_default.enhancedLogger;
516
+ var streamLogger2 = logger_default.getDisableLog() ? logger_default.dummyLogger : logger_default.streamLogger;
517
+ if (process.env.LOG_LEVEL) {
518
+ logger.info(`LOG_LEVEL: ${process.env.LOG_LEVEL}`);
519
+ } else {
520
+ logger.info("LOG_LEVEL is not set");
521
+ }
522
+ if (process.env.LOG_OUTPUT) {
523
+ logger.info(`LOG_OUTPUT: ${process.env.LOG_OUTPUT}`);
524
+ }
525
+ if (process.env.ENABLE_LOG === "true") {
526
+ logger.info("ENABLE_LOG is set to true");
527
+ } else {
528
+ logger.info("ENABLE_LOG is not set");
529
+ }
530
+
531
+ // src/utils/connections.ts
532
+ var AsyncExitStack = class {
533
+ stack = [];
534
+ /**
535
+ * Enter a context manager and add it to the stack
536
+ */
537
+ async enterContext(context) {
538
+ const result = await context.enter();
539
+ this.stack.push(context);
540
+ return result;
541
+ }
542
+ /**
543
+ * Close all context managers in reverse order
544
+ */
545
+ async close() {
546
+ while (this.stack.length > 0) {
547
+ const context = this.stack.pop();
548
+ if (context) {
549
+ try {
550
+ await context.exit(null, null, null);
551
+ } catch (error) {
552
+ logger.error("Error closing context:", error);
553
+ }
554
+ }
555
+ }
556
+ }
557
+ /**
558
+ * Alias for close to match Python's close method if needed,
559
+ * though Python uses __aexit__ usually.
560
+ */
561
+ async aclose() {
562
+ await this.close();
563
+ }
564
+ /**
565
+ * Push a callback to be called when closing
566
+ */
567
+ push(callback) {
568
+ const contextManager = {
569
+ enter: async () => {
570
+ },
571
+ exit: async (exc_type, exc_val, exc_tb) => {
572
+ await callback();
573
+ }
574
+ };
575
+ this.stack.push(contextManager);
576
+ }
577
+ };
578
+ var MCPConnection = class {
579
+ session = null;
580
+ transport = null;
581
+ async enter() {
582
+ this.transport = await this.createTransport();
583
+ this.session = new Client(
584
+ {
585
+ name: "evoltagent-client",
586
+ version: "1.0.0"
587
+ },
588
+ {
589
+ capabilities: {
590
+ // Client capabilities
591
+ }
592
+ }
593
+ );
594
+ await this.session.connect(this.transport);
595
+ return this;
596
+ }
597
+ async exit(exc_type, exc_val, exc_tb) {
598
+ try {
599
+ if (this.session) {
600
+ await this.session.close();
601
+ }
602
+ } catch (e) {
603
+ logger.error(`Error during cleanup: ${e}`);
604
+ } finally {
605
+ this.session = null;
606
+ this.transport = null;
607
+ }
608
+ }
609
+ async listTools() {
610
+ if (!this.session) throw new Error("Session not initialized");
611
+ const result = await this.session.listTools();
612
+ return result.tools;
613
+ }
614
+ async callTool(toolName, argumentsDict) {
615
+ if (!this.session) throw new Error("Session not initialized");
616
+ return await this.session.callTool({
617
+ name: toolName,
618
+ arguments: argumentsDict
619
+ });
620
+ }
621
+ };
622
+ var MCPConnectionStdio = class extends MCPConnection {
623
+ command;
624
+ args;
625
+ env;
626
+ constructor(command, args = [], env) {
627
+ super();
628
+ this.command = command;
629
+ this.args = args;
630
+ this.env = env;
631
+ }
632
+ async createTransport() {
633
+ return new StdioClientTransport({
634
+ command: this.command,
635
+ args: this.args,
636
+ env: this.env
637
+ });
638
+ }
639
+ };
640
+ var MCPConnectionSSE = class extends MCPConnection {
641
+ url;
642
+ headers;
643
+ constructor(url, headers) {
644
+ super();
645
+ this.url = url;
646
+ this.headers = headers;
647
+ }
648
+ async createTransport() {
649
+ return new SSEClientTransport(new URL(this.url), {
650
+ eventSourceInit: {
651
+ // headers: this.headers, // TypeScript doesn't like headers in EventSourceInit
652
+ }
653
+ });
654
+ }
655
+ };
656
+ function createMcpConnection(config2) {
657
+ const connType = (config2.type || "stdio").toLowerCase();
658
+ if (connType === "stdio") {
659
+ if (!config2.command) {
660
+ throw new Error("Command is required for STDIO connections");
661
+ }
662
+ return new MCPConnectionStdio(config2.command, config2.args || [], config2.env);
663
+ } else if (connType === "sse") {
664
+ if (!config2.url) {
665
+ throw new Error("URL is required for SSE connections");
666
+ }
667
+ return new MCPConnectionSSE(config2.url, config2.headers);
668
+ } else {
669
+ throw new Error(`Unsupported connection type: ${connType}`);
670
+ }
671
+ }
672
+
673
+ // src/configs/configLoader.ts
674
+ import * as fs2 from "fs";
675
+ import * as path from "path";
676
+ import * as yaml from "yaml";
677
+ function getConfigPath() {
678
+ return path.join(process.env.HOME || "~", ".evolt", "config.yaml");
679
+ }
680
+ function loadModelConfig(modelName) {
681
+ const configPath = process.env.EVOLT_CONFIG_PATH || getConfigPath();
682
+ let configData = {};
683
+ try {
684
+ if (fs2.existsSync(configPath)) {
685
+ const fileContent = fs2.readFileSync(configPath, "utf8");
686
+ configData = yaml.parse(fileContent);
687
+ } else {
688
+ logger.warn(`Config file not found at ${configPath}, using defaults`);
689
+ configData = getDefaultConfig();
690
+ }
691
+ } catch (error) {
692
+ logger.warn(`Failed to load config from ${configPath}, using defaults:`, error);
693
+ configData = getDefaultConfig();
694
+ }
695
+ const models = configData.models || {};
696
+ const defaultModel = modelName || configData.defaultModel || "deepseek";
697
+ const modelConfig = models[defaultModel] || models.deepseek || getDefaultModelConfig();
698
+ const params = modelConfig.params || {};
699
+ return {
700
+ provider: modelConfig.provider || "openai",
701
+ model: modelConfig.model || "gpt-3.5-turbo",
702
+ contextWindowTokens: modelConfig.contextWindowTokens || 4096,
703
+ maxOutputTokens: params.maxCompletionTokens || params.maxTokens || modelConfig.maxOutputTokens || 1024,
704
+ temperature: params.temperature || modelConfig.temperature || 0.7,
705
+ topP: modelConfig.topP || 0.9,
706
+ apiKey: modelConfig.apiKey,
707
+ baseUrl: modelConfig.baseUrl,
708
+ ...modelConfig
709
+ };
710
+ }
711
+ function getDefaultConfig() {
712
+ return {
713
+ defaultModel: "deepseek",
714
+ models: {
715
+ deepseek: getDefaultModelConfig(),
716
+ openai: {
717
+ provider: "openai",
718
+ model: "gpt-3.5-turbo",
719
+ contextWindowTokens: 4096,
720
+ maxOutputTokens: 1024,
721
+ temperature: 0.7,
722
+ topP: 0.9
723
+ },
724
+ anthropic: {
725
+ provider: "anthropic",
726
+ model: "claude-3-sonnet-20240229",
727
+ contextWindowTokens: 2e5,
728
+ maxOutputTokens: 4096,
729
+ temperature: 0.7,
730
+ topP: 0.9
731
+ }
732
+ }
733
+ };
734
+ }
735
+ function getDefaultModelConfig() {
736
+ return {
737
+ provider: "deepseek",
738
+ model: "deepseek-chat",
739
+ contextWindowTokens: 32768,
740
+ maxOutputTokens: 4096,
741
+ temperature: 0.7,
742
+ topP: 0.9,
743
+ apiKey: process.env.DEEPSEEK_API_KEY,
744
+ baseUrl: process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com/v1"
745
+ };
746
+ }
747
+ function convertTypeNameToOpenai(typeName) {
748
+ const typeMap = {
749
+ str: "string",
750
+ string: "string",
751
+ int: "integer",
752
+ integer: "integer",
753
+ float: "number",
754
+ number: "number",
755
+ bool: "boolean",
756
+ boolean: "boolean",
757
+ list: "array",
758
+ array: "array",
759
+ dict: "object",
760
+ object: "object"
761
+ };
762
+ return typeMap[typeName.toLowerCase()] || "string";
763
+ }
764
+
765
+ // src/configs/constants.ts
766
+ var DEFAULT_CONFIG = {
767
+ MODEL: "deepseek",
768
+ PROVIDER: "deepseek",
769
+ CONTEXT_WINDOW: 32768,
770
+ MAX_OUTPUT_TOKENS: 4096,
771
+ TEMPERATURE: 0.7,
772
+ TOP_P: 0.9
773
+ };
774
+ var TOOL_CONSTANTS = {
775
+ SYSTEM_TOOL_PREFIX: "SystemTool.",
776
+ USER_TOOL_PREFIX: "UserTool.",
777
+ AGENT_TOOL_PREFIX: "Agent.",
778
+ MCP_TOOL_PREFIX: "MCP."
779
+ };
780
+ var MESSAGE_ROLES = {
781
+ SYSTEM: "system",
782
+ USER: "user",
783
+ ASSISTANT: "assistant"
784
+ };
785
+ var TOOL_CALL_TYPES = {
786
+ SYSTEM: "system",
787
+ USER: "user"
788
+ };
789
+ var ENV_VARS = {
790
+ EVOLT_CONFIG_PATH: "EVOLT_CONFIG_PATH",
791
+ DEEPSEEK_API_KEY: "DEEPSEEK_API_KEY",
792
+ DEEPSEEK_BASE_URL: "DEEPSEEK_BASE_URL",
793
+ OPENAI_API_KEY: "OPENAI_API_KEY",
794
+ ANTHROPIC_API_KEY: "ANTHROPIC_API_KEY"
795
+ };
796
+ var ERROR_MESSAGES = {
797
+ CONFIG_LOAD_FAILED: "Failed to load configuration",
798
+ MODEL_NOT_FOUND: "Model configuration not found",
799
+ TOOL_NOT_REGISTERED: "Tool not registered in tool store",
800
+ INVALID_MESSAGE_FORMAT: "Invalid message format",
801
+ TOOL_EXECUTION_FAILED: "Tool execution failed"
802
+ };
803
+ var LOG_LEVELS = {
804
+ DEBUG: 0,
805
+ INFO: 1,
806
+ WARNING: 2,
807
+ ERROR: 3
808
+ };
809
+
810
+ // src/configs/paths.ts
811
+ import * as path2 from "path";
812
+ import * as fs3 from "fs";
813
+ function getWorkspaceDir() {
814
+ return process.env.EVOLT_WORKSPACE || path2.join(process.cwd(), "workspace");
815
+ }
816
+ function getConfigDir() {
817
+ return process.env.EVOLT_CONFIG_DIR || path2.join(process.cwd(), "config");
818
+ }
819
+ function getLogsDir() {
820
+ return process.env.EVOLT_LOGS_DIR || path2.join(getWorkspaceDir(), "logs");
821
+ }
822
+ function getCacheDir() {
823
+ return process.env.EVOLT_CACHE_DIR || path2.join(getWorkspaceDir(), "cache");
824
+ }
825
+ function getSkillsDir() {
826
+ return process.env.EVOLT_SKILLS_DIR || path2.join(getWorkspaceDir(), "skills");
827
+ }
828
+ function ensureDir(dirPath) {
829
+ if (!fs3.existsSync(dirPath)) {
830
+ fs3.mkdirSync(dirPath, { recursive: true });
831
+ }
832
+ }
833
+ function getWorkspacePath(relativePath) {
834
+ const workspaceDir = getWorkspaceDir();
835
+ ensureDir(workspaceDir);
836
+ return path2.join(workspaceDir, relativePath);
837
+ }
838
+ function getConfigPath2(relativePath) {
839
+ const configDir = getConfigDir();
840
+ ensureDir(configDir);
841
+ return path2.join(configDir, relativePath);
842
+ }
843
+ function isInWorkspace(filePath) {
844
+ const workspaceDir = getWorkspaceDir();
845
+ const absolutePath = path2.resolve(filePath);
846
+ return absolutePath.startsWith(path2.resolve(workspaceDir));
847
+ }
848
+ function normalizePath(filePath) {
849
+ return path2.normalize(filePath).replace(/\\/g, "/");
850
+ }
851
+ function getFileExtension(filePath) {
852
+ return path2.extname(filePath).toLowerCase();
853
+ }
854
+ function fileExists(filePath) {
855
+ try {
856
+ return fs3.existsSync(filePath);
857
+ } catch {
858
+ return false;
859
+ }
860
+ }
861
+ function getTempFilePath(prefix = "evolt") {
862
+ const tempDir = path2.join(getCacheDir(), "temp");
863
+ ensureDir(tempDir);
864
+ const timestamp = Date.now();
865
+ const random = Math.random().toString(36).substring(2, 8);
866
+ return path2.join(tempDir, `${prefix}_${timestamp}_${random}.tmp`);
867
+ }
868
+ var WORKSPACE_DIR = getWorkspaceDir();
869
+ var SKILLS_DIR = getSkillsDir();
870
+
871
+ // src/configs/settings.ts
872
+ var DEFAULT_SETTINGS = {
873
+ logLevel: LOG_LEVELS.INFO,
874
+ verbose: false,
875
+ debug: false,
876
+ workspace: process.env.EVOLT_WORKSPACE || "./workspace",
877
+ maxRetries: 3,
878
+ timeout: 3e4,
879
+ // 30 seconds
880
+ enableCache: true,
881
+ enableTelemetry: false
882
+ };
883
+ var SettingsManager = class {
884
+ settings = { ...DEFAULT_SETTINGS };
885
+ /**
886
+ * Update settings
887
+ */
888
+ update(newSettings) {
889
+ this.settings = { ...this.settings, ...newSettings };
890
+ }
891
+ /**
892
+ * Get current settings
893
+ */
894
+ get() {
895
+ return { ...this.settings };
896
+ }
897
+ /**
898
+ * Reset to default settings
899
+ */
900
+ reset() {
901
+ this.settings = { ...DEFAULT_SETTINGS };
902
+ }
903
+ /**
904
+ * Get specific setting value
905
+ */
906
+ getValue(key) {
907
+ return this.settings[key];
908
+ }
909
+ /**
910
+ * Set specific setting value
911
+ */
912
+ setValue(key, value) {
913
+ this.settings[key] = value;
914
+ }
915
+ };
916
+ var settings = new SettingsManager();
917
+ function initializeSettings() {
918
+ const envSettings = {};
919
+ const logLevelEnv = process.env.EVOLT_LOG_LEVEL;
920
+ if (logLevelEnv) {
921
+ const levelMap = {
922
+ debug: LOG_LEVELS.DEBUG,
923
+ info: LOG_LEVELS.INFO,
924
+ warning: LOG_LEVELS.WARNING,
925
+ error: LOG_LEVELS.ERROR
926
+ };
927
+ const normalizedLevel = logLevelEnv.toLowerCase();
928
+ envSettings.logLevel = levelMap[normalizedLevel] ?? LOG_LEVELS.INFO;
929
+ }
930
+ if (process.env.EVOLT_VERBOSE === "true" || process.env.EVOLT_VERBOSE === "1") {
931
+ envSettings.verbose = true;
932
+ }
933
+ if (process.env.EVOLT_DEBUG === "true" || process.env.EVOLT_DEBUG === "1") {
934
+ envSettings.debug = true;
935
+ envSettings.logLevel = LOG_LEVELS.DEBUG;
936
+ }
937
+ if (process.env.EVOLT_WORKSPACE) {
938
+ envSettings.workspace = process.env.EVOLT_WORKSPACE;
939
+ }
940
+ if (process.env.EVOLT_MAX_RETRIES) {
941
+ const maxRetries = parseInt(process.env.EVOLT_MAX_RETRIES, 10);
942
+ if (!isNaN(maxRetries)) {
943
+ envSettings.maxRetries = maxRetries;
944
+ }
945
+ }
946
+ if (process.env.EVOLT_TIMEOUT) {
947
+ const timeout = parseInt(process.env.EVOLT_TIMEOUT, 10);
948
+ if (!isNaN(timeout)) {
949
+ envSettings.timeout = timeout;
950
+ }
951
+ }
952
+ if (process.env.EVOLT_ENABLE_CACHE === "false" || process.env.EVOLT_ENABLE_CACHE === "0") {
953
+ envSettings.enableCache = false;
954
+ }
955
+ if (process.env.EVOLT_ENABLE_TELEMETRY === "true" || process.env.EVOLT_ENABLE_TELEMETRY === "1") {
956
+ envSettings.enableTelemetry = true;
957
+ }
958
+ settings.update(envSettings);
959
+ }
960
+ function getSettings() {
961
+ return settings.get();
962
+ }
963
+ function updateSettings(newSettings) {
964
+ settings.update(newSettings);
965
+ }
966
+ initializeSettings();
967
+
968
+ // src/configs/mcpConfig.ts
969
+ var MCP_SERVERS_CONFIG = {
970
+ playwright: {
971
+ type: "stdio",
972
+ command: "npx",
973
+ args: ["-y", "@playwright/mcp@latest"]
974
+ },
975
+ filesystem: {
976
+ type: "stdio",
977
+ command: "npx",
978
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "."]
979
+ }
980
+ };
981
+
982
+ // src/tools/toolStore.ts
983
+ async function mcpTool(connection, toolName, args) {
984
+ try {
985
+ const argumentsDict = typeof args === "object" ? args : {};
986
+ const result = await connection.callTool(toolName, argumentsDict);
987
+ if (result && result.content) {
988
+ for (const item of result.content) {
989
+ if (item.type === "text") {
990
+ return item.text;
991
+ }
992
+ }
993
+ }
994
+ return "No text content in tool response";
995
+ } catch (e) {
996
+ return `Error executing ${toolName}: ${e}`;
997
+ }
998
+ }
999
+ var ToolStore = class {
1000
+ tools = {};
1001
+ /**
1002
+ * Add a tool to the store
1003
+ */
1004
+ addTool(name, desc, execute, argNames, serverName, inputSchema) {
1005
+ if (name in this.tools) {
1006
+ logger.warn(`Tool ${name} already exists in store.`);
1007
+ return;
1008
+ }
1009
+ this.tools[name] = {
1010
+ desc,
1011
+ execute,
1012
+ argNames,
1013
+ serverName,
1014
+ inputSchema
1015
+ };
1016
+ }
1017
+ /**
1018
+ * Add MCP tools to the store
1019
+ */
1020
+ async addMcpTools(agentName, serverName, stack) {
1021
+ const config2 = MCP_SERVERS_CONFIG[serverName];
1022
+ if (!config2) {
1023
+ logger.warn(`No MCP server config found for ${serverName}, agent: ${agentName}.`);
1024
+ return;
1025
+ }
1026
+ let numMcpTools = 0;
1027
+ try {
1028
+ const connection = createMcpConnection(config2);
1029
+ if (stack && typeof stack.enterContext === "function") {
1030
+ await stack.enterContext(connection);
1031
+ } else {
1032
+ logger.warn("No AsyncExitStack provided for MCP connection, connection might leak.");
1033
+ await connection.enter();
1034
+ }
1035
+ const toolDefinitions = await connection.listTools();
1036
+ for (const toolInfo of toolDefinitions) {
1037
+ if (toolInfo && toolInfo.name && toolInfo.inputSchema) {
1038
+ const toolDesc = toolInfo.description || `tool: ${toolInfo.name}`;
1039
+ const executeFn = async (args) => {
1040
+ return await mcpTool(connection, toolInfo.name, args);
1041
+ };
1042
+ const existingTool = this.getTool(toolInfo.name);
1043
+ if (existingTool && existingTool.agentName !== agentName) {
1044
+ logger.warn(`Tool ${toolInfo.name} already exists in store for different agent.`);
1045
+ continue;
1046
+ }
1047
+ this.addTool(
1048
+ toolInfo.name,
1049
+ toolDesc,
1050
+ executeFn,
1051
+ [],
1052
+ // Empty argNames implies expecting a single object argument (the dict)
1053
+ serverName,
1054
+ toolInfo.inputSchema
1055
+ );
1056
+ const tool = this.getTool(toolInfo.name);
1057
+ if (tool) {
1058
+ tool.agentName = agentName;
1059
+ }
1060
+ numMcpTools++;
1061
+ }
1062
+ }
1063
+ logger.info(`Loaded ${numMcpTools} MCP tools from ${serverName}, config: ${JSON.stringify(config2)}.`);
1064
+ } catch (e) {
1065
+ logger.error(`Error setting up MCP server ${serverName}, config: ${JSON.stringify(config2)}: ${e}`);
1066
+ }
1067
+ }
1068
+ /**
1069
+ * Get MCP tools schemas for a specific agent and server
1070
+ */
1071
+ getMcpToolsSchemas(agentName, serverName, provider) {
1072
+ const toolcallSchemas = [];
1073
+ for (const name of this.listTools()) {
1074
+ const tool = this.getTool(name);
1075
+ if (!tool) continue;
1076
+ if (serverName && tool.serverName !== serverName) {
1077
+ continue;
1078
+ }
1079
+ if (tool.agentName && tool.agentName !== agentName) {
1080
+ continue;
1081
+ }
1082
+ if (tool.inputSchema) {
1083
+ toolcallSchemas.push(this.toToolSchema(name, tool, provider));
1084
+ }
1085
+ }
1086
+ return toolcallSchemas;
1087
+ }
1088
+ /**
1089
+ * Convert tool to schema format for specific provider
1090
+ */
1091
+ toToolSchema(name, tool, provider = "openai") {
1092
+ if (provider === "openai") {
1093
+ return {
1094
+ type: "function",
1095
+ function: {
1096
+ name,
1097
+ description: tool.desc,
1098
+ parameters: tool.inputSchema
1099
+ }
1100
+ };
1101
+ } else if (provider === "anthropic") {
1102
+ return {
1103
+ name,
1104
+ description: tool.desc,
1105
+ input_schema: tool.inputSchema
1106
+ };
1107
+ }
1108
+ return {};
1109
+ }
1110
+ /**
1111
+ * Get tool schema by name (Python: get_toolcall_schema)
1112
+ */
1113
+ getToolcallSchema(toolName, provider = "openai") {
1114
+ const tool = this.getTool(toolName);
1115
+ if (!tool) {
1116
+ return {};
1117
+ }
1118
+ return this.toToolSchema(toolName, tool, provider);
1119
+ }
1120
+ /**
1121
+ * Get tool by name
1122
+ */
1123
+ getTool(name) {
1124
+ return this.tools[name];
1125
+ }
1126
+ /**
1127
+ * Check if tool exists
1128
+ */
1129
+ hasTool(name) {
1130
+ return name in this.tools;
1131
+ }
1132
+ /**
1133
+ * Get all tool names (Python: list_tools)
1134
+ */
1135
+ listTools() {
1136
+ return Object.keys(this.tools);
1137
+ }
1138
+ /**
1139
+ * Convert all tools to schema format
1140
+ */
1141
+ toDict(provider = "openai") {
1142
+ const toolSchemas = [];
1143
+ for (const [name, tool] of Object.entries(this.tools)) {
1144
+ if (tool.inputSchema) {
1145
+ toolSchemas.push(this.toToolSchema(name, tool, provider));
1146
+ }
1147
+ }
1148
+ return toolSchemas;
1149
+ }
1150
+ /**
1151
+ * Get number of tools in store
1152
+ */
1153
+ get length() {
1154
+ return Object.keys(this.tools).length;
1155
+ }
1156
+ /**
1157
+ * Check if tool exists (Python __contains__ equivalent)
1158
+ */
1159
+ contains(name) {
1160
+ return this.hasTool(name);
1161
+ }
1162
+ /**
1163
+ * Get tool by index operator (Python __getitem__ equivalent)
1164
+ */
1165
+ getItem(name) {
1166
+ const tool = this.getTool(name);
1167
+ if (!tool) {
1168
+ throw new Error(`Tool ${name} not found in store.`);
1169
+ }
1170
+ return tool;
1171
+ }
1172
+ /**
1173
+ * Get all tool entries
1174
+ */
1175
+ items() {
1176
+ return Object.entries(this.tools);
1177
+ }
1178
+ /**
1179
+ * Get all tool names (alias for listTools)
1180
+ */
1181
+ keys() {
1182
+ return this.listTools();
1183
+ }
1184
+ };
1185
+ var SystemToolStore = new ToolStore();
1186
+ var FunctionCallingStore = new ToolStore();
1187
+ var UserToolStore = FunctionCallingStore;
1188
+
1189
+ // src/tools/toolRegister.ts
1190
+ function buildToolDescription(fullToolName, config2) {
1191
+ let toolDesc = `
1192
+ <${fullToolName}>
1193
+ <${fullToolName}.description> ${config2.description}
1194
+ `;
1195
+ if (config2.params) {
1196
+ for (const param of config2.params) {
1197
+ toolDesc += `<argument name="${param.name}" type="${param.type}"> ${param.description} </argument>
1198
+ `;
1199
+ }
1200
+ }
1201
+ if (config2.returns) {
1202
+ toolDesc += `<returns type="${config2.returns.type}"> ${config2.returns.description} </returns>
1203
+ `;
1204
+ }
1205
+ toolDesc += `</${fullToolName}.description>
1206
+ `;
1207
+ if (config2.examples && config2.examples.length > 0) {
1208
+ for (const example of config2.examples) {
1209
+ toolDesc += `<${fullToolName}.example>
1210
+ ${example}
1211
+ </${fullToolName}.example>
1212
+ `;
1213
+ }
1214
+ }
1215
+ toolDesc += `</${fullToolName}>`;
1216
+ return toolDesc;
1217
+ }
1218
+ function buildInputSchema(config2) {
1219
+ const inputSchema = {
1220
+ type: "object",
1221
+ properties: {},
1222
+ required: []
1223
+ };
1224
+ if (config2.params) {
1225
+ for (const param of config2.params) {
1226
+ inputSchema.properties[param.name] = {
1227
+ type: convertTypeNameToOpenai(param.type),
1228
+ description: param.description
1229
+ };
1230
+ if (!param.optional) {
1231
+ inputSchema.required.push(param.name);
1232
+ }
1233
+ }
1234
+ }
1235
+ return inputSchema;
1236
+ }
1237
+ function tools(config2) {
1238
+ return function(target) {
1239
+ const instance = new target();
1240
+ for (const [methodName, methodConfig] of Object.entries(config2)) {
1241
+ const method = instance[methodName];
1242
+ if (!method || typeof method !== "function") {
1243
+ throw new Error(`Tool ${target.name}.${methodName} not found`);
1244
+ }
1245
+ const execute = method.bind(instance);
1246
+ const argNames = methodConfig.params?.map((p) => p.name) || [];
1247
+ const systemToolName = `${target.name}.${methodName}`;
1248
+ const systemToolDesc = buildToolDescription(systemToolName, methodConfig);
1249
+ SystemToolStore.addTool(systemToolName, systemToolDesc, execute, argNames, target.name);
1250
+ const userToolName = `${target.name}-${methodName}`;
1251
+ const userToolDesc = `
1252
+ Tool \`${userToolName}\` function is: ${methodConfig.description}
1253
+ `;
1254
+ const inputSchema = buildInputSchema(methodConfig);
1255
+ FunctionCallingStore.addTool(userToolName, userToolDesc, execute, argNames, target.name, inputSchema);
1256
+ logger.debug(`Registered unified tool: ${systemToolName} / ${userToolName}`);
1257
+ }
1258
+ return target;
1259
+ };
1260
+ }
1261
+ function registerAgentAsTool(agents, verbose = false) {
1262
+ if (!agents) {
1263
+ return [];
1264
+ }
1265
+ const agentList = Array.isArray(agents) ? agents : [agents];
1266
+ const registeredAgentNames = [];
1267
+ for (const agent of agentList) {
1268
+ if (!agent || typeof agent !== "object") {
1269
+ logger.warn(`Invalid agent: ${agent}, skipping`);
1270
+ continue;
1271
+ }
1272
+ const agentName = `Agent.${agent.name}`;
1273
+ if (SystemToolStore.hasTool(agentName)) {
1274
+ logger.debug(`Agent ${agent.name} already registered as ${agentName}, change agent name`);
1275
+ registeredAgentNames.push(agentName);
1276
+ continue;
1277
+ }
1278
+ const toolDesc = `Delegate tasks to sub-agent ${agent.name}.
1279
+
1280
+ Profile: ${agent.profile}
1281
+
1282
+ Args:
1283
+ instruction (str): Detailed task description or instruction for the agent.
1284
+ Be specific about what you want the agent to accomplish.
1285
+
1286
+ Returns:
1287
+ str: The agent's execution result, including analysis, outputs, or conclusions.
1288
+
1289
+ Examples:
1290
+ <${agentName}>
1291
+ <instruction>
1292
+ Please analyze this data and provide insights on trends and patterns.
1293
+ </instruction>
1294
+ </${agentName}>
1295
+ `;
1296
+ const agentExecute = async (instruction) => {
1297
+ try {
1298
+ const response = await agent.run(instruction);
1299
+ if (typeof response === "string") {
1300
+ return response;
1301
+ }
1302
+ if (Array.isArray(response)) {
1303
+ return response.map((r) => String(r)).join("\n");
1304
+ }
1305
+ return JSON.stringify(response);
1306
+ } catch (error) {
1307
+ logger.error(`Error executing agent ${agent.name}:`, error);
1308
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
1309
+ }
1310
+ };
1311
+ SystemToolStore.addTool(agentName, toolDesc, agentExecute, ["instruction"], agent.name);
1312
+ registeredAgentNames.push(agentName);
1313
+ if (verbose) {
1314
+ logger.info(`Registered agent as tool: ${agentName}`);
1315
+ }
1316
+ }
1317
+ if (registeredAgentNames.length > 0) {
1318
+ logger.debug(`Successfully registered ${registeredAgentNames.length} Agent tool(s): ${registeredAgentNames.join(", ")}`);
1319
+ }
1320
+ return registeredAgentNames;
1321
+ }
1322
+
1323
+ // src/tools/think.ts
1324
+ var ThinkTool = class {
1325
+ async execute(thought) {
1326
+ return "Thinking complete!";
1327
+ }
1328
+ };
1329
+ ThinkTool = __decorateClass([
1330
+ tools({
1331
+ execute: {
1332
+ description: "Use the tool to think about something when complex reasoning.",
1333
+ params: [
1334
+ {
1335
+ name: "thought",
1336
+ type: "str",
1337
+ description: "The thought to think about."
1338
+ }
1339
+ ],
1340
+ returns: {
1341
+ type: "str",
1342
+ description: "The complete thought result."
1343
+ },
1344
+ examples: [
1345
+ "Good example:\n<ThinkTool.execute><thought> your thought here </thought></ThinkTool.execute>",
1346
+ 'Bad example:\n<ThinkTool.execute>{"thought":"your thought here"}</ThinkTool.execute>'
1347
+ ]
1348
+ }
1349
+ })
1350
+ ], ThinkTool);
1351
+
1352
+ // src/tools/cmdTool.ts
1353
+ import { spawn } from "child_process";
1354
+
1355
+ // src/types.ts
1356
+ var EvoltError = class extends Error {
1357
+ constructor(message) {
1358
+ super(message);
1359
+ this.name = "EvoltError";
1360
+ }
1361
+ };
1362
+ var ToolExecutionError = class extends EvoltError {
1363
+ constructor(message) {
1364
+ super(message);
1365
+ this.name = "ToolExecutionError";
1366
+ }
1367
+ };
1368
+ var ModelError = class extends EvoltError {
1369
+ constructor(message) {
1370
+ super(message);
1371
+ this.name = "ModelError";
1372
+ }
1373
+ };
1374
+
1375
+ // src/tools/context.ts
1376
+ import { AsyncLocalStorage } from "async_hooks";
1377
+ var toolcallManagerContext = new AsyncLocalStorage();
1378
+ function getCurrentManager() {
1379
+ return toolcallManagerContext.getStore() || null;
1380
+ }
1381
+ function runWithManager(manager, fn) {
1382
+ return toolcallManagerContext.run(manager, fn);
1383
+ }
1384
+
1385
+ // src/tools/cmdTool.ts
1386
+ var CommandLineTool = class {
1387
+ async execute(command, cwd, env) {
1388
+ try {
1389
+ const workDir = cwd || process.cwd();
1390
+ try {
1391
+ const fs9 = await import("fs");
1392
+ if (!fs9.existsSync(workDir)) {
1393
+ return `Working directory does not exist: ${workDir}`;
1394
+ }
1395
+ } catch (error) {
1396
+ return `Cannot access working directory: ${workDir}`;
1397
+ }
1398
+ const execEnv = { ...process.env, ...env };
1399
+ const childProcess = spawn(command, {
1400
+ shell: true,
1401
+ cwd: workDir,
1402
+ env: execEnv,
1403
+ stdio: ["pipe", "pipe", "pipe"]
1404
+ });
1405
+ const manager = getCurrentManager();
1406
+ if (!manager) {
1407
+ throw new ToolExecutionError("Cannot get ToolcallManager, please execute this tool through ToolcallManager");
1408
+ }
1409
+ const processId = manager.registerBackgroundProcess(childProcess, command, workDir);
1410
+ logger.debug(`Register background process: Command: ${command}
1411
+ Process ID: ${processId}`);
1412
+ return new Promise((resolve2) => {
1413
+ const timeout = setTimeout(async () => {
1414
+ resolve2(
1415
+ `COMMAND: ${command}
1416
+ PROCESS ID: ${processId}
1417
+ STATUS: The process may still be executing (waited 5 seconds, not completed)
1418
+ TIP: Please use the list command later to check the process status, or wait for the process to complete and then check the result`
1419
+ );
1420
+ }, 5e3);
1421
+ let stdout = "";
1422
+ let stderr = "";
1423
+ childProcess.stdout?.on("data", (data) => {
1424
+ stdout += data.toString();
1425
+ });
1426
+ childProcess.stderr?.on("data", (data) => {
1427
+ stderr += data.toString();
1428
+ });
1429
+ childProcess.on("close", (code) => {
1430
+ clearTimeout(timeout);
1431
+ const stdoutText = stdout.trim();
1432
+ const stderrText = stderr.trim();
1433
+ const resultParts = [`COMMAND: ${command}`];
1434
+ if (stdoutText) {
1435
+ resultParts.push(`STDOUT:
1436
+ ${stdoutText}`);
1437
+ }
1438
+ if (stderrText) {
1439
+ resultParts.push(`STDERR:
1440
+ ${stderrText}`);
1441
+ }
1442
+ resultParts.push(`EXIT CODE: ${code}`);
1443
+ resolve2(resultParts.join("\n\n"));
1444
+ });
1445
+ childProcess.on("error", (error) => {
1446
+ clearTimeout(timeout);
1447
+ resolve2(`COMMAND: ${command}
1448
+ ERROR: ${error.message}`);
1449
+ });
1450
+ });
1451
+ } catch (error) {
1452
+ throw new ToolExecutionError(`Error executing background process '${command}': ${error.message}`);
1453
+ }
1454
+ }
1455
+ /**
1456
+ * List all background processes.
1457
+ *
1458
+ * Returns:
1459
+ * str: The natural language description of the background process list
1460
+ */
1461
+ async list() {
1462
+ const manager = getCurrentManager();
1463
+ if (!manager) {
1464
+ throw new ToolExecutionError("Cannot get ToolcallManager, please execute this tool through ToolcallManager");
1465
+ }
1466
+ const [status, result] = manager.listBackgroundProcesses();
1467
+ return result;
1468
+ }
1469
+ /**
1470
+ * Stop the specified background process.
1471
+ *
1472
+ * Args:
1473
+ * process_id (str): The process ID to stop
1474
+ * force (bool): Whether to force kill the process (using SIGKILL)
1475
+ *
1476
+ * Returns:
1477
+ * str: Natural language description of the operation result
1478
+ */
1479
+ async stop(processId, force = false) {
1480
+ const manager = getCurrentManager();
1481
+ if (!manager) {
1482
+ throw new ToolExecutionError("Cannot get ToolcallManager, please execute this tool through ToolcallManager");
1483
+ }
1484
+ return await manager.stopBackgroundProcess(processId, force);
1485
+ }
1486
+ /**
1487
+ * Clean up all background processes.
1488
+ *
1489
+ * Returns:
1490
+ * str: The natural language description of the cleanup result
1491
+ */
1492
+ async cleanup() {
1493
+ const manager = getCurrentManager();
1494
+ if (!manager) {
1495
+ throw new ToolExecutionError("Cannot get ToolcallManager, please execute this tool through ToolcallManager");
1496
+ }
1497
+ return await manager.cleanupBackgroundProcesses();
1498
+ }
1499
+ };
1500
+ CommandLineTool = __decorateClass([
1501
+ tools({
1502
+ execute: {
1503
+ description: "Execute bash command in background (non-blocking, returns result).",
1504
+ params: [
1505
+ { name: "command", type: "str", description: "The bash command to execute" },
1506
+ {
1507
+ name: "cwd",
1508
+ type: "Optional[str]",
1509
+ description: "Working directory, uses current directory if None",
1510
+ optional: true
1511
+ },
1512
+ {
1513
+ name: "env",
1514
+ type: "Optional[Dict[str, str]]",
1515
+ description: "Environment variables dictionary, uses current environment if None",
1516
+ optional: true
1517
+ }
1518
+ ],
1519
+ returns: { type: "str", description: "Background process startup information, including process ID and PID" }
1520
+ },
1521
+ list: {
1522
+ description: "List all background processes.",
1523
+ returns: { type: "str", description: "Information about all background processes" }
1524
+ },
1525
+ stop: {
1526
+ description: "Stop the specified background process.",
1527
+ params: [
1528
+ { name: "processId", type: "str", description: "The process ID to stop" },
1529
+ {
1530
+ name: "force",
1531
+ type: "bool",
1532
+ description: "Whether to force kill the process (using SIGKILL)",
1533
+ optional: true
1534
+ }
1535
+ ],
1536
+ returns: { type: "str", description: "Result information of stopping the process" }
1537
+ },
1538
+ cleanup: {
1539
+ description: "Clean up all background processes.",
1540
+ returns: { type: "str", description: "Cleanup result information" }
1541
+ }
1542
+ })
1543
+ ], CommandLineTool);
1544
+
1545
+ // src/tools/fileTool.ts
1546
+ import * as fs4 from "fs/promises";
1547
+ import * as pathModule from "path";
1548
+ var FileEditor = class {
1549
+ async read(path5, lineRange = "all") {
1550
+ try {
1551
+ await fs4.access(path5);
1552
+ } catch {
1553
+ throw new ToolExecutionError(`File does not exist: ${path5}`);
1554
+ }
1555
+ try {
1556
+ let content;
1557
+ try {
1558
+ content = await fs4.readFile(path5, "utf-8");
1559
+ } catch (error) {
1560
+ if (error.code === "ENCODING_NOT_SUPPORTED" || error.message.includes("encoding")) {
1561
+ const buffer = await fs4.readFile(path5);
1562
+ content = buffer.toString("latin1");
1563
+ } else {
1564
+ throw error;
1565
+ }
1566
+ }
1567
+ const lines = content.split("\n");
1568
+ if (lineRange === "all") {
1569
+ return content;
1570
+ }
1571
+ if (lineRange.includes("-")) {
1572
+ try {
1573
+ const [startStr, endStr] = lineRange.split("-", 2);
1574
+ const start = parseInt(startStr) - 1;
1575
+ const end = parseInt(endStr);
1576
+ if (start < 0 || end <= start) {
1577
+ throw new ToolExecutionError(`Line range is invalid: ${lineRange}`);
1578
+ }
1579
+ const selectedLines = lines.slice(start, end);
1580
+ return `Lines ${start + 1} to ${end} of file ${path5}:
1581
+ ` + selectedLines.join("\n");
1582
+ } catch (error) {
1583
+ throw new ToolExecutionError(
1584
+ `Invalid line range format when reading file ${path5}: ${lineRange}, error: ${error.message}`
1585
+ );
1586
+ }
1587
+ } else {
1588
+ try {
1589
+ const lineNum = parseInt(lineRange) - 1;
1590
+ if (lineNum < 0) {
1591
+ throw new ToolExecutionError(`Line number is less than 0: ${lineRange}`);
1592
+ }
1593
+ if (lineNum >= lines.length) {
1594
+ throw new ToolExecutionError(`Line number ${lineNum + 1} exceeds file length ${lines.length}`);
1595
+ }
1596
+ return `Line ${lineNum + 1} of file ${path5}:
1597
+ ` + lines[lineNum];
1598
+ } catch (error) {
1599
+ throw new ToolExecutionError(
1600
+ `Invalid line number format when reading file ${path5}: ${lineRange}, error: ${error.message}`
1601
+ );
1602
+ }
1603
+ }
1604
+ } catch (error) {
1605
+ if (error instanceof ToolExecutionError) {
1606
+ throw error;
1607
+ }
1608
+ throw new ToolExecutionError(`Error reading file ${path5}: ${error.message}`);
1609
+ }
1610
+ }
1611
+ async write(path5, content) {
1612
+ try {
1613
+ const dirPath = pathModule.dirname(path5);
1614
+ if (dirPath) {
1615
+ await fs4.mkdir(dirPath, { recursive: true });
1616
+ }
1617
+ await fs4.writeFile(path5, content, "utf-8");
1618
+ const bytesWritten = Buffer.from(content, "utf-8").length;
1619
+ return `Successfully wrote content to file ${path5}, wrote ${bytesWritten} bytes`;
1620
+ } catch (error) {
1621
+ if (error.code === "EACCES") {
1622
+ throw new ToolExecutionError(`No write permission: ${path5}`);
1623
+ }
1624
+ throw new ToolExecutionError(`Error writing to file ${path5}: ${error.message}`);
1625
+ }
1626
+ }
1627
+ async find(path5, pattern) {
1628
+ try {
1629
+ await fs4.access(path5);
1630
+ } catch {
1631
+ throw new ToolExecutionError(`File does not exist: ${path5}`);
1632
+ }
1633
+ let compiledPattern;
1634
+ try {
1635
+ compiledPattern = new RegExp(pattern, "g");
1636
+ } catch (error) {
1637
+ throw new ToolExecutionError(`Invalid regex pattern: ${pattern}, error: ${error.message}`);
1638
+ }
1639
+ const matches = [];
1640
+ try {
1641
+ let content;
1642
+ try {
1643
+ content = await fs4.readFile(path5, "utf-8");
1644
+ } catch (error) {
1645
+ if (error.code === "ENCODING_NOT_SUPPORTED" || error.message.includes("encoding")) {
1646
+ const buffer = await fs4.readFile(path5);
1647
+ content = buffer.toString("latin1");
1648
+ } else {
1649
+ throw error;
1650
+ }
1651
+ }
1652
+ const lines = content.split("\n");
1653
+ for (let lineNumber = 0; lineNumber < lines.length; lineNumber++) {
1654
+ const line = lines[lineNumber];
1655
+ let match;
1656
+ compiledPattern.lastIndex = 0;
1657
+ while ((match = compiledPattern.exec(line)) !== null) {
1658
+ matches.push({
1659
+ lineNumber: lineNumber + 1,
1660
+ lineContent: line,
1661
+ match: match[0],
1662
+ startPos: match.index,
1663
+ endPos: match.index + match[0].length
1664
+ });
1665
+ }
1666
+ }
1667
+ } catch (error) {
1668
+ throw new ToolExecutionError(`Error reading file ${path5}: ${error.message}`);
1669
+ }
1670
+ if (matches.length === 0) {
1671
+ return `No content matching pattern '${pattern}' found in file ${path5}`;
1672
+ }
1673
+ const resultLines = [`Found ${matches.length} matches in file ${path5}:`];
1674
+ for (const match of matches) {
1675
+ resultLines.push(`Line ${match.lineNumber}: ${match.match} (position ${match.startPos}-${match.endPos})`);
1676
+ resultLines.push(` Full line content: ${match.lineContent}`);
1677
+ }
1678
+ return resultLines.join("\n");
1679
+ }
1680
+ async findAndReplace(path5, pattern, replacement) {
1681
+ try {
1682
+ await fs4.access(path5);
1683
+ } catch {
1684
+ throw new ToolExecutionError(`File does not exist: ${path5}`);
1685
+ }
1686
+ let compiledPattern;
1687
+ try {
1688
+ compiledPattern = new RegExp(pattern, "g");
1689
+ } catch (error) {
1690
+ throw new ToolExecutionError(`Invalid regex pattern ${pattern}, error: ${error.message}`);
1691
+ }
1692
+ let content;
1693
+ try {
1694
+ try {
1695
+ content = await fs4.readFile(path5, "utf-8");
1696
+ } catch (error) {
1697
+ if (error.code === "ENCODING_NOT_SUPPORTED" || error.message.includes("encoding")) {
1698
+ const buffer = await fs4.readFile(path5);
1699
+ content = buffer.toString("latin1");
1700
+ } else {
1701
+ throw error;
1702
+ }
1703
+ }
1704
+ } catch (error) {
1705
+ throw new ToolExecutionError(`Error reading file ${path5}: ${error.message}`);
1706
+ }
1707
+ const newContent = content.replace(compiledPattern, replacement);
1708
+ const replacementCount = (content.match(compiledPattern) || []).length;
1709
+ let modifiedLines = 0;
1710
+ if (replacementCount > 0) {
1711
+ const originalLines = content.split("\n");
1712
+ const newLines = newContent.split("\n");
1713
+ modifiedLines = originalLines.filter((line, index) => line !== newLines[index]).length;
1714
+ try {
1715
+ await fs4.writeFile(path5, newContent, "utf-8");
1716
+ } catch (error) {
1717
+ if (error.code === "EACCES") {
1718
+ throw new ToolExecutionError(`No write permission: ${path5}`);
1719
+ }
1720
+ throw new ToolExecutionError(`Error writing to file ${path5}: ${error.message}`);
1721
+ }
1722
+ }
1723
+ return `In file ${path5}, found and replaced pattern '${pattern}' with '${replacement}', successfully replaced ${replacementCount} occurrences, modified ${modifiedLines} lines`;
1724
+ }
1725
+ async insert(path5, content, line) {
1726
+ try {
1727
+ await fs4.access(path5);
1728
+ } catch {
1729
+ throw new ToolExecutionError(`File does not exist: ${path5}`);
1730
+ }
1731
+ let lines;
1732
+ try {
1733
+ let fileContent;
1734
+ try {
1735
+ fileContent = await fs4.readFile(path5, "utf-8");
1736
+ } catch (error) {
1737
+ if (error.code === "ENCODING_NOT_SUPPORTED" || error.message.includes("encoding")) {
1738
+ const buffer = await fs4.readFile(path5);
1739
+ fileContent = buffer.toString("latin1");
1740
+ } else {
1741
+ throw error;
1742
+ }
1743
+ }
1744
+ lines = fileContent.split("\n");
1745
+ } catch (error) {
1746
+ throw new ToolExecutionError(`Error reading file ${path5}: ${error.message}`);
1747
+ }
1748
+ let actionDesc;
1749
+ if (line === void 0) {
1750
+ lines.push(content);
1751
+ actionDesc = `Appended content to end of file ${path5}`;
1752
+ } else {
1753
+ if (!(0 < line && line <= lines.length + 1)) {
1754
+ throw new ToolExecutionError(`Line number ${line} exceeds file ${path5} bounds (1 to ${lines.length + 1})`);
1755
+ }
1756
+ lines.splice(line - 1, 0, content);
1757
+ actionDesc = `Inserted content at line ${line} of file ${path5}`;
1758
+ }
1759
+ try {
1760
+ await fs4.writeFile(path5, lines.join("\n"), "utf-8");
1761
+ return actionDesc;
1762
+ } catch (error) {
1763
+ if (error.code === "EACCES") {
1764
+ throw new ToolExecutionError(`No write permission: ${path5}`);
1765
+ }
1766
+ throw new ToolExecutionError(`Error writing to file ${path5}: ${error.message}`);
1767
+ }
1768
+ }
1769
+ };
1770
+ FileEditor = __decorateClass([
1771
+ tools({
1772
+ read: {
1773
+ description: "Read the content of only one file. **Read one file at a time**.",
1774
+ params: [
1775
+ { name: "path", type: "string", description: "The path of only one file, must include workspace directory" },
1776
+ {
1777
+ name: "lineRange",
1778
+ type: "string",
1779
+ description: "Line range, format 'start-end' or 'start'. If 'all', reads entire file.",
1780
+ optional: true
1781
+ }
1782
+ ],
1783
+ returns: { type: "string", description: "The content of the file" }
1784
+ },
1785
+ write: {
1786
+ description: "Write content to a file.",
1787
+ params: [
1788
+ { name: "path", type: "string", description: "File path, must include workspace directory" },
1789
+ { name: "content", type: "string", description: "Content to write" }
1790
+ ],
1791
+ returns: { type: "string", description: "Natural language description of operation result" }
1792
+ },
1793
+ find: {
1794
+ description: "Find content matching specified pattern in file. **Folder searching is not supported.**",
1795
+ params: [
1796
+ { name: "path", type: "string", description: "File path, must include workspace directory" },
1797
+ { name: "pattern", type: "string", description: "Regex pattern to search for" }
1798
+ ],
1799
+ returns: { type: "string", description: "Natural language description of search results" }
1800
+ },
1801
+ findAndReplace: {
1802
+ description: "Find and replace content matching specified pattern in file. **Folder searching is not supported.**",
1803
+ params: [
1804
+ { name: "path", type: "string", description: "File path, must include workspace directory" },
1805
+ {
1806
+ name: "pattern",
1807
+ type: "string",
1808
+ description: 'Regex pattern to search for. Escape special chars [ ] ( ) . * + ? $ ^ | \\ with backslash. Example: CSS class "pt-[30]" \u2192 use pattern "pt-\\[30\\]"'
1809
+ },
1810
+ { name: "replacement", type: "string", description: "Replacement text" }
1811
+ ],
1812
+ returns: { type: "string", description: "Natural language description of operation result" }
1813
+ },
1814
+ insert: {
1815
+ description: "Insert content at specified line in file. **Folder searching is not supported.**",
1816
+ params: [
1817
+ { name: "path", type: "string", description: "File path, must include workspace directory" },
1818
+ { name: "content", type: "string", description: "Content to insert" },
1819
+ { name: "line", type: "integer", description: "Line number to insert at. If None, appends to end of file.", optional: true }
1820
+ ],
1821
+ returns: { type: "string", description: "Natural language description of operation result" }
1822
+ }
1823
+ })
1824
+ ], FileEditor);
1825
+
1826
+ // src/tools/esmTool.ts
1827
+ var ExtendStateMachineTool = class {
1828
+ async writeEsm(esmContent, filepath) {
1829
+ try {
1830
+ const fileEditor = new FileEditor();
1831
+ await fileEditor.write(filepath, esmContent);
1832
+ return `Successfully wrote the ESM content to the yaml file ${filepath}`;
1833
+ } catch (error) {
1834
+ throw new ToolExecutionError(`Failed to write the ESM content to the yaml file ${filepath}: ${error.message}`);
1835
+ }
1836
+ }
1837
+ };
1838
+ ExtendStateMachineTool = __decorateClass([
1839
+ tools({
1840
+ writeEsm: {
1841
+ description: "Write the yaml format ExtendStateMachine(ESM) content to the yaml file",
1842
+ params: [
1843
+ {
1844
+ name: "esmContent",
1845
+ type: "str",
1846
+ description: "The yaml format ESM content to write. follow the format of the ESM content."
1847
+ },
1848
+ {
1849
+ name: "filepath",
1850
+ type: "str",
1851
+ description: "The path to write the yaml format ESM content to."
1852
+ }
1853
+ ],
1854
+ returns: {
1855
+ type: "str",
1856
+ description: "Successfully wrote the ESM content to the yaml file {filepath}"
1857
+ }
1858
+ }
1859
+ })
1860
+ ], ExtendStateMachineTool);
1861
+
1862
+ // src/tools/apiTool.ts
1863
+ var ApiTool = class {
1864
+ async write(apiFilePath, apiContent) {
1865
+ const fileEditor = new FileEditor();
1866
+ await fileEditor.write(apiFilePath, apiContent);
1867
+ return `Write api file ${apiFilePath} complete!`;
1868
+ }
1869
+ async generateGolangFilesFromApi(apiFilePath, dir) {
1870
+ const cmdTool = new CommandLineTool();
1871
+ await cmdTool.execute(`goctl api go -api ${apiFilePath} -dir ${dir}`);
1872
+ return `Generate golang files from ${apiFilePath} complete! The files are in ${dir}`;
1873
+ }
1874
+ };
1875
+ ApiTool = __decorateClass([
1876
+ tools({
1877
+ write: {
1878
+ description: "Use the tool to write api file based on goctl.",
1879
+ params: [
1880
+ {
1881
+ name: "apiFilePath",
1882
+ type: "str",
1883
+ description: "The api file path to write."
1884
+ },
1885
+ {
1886
+ name: "apiContent",
1887
+ type: "str",
1888
+ description: "The api content to write."
1889
+ }
1890
+ ],
1891
+ returns: { type: "str", description: "The complete api file result." },
1892
+ examples: [
1893
+ 'Good example:\n<ApiTool.write><apiFilePath>to/your/workspace/your_api_file_name.api</apiFilePath><apiContent>type ( Request { Name string `path:"name,options=[you,me]"` } Response { Message string `json:"message"` } ) service greet-api { @handler GreetHandler get /greet/from/:name (Request) returns (Response) }</apiContent></ApiTool.write>'
1894
+ ]
1895
+ },
1896
+ generateGolangFilesFromApi: {
1897
+ description: "Use the tool to generate golang files from api file.",
1898
+ params: [
1899
+ {
1900
+ name: "apiFilePath",
1901
+ type: "str",
1902
+ description: "The api file path to generate golang files."
1903
+ },
1904
+ {
1905
+ name: "dir",
1906
+ type: "str",
1907
+ description: "The directory to generate golang files."
1908
+ }
1909
+ ],
1910
+ returns: { type: "str", description: "The complete golang files result." }
1911
+ }
1912
+ })
1913
+ ], ApiTool);
1914
+
1915
+ // src/tools/reply2human.ts
1916
+ var Reply2HumanTool = class {
1917
+ async reply(reply) {
1918
+ return "Reply complete!";
1919
+ }
1920
+ };
1921
+ Reply2HumanTool = __decorateClass([
1922
+ tools({
1923
+ reply: {
1924
+ description: "Emit the reply text in a unified and formatted manner.",
1925
+ params: [{ name: "reply", type: "str", description: "Raw reply text to be sent to the user." }],
1926
+ returns: { type: "str", description: "The complete, formatted reply." }
1927
+ }
1928
+ })
1929
+ ], Reply2HumanTool);
1930
+
1931
+ // src/tools/todoList.ts
1932
+ var TodoListTool = class {
1933
+ async write(projectName, todoList, projectDir) {
1934
+ const content = `# ${projectName}
1935
+ ## Todo List
1936
+ ${todoList}`;
1937
+ const fileEditor = new FileEditor();
1938
+ await fileEditor.write(`${projectDir}/todo.md`, content);
1939
+ return `Write todo list file for project ${projectName} complete! The file is in ${projectDir}/todo.md`;
1940
+ }
1941
+ };
1942
+ TodoListTool = __decorateClass([
1943
+ tools({
1944
+ write: {
1945
+ description: "Use the tool to write todo list file for project.",
1946
+ params: [
1947
+ { name: "projectName", type: "str", description: "The project name to write todo list file." },
1948
+ { name: "todoList", type: "str", description: "The todo list to write." },
1949
+ { name: "projectDir", type: "str", description: "The project directory to write todo list file." }
1950
+ ],
1951
+ returns: { type: "str", description: "The complete todo list file result." },
1952
+ examples: [
1953
+ "Good example:\n<TodoListTool.write><projectName>your project name here</projectName><todoList>- [ ] Write todo list file for project\n- [ ] Write todo list file for project</todoList><projectDir>your project directory here</projectDir></TodoListTool.write>"
1954
+ ]
1955
+ }
1956
+ })
1957
+ ], TodoListTool);
1958
+
1959
+ // src/tools/designUI.ts
1960
+ var WriteUIDesignDocument = class {
1961
+ async write(uiDesignDocumentFileDir, elements, composites, pages, functions, styles) {
1962
+ const fileEditor = new FileEditor();
1963
+ await fileEditor.write(`${uiDesignDocumentFileDir}/AtomicElements.json`, JSON.stringify(elements, null, 2));
1964
+ await fileEditor.write(`${uiDesignDocumentFileDir}/Composites.json`, JSON.stringify(composites, null, 2));
1965
+ await fileEditor.write(`${uiDesignDocumentFileDir}/Pages.json`, JSON.stringify(pages, null, 2));
1966
+ await fileEditor.write(`${uiDesignDocumentFileDir}/Functions.json`, JSON.stringify(functions, null, 2));
1967
+ await fileEditor.write(`${uiDesignDocumentFileDir}/Styles.json`, JSON.stringify(styles, null, 2));
1968
+ return `Write UI Design Document files ${uiDesignDocumentFileDir} complete!`;
1969
+ }
1970
+ };
1971
+ WriteUIDesignDocument = __decorateClass([
1972
+ tools({
1973
+ write: {
1974
+ description: "Use the tool to write UI Design Document files.",
1975
+ params: [
1976
+ {
1977
+ name: "uiDesignDocumentFileDir",
1978
+ type: "str",
1979
+ description: "The UI Design Document file directory to write."
1980
+ },
1981
+ {
1982
+ name: "elements",
1983
+ type: "List[Dict]",
1984
+ description: "The elements to write."
1985
+ },
1986
+ {
1987
+ name: "composites",
1988
+ type: "List[Dict]",
1989
+ description: "The composites to write."
1990
+ },
1991
+ { name: "pages", type: "List[Dict]", description: "The pages to write." },
1992
+ {
1993
+ name: "functions",
1994
+ type: "List[Dict]",
1995
+ description: "The functions to write."
1996
+ },
1997
+ {
1998
+ name: "styles",
1999
+ type: "List[Dict]",
2000
+ description: "The styles to write."
2001
+ }
2002
+ ],
2003
+ returns: {
2004
+ type: "str",
2005
+ description: "The complete UI Design Document files result."
2006
+ }
2007
+ }
2008
+ })
2009
+ ], WriteUIDesignDocument);
2010
+
2011
+ // src/tools/reflect.ts
2012
+ var ReflectTool = class {
2013
+ async reflect(state) {
2014
+ return "Reflected complete!";
2015
+ }
2016
+ /**
2017
+ * Set the reflection for agent to see.
2018
+ */
2019
+ setReflection(reflection) {
2020
+ return `<ReflectTool.setReflection><reflection>${reflection}</reflection></ReflectTool.setReflection>`;
2021
+ }
2022
+ };
2023
+ ReflectTool = __decorateClass([
2024
+ tools({
2025
+ reflect: {
2026
+ description: "Use the tool to reflect on the state.",
2027
+ params: [{ name: "state", type: "str", description: "The state to reflect on." }],
2028
+ returns: { type: "str", description: "The reflected result." }
2029
+ }
2030
+ })
2031
+ ], ReflectTool);
2032
+
2033
+ // src/tools/skills.ts
2034
+ import * as fs5 from "fs";
2035
+ import * as path3 from "path";
2036
+ var SkillsTool = class {
2037
+ /**
2038
+ * Skills directory
2039
+ */
2040
+ skillsDir;
2041
+ constructor(skillsDir = SKILLS_DIR) {
2042
+ this.skillsDir = skillsDir;
2043
+ }
2044
+ /**
2045
+ * Read the content of the skill description file.
2046
+ *
2047
+ * Args:
2048
+ * name (str): The name of the skill
2049
+ *
2050
+ * Returns:
2051
+ * str: The content of the skill description file
2052
+ */
2053
+ async readSkillDescription(name) {
2054
+ const skillsPath = path3.join(this.skillsDir, name, "SKILL.md");
2055
+ if (!fs5.existsSync(skillsPath)) {
2056
+ throw new ToolExecutionError(`Skill description file not found: ${skillsPath}`);
2057
+ }
2058
+ const fileEditor = new FileEditor();
2059
+ const skillDescription = await fileEditor.read(skillsPath);
2060
+ const formattedDescription = `<${name}.SkillDescription>${skillDescription}</${name}.SkillDescription>`;
2061
+ logger.debug(formattedDescription);
2062
+ return formattedDescription;
2063
+ }
2064
+ /**
2065
+ * List the skills in the skills root directory
2066
+ */
2067
+ async listSkills() {
2068
+ if (!fs5.existsSync(this.skillsDir)) {
2069
+ throw new ToolExecutionError(`Skills path not found: ${this.skillsDir}`);
2070
+ }
2071
+ const skillsDict = {};
2072
+ const items = fs5.readdirSync(this.skillsDir);
2073
+ for (const skillName of items) {
2074
+ const skillPath = path3.join(this.skillsDir, skillName, "SKILL.md");
2075
+ if (!fs5.existsSync(skillPath)) {
2076
+ continue;
2077
+ }
2078
+ const fileEditor = new FileEditor();
2079
+ try {
2080
+ const skillContent = await fileEditor.read(skillPath, "1-3");
2081
+ skillsDict[skillName] = skillContent;
2082
+ } catch (error) {
2083
+ logger.warn(`Failed to read skill ${skillName}:`, error);
2084
+ }
2085
+ }
2086
+ const skillsInfo = "<SkillsInformation>" + Object.entries(skillsDict).map(([skillName, content]) => `<${skillName}> ${content} </${skillName}>`).join("\n") + "</SkillsInformation>";
2087
+ logger.debug(skillsInfo);
2088
+ return skillsInfo;
2089
+ }
2090
+ };
2091
+ SkillsTool = __decorateClass([
2092
+ tools({
2093
+ readSkillDescription: {
2094
+ description: "Read the content of the skill description file.",
2095
+ params: [{ name: "name", type: "str", description: "The name of the skill" }],
2096
+ returns: { type: "str", description: "The content of the skill description file" }
2097
+ },
2098
+ listSkills: {
2099
+ description: "List the skills in the skills root directory",
2100
+ returns: { type: "str", description: "The list of skills with their descriptions" }
2101
+ }
2102
+ })
2103
+ ], SkillsTool);
2104
+
2105
+ // src/tools/gitTool.ts
2106
+ import { exec } from "child_process";
2107
+ import * as fs6 from "fs";
2108
+ import * as path4 from "path";
2109
+ function quote(str) {
2110
+ if (/^[a-zA-Z0-9_\-.\/]+$/.test(str)) {
2111
+ return str;
2112
+ }
2113
+ return `'${str.replace(/'/g, "'\\''")}'`;
2114
+ }
2115
+ var gitToolConfig = {
2116
+ init: {
2117
+ description: "Initialize a git repository.",
2118
+ params: [
2119
+ {
2120
+ name: "cwd",
2121
+ type: "string",
2122
+ description: "Working directory, defaults to current directory if None",
2123
+ optional: true
2124
+ },
2125
+ {
2126
+ name: "bare",
2127
+ type: "boolean",
2128
+ description: "Create a bare repository",
2129
+ optional: true
2130
+ },
2131
+ {
2132
+ name: "initialBranch",
2133
+ type: "string",
2134
+ description: "Initial branch name",
2135
+ optional: true
2136
+ },
2137
+ {
2138
+ name: "config",
2139
+ type: "object",
2140
+ description: "Git config options {key: value}",
2141
+ optional: true
2142
+ }
2143
+ ],
2144
+ returns: { type: "string", description: "Initialization result" }
2145
+ },
2146
+ status: {
2147
+ description: "View git repository status, showing changes in working directory and staging area.",
2148
+ params: [
2149
+ {
2150
+ name: "cwd",
2151
+ type: "string",
2152
+ description: "Working directory, defaults to current directory if None",
2153
+ optional: true
2154
+ },
2155
+ {
2156
+ name: "config",
2157
+ type: "object",
2158
+ description: "Git config options {key: value}",
2159
+ optional: true
2160
+ }
2161
+ ],
2162
+ returns: { type: "string", description: "Output of git status" }
2163
+ },
2164
+ add: {
2165
+ description: "Add files to staging area.",
2166
+ params: [
2167
+ {
2168
+ name: "files",
2169
+ type: "string",
2170
+ description: 'File paths to add, can be single file, multiple files (space separated), "." (all files) or path patterns'
2171
+ },
2172
+ {
2173
+ name: "cwd",
2174
+ type: "string",
2175
+ description: "Working directory, defaults to current directory if None",
2176
+ optional: true
2177
+ },
2178
+ {
2179
+ name: "config",
2180
+ type: "object",
2181
+ description: "Git config options {key: value}",
2182
+ optional: true
2183
+ }
2184
+ ],
2185
+ returns: { type: "string", description: "Operation result description" }
2186
+ },
2187
+ commit: {
2188
+ description: "Commit changes in staging area.",
2189
+ params: [
2190
+ { name: "message", type: "string", description: "Commit message" },
2191
+ {
2192
+ name: "cwd",
2193
+ type: "string",
2194
+ description: "Working directory, defaults to current directory if None",
2195
+ optional: true
2196
+ },
2197
+ {
2198
+ name: "allowEmpty",
2199
+ type: "boolean",
2200
+ description: "Whether to allow empty commits, default False",
2201
+ optional: true
2202
+ },
2203
+ {
2204
+ name: "config",
2205
+ type: "object",
2206
+ description: "Git config options {key: value}",
2207
+ optional: true
2208
+ }
2209
+ ],
2210
+ returns: {
2211
+ type: "string",
2212
+ description: "Commit result, including commit hash and change statistics"
2213
+ }
2214
+ },
2215
+ push: {
2216
+ description: "Push local commits to remote repository.",
2217
+ params: [
2218
+ {
2219
+ name: "remote",
2220
+ type: "string",
2221
+ description: "Remote repository name, defaults to origin",
2222
+ optional: true
2223
+ },
2224
+ {
2225
+ name: "branch",
2226
+ type: "string",
2227
+ description: "Branch name to push, defaults to current branch",
2228
+ optional: true
2229
+ },
2230
+ {
2231
+ name: "cwd",
2232
+ type: "string",
2233
+ description: "Working directory, defaults to current directory if None",
2234
+ optional: true
2235
+ },
2236
+ {
2237
+ name: "force",
2238
+ type: "boolean",
2239
+ description: "Whether to force push, default False",
2240
+ optional: true
2241
+ },
2242
+ {
2243
+ name: "config",
2244
+ type: "object",
2245
+ description: "Git config options {key: value}",
2246
+ optional: true
2247
+ }
2248
+ ],
2249
+ returns: { type: "string", description: "Push result description" }
2250
+ },
2251
+ pull: {
2252
+ description: "Pull latest changes from remote repository.",
2253
+ params: [
2254
+ {
2255
+ name: "remote",
2256
+ type: "string",
2257
+ description: "Remote repository name, defaults to origin",
2258
+ optional: true
2259
+ },
2260
+ {
2261
+ name: "branch",
2262
+ type: "string",
2263
+ description: "Branch name to pull, defaults to current branch",
2264
+ optional: true
2265
+ },
2266
+ {
2267
+ name: "cwd",
2268
+ type: "string",
2269
+ description: "Working directory, defaults to current directory if None",
2270
+ optional: true
2271
+ },
2272
+ {
2273
+ name: "config",
2274
+ type: "object",
2275
+ description: "Git config options {key: value}",
2276
+ optional: true
2277
+ }
2278
+ ],
2279
+ returns: { type: "string", description: "Pull result description" }
2280
+ },
2281
+ checkout: {
2282
+ description: "Switch branch or checkout files.",
2283
+ params: [
2284
+ {
2285
+ name: "target",
2286
+ type: "string",
2287
+ description: "Target branch name or file path"
2288
+ },
2289
+ {
2290
+ name: "cwd",
2291
+ type: "string",
2292
+ description: "Working directory, defaults to current directory if None",
2293
+ optional: true
2294
+ },
2295
+ {
2296
+ name: "createBranch",
2297
+ type: "boolean",
2298
+ description: "Whether to create new branch if target doesn't exist, default True",
2299
+ optional: true
2300
+ },
2301
+ {
2302
+ name: "config",
2303
+ type: "object",
2304
+ description: "Git config options {key: value}",
2305
+ optional: true
2306
+ }
2307
+ ],
2308
+ returns: { type: "string", description: "Checkout result description" }
2309
+ },
2310
+ branch: {
2311
+ description: "List all branches or create/delete branch.",
2312
+ params: [
2313
+ {
2314
+ name: "name",
2315
+ type: "string",
2316
+ description: "Branch name, lists all branches if None",
2317
+ optional: true
2318
+ },
2319
+ {
2320
+ name: "cwd",
2321
+ type: "string",
2322
+ description: "Working directory, defaults to current directory if None",
2323
+ optional: true
2324
+ },
2325
+ {
2326
+ name: "delete",
2327
+ type: "boolean",
2328
+ description: "Whether to delete branch, default False",
2329
+ optional: true
2330
+ },
2331
+ {
2332
+ name: "config",
2333
+ type: "object",
2334
+ description: "Git config options {key: value}",
2335
+ optional: true
2336
+ }
2337
+ ],
2338
+ returns: { type: "string", description: "Branch operation result" }
2339
+ },
2340
+ log: {
2341
+ description: "View commit history.",
2342
+ params: [
2343
+ {
2344
+ name: "cwd",
2345
+ type: "string",
2346
+ description: "Working directory, defaults to current directory if None",
2347
+ optional: true
2348
+ },
2349
+ {
2350
+ name: "maxCount",
2351
+ type: "integer",
2352
+ description: "Maximum number of commits to show",
2353
+ optional: true
2354
+ },
2355
+ {
2356
+ name: "oneline",
2357
+ type: "boolean",
2358
+ description: "Whether to show in oneline format, default False",
2359
+ optional: true
2360
+ },
2361
+ {
2362
+ name: "filePath",
2363
+ type: "string",
2364
+ description: "View commit history for specific file",
2365
+ optional: true
2366
+ },
2367
+ {
2368
+ name: "config",
2369
+ type: "object",
2370
+ description: "Git config options {key: value}",
2371
+ optional: true
2372
+ }
2373
+ ],
2374
+ returns: { type: "string", description: "Commit history" }
2375
+ },
2376
+ diff: {
2377
+ description: "View file differences.",
2378
+ params: [
2379
+ {
2380
+ name: "cwd",
2381
+ type: "string",
2382
+ description: "Working directory, defaults to current directory if None",
2383
+ optional: true
2384
+ },
2385
+ {
2386
+ name: "staged",
2387
+ type: "boolean",
2388
+ description: "Whether to view staged changes, default False",
2389
+ optional: true
2390
+ },
2391
+ {
2392
+ name: "filePath",
2393
+ type: "string",
2394
+ description: "View diff for specific file",
2395
+ optional: true
2396
+ },
2397
+ {
2398
+ name: "commit1",
2399
+ type: "string",
2400
+ description: "First commit hash or branch name",
2401
+ optional: true
2402
+ },
2403
+ {
2404
+ name: "commit2",
2405
+ type: "string",
2406
+ description: "Second commit hash or branch name",
2407
+ optional: true
2408
+ },
2409
+ {
2410
+ name: "config",
2411
+ type: "object",
2412
+ description: "Git config options {key: value}",
2413
+ optional: true
2414
+ }
2415
+ ],
2416
+ returns: { type: "string", description: "Diff content" }
2417
+ },
2418
+ remote: {
2419
+ description: "Manage remote repositories.",
2420
+ params: [
2421
+ {
2422
+ name: "action",
2423
+ type: "string",
2424
+ description: 'Action type: "list", "add", "remove", "set-url", default "list"',
2425
+ optional: true
2426
+ },
2427
+ {
2428
+ name: "name",
2429
+ type: "string",
2430
+ description: 'Remote repository name, usually "origin"',
2431
+ optional: true
2432
+ },
2433
+ {
2434
+ name: "url",
2435
+ type: "string",
2436
+ description: "Remote repository URL (for add or set-url)",
2437
+ optional: true
2438
+ },
2439
+ {
2440
+ name: "cwd",
2441
+ type: "string",
2442
+ description: "Working directory, defaults to current directory if None",
2443
+ optional: true
2444
+ },
2445
+ {
2446
+ name: "config",
2447
+ type: "object",
2448
+ description: "Git config options {key: value}",
2449
+ optional: true
2450
+ }
2451
+ ],
2452
+ returns: { type: "string", description: "Operation result" }
2453
+ },
2454
+ clone: {
2455
+ description: "Clone remote repository to local.",
2456
+ params: [
2457
+ { name: "url", type: "string", description: "Remote repository URL" },
2458
+ {
2459
+ name: "directory",
2460
+ type: "string",
2461
+ description: "Local directory name, defaults to repository name if None",
2462
+ optional: true
2463
+ },
2464
+ {
2465
+ name: "cwd",
2466
+ type: "string",
2467
+ description: "Working directory, defaults to current directory if None",
2468
+ optional: true
2469
+ },
2470
+ {
2471
+ name: "config",
2472
+ type: "object",
2473
+ description: "Git config options {key: value}",
2474
+ optional: true
2475
+ }
2476
+ ],
2477
+ returns: { type: "string", description: "Clone result description" }
2478
+ },
2479
+ fetch: {
2480
+ description: "Fetch latest changes from remote without merging.",
2481
+ params: [
2482
+ {
2483
+ name: "remote",
2484
+ type: "string",
2485
+ description: "Remote repository name, defaults to origin",
2486
+ optional: true
2487
+ },
2488
+ {
2489
+ name: "cwd",
2490
+ type: "string",
2491
+ description: "Working directory, defaults to current directory if None",
2492
+ optional: true
2493
+ },
2494
+ {
2495
+ name: "config",
2496
+ type: "object",
2497
+ description: "Git config options {key: value}",
2498
+ optional: true
2499
+ }
2500
+ ],
2501
+ returns: { type: "string", description: "Fetch result description" }
2502
+ },
2503
+ merge: {
2504
+ description: "Merge specified branch into current branch.",
2505
+ params: [
2506
+ { name: "branch", type: "string", description: "Branch name to merge" },
2507
+ {
2508
+ name: "cwd",
2509
+ type: "string",
2510
+ description: "Working directory, defaults to current directory if None",
2511
+ optional: true
2512
+ },
2513
+ {
2514
+ name: "config",
2515
+ type: "object",
2516
+ description: "Git config options {key: value}",
2517
+ optional: true
2518
+ }
2519
+ ],
2520
+ returns: { type: "string", description: "Merge result description" }
2521
+ },
2522
+ show: {
2523
+ description: "Show detailed information about git objects (commits, tags, trees, etc).",
2524
+ params: [
2525
+ {
2526
+ name: "object",
2527
+ type: "string",
2528
+ description: "Object to show (commit hash, tag, branch, etc.), defaults to HEAD",
2529
+ optional: true
2530
+ },
2531
+ {
2532
+ name: "cwd",
2533
+ type: "string",
2534
+ description: "Working directory",
2535
+ optional: true
2536
+ },
2537
+ {
2538
+ name: "stat",
2539
+ type: "boolean",
2540
+ description: "Show status info",
2541
+ optional: true
2542
+ },
2543
+ {
2544
+ name: "nameOnly",
2545
+ type: "boolean",
2546
+ description: "Show only filenames",
2547
+ optional: true
2548
+ },
2549
+ {
2550
+ name: "format",
2551
+ type: "string",
2552
+ description: "Custom format string",
2553
+ optional: true
2554
+ },
2555
+ {
2556
+ name: "config",
2557
+ type: "object",
2558
+ description: "Git config options {key: value}",
2559
+ optional: true
2560
+ }
2561
+ ],
2562
+ returns: { type: "string", description: "Object details" }
2563
+ },
2564
+ tag: {
2565
+ description: "Create, list or delete tags.",
2566
+ params: [
2567
+ {
2568
+ name: "name",
2569
+ type: "string",
2570
+ description: "Tag name, lists all tags if None",
2571
+ optional: true
2572
+ },
2573
+ {
2574
+ name: "cwd",
2575
+ type: "string",
2576
+ description: "Working directory",
2577
+ optional: true
2578
+ },
2579
+ {
2580
+ name: "message",
2581
+ type: "string",
2582
+ description: "Tag message",
2583
+ optional: true
2584
+ },
2585
+ {
2586
+ name: "delete",
2587
+ type: "boolean",
2588
+ description: "Delete tag",
2589
+ optional: true
2590
+ },
2591
+ {
2592
+ name: "listAll",
2593
+ type: "boolean",
2594
+ description: "List all tags",
2595
+ optional: true
2596
+ },
2597
+ {
2598
+ name: "annotate",
2599
+ type: "boolean",
2600
+ description: "Create annotated tag",
2601
+ optional: true
2602
+ },
2603
+ {
2604
+ name: "config",
2605
+ type: "object",
2606
+ description: "Git config options {key: value}",
2607
+ optional: true
2608
+ }
2609
+ ],
2610
+ returns: { type: "string", description: "Tag operation result" }
2611
+ },
2612
+ revert: {
2613
+ description: "Revert existing commits.",
2614
+ params: [
2615
+ {
2616
+ name: "commit",
2617
+ type: "string",
2618
+ description: "Commit hash to revert"
2619
+ },
2620
+ {
2621
+ name: "cwd",
2622
+ type: "string",
2623
+ description: "Working directory",
2624
+ optional: true
2625
+ },
2626
+ {
2627
+ name: "noCommit",
2628
+ type: "boolean",
2629
+ description: "Revert changes but do not commit",
2630
+ optional: true
2631
+ },
2632
+ {
2633
+ name: "noEdit",
2634
+ type: "boolean",
2635
+ description: "Do not edit commit message, default True",
2636
+ optional: true
2637
+ },
2638
+ {
2639
+ name: "mainline",
2640
+ type: "integer",
2641
+ description: "Mainline parent number for merge commits",
2642
+ optional: true
2643
+ },
2644
+ {
2645
+ name: "config",
2646
+ type: "object",
2647
+ description: "Git config options {key: value}",
2648
+ optional: true
2649
+ }
2650
+ ],
2651
+ returns: { type: "string", description: "Revert result" }
2652
+ }
2653
+ };
2654
+ var GitTool = class {
2655
+ /**
2656
+ * Helper method to execute git commands.
2657
+ */
2658
+ async _executeGitCommand(command, cwd, timeout = 3e4, config2) {
2659
+ const workDir = cwd || process.cwd();
2660
+ if (!fs6.existsSync(workDir)) {
2661
+ throw new ToolExecutionError(`\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u5B58\u5728: ${workDir}`);
2662
+ }
2663
+ const gitDir = path4.join(workDir, ".git");
2664
+ const isInitOrClone = command.includes("clone") || command.includes("init");
2665
+ if (!fs6.existsSync(gitDir) && !isInitOrClone) {
2666
+ throw new ToolExecutionError(`\u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93: ${workDir}`);
2667
+ }
2668
+ let gitCmd = "git";
2669
+ if (config2) {
2670
+ for (const [key, value] of Object.entries(config2)) {
2671
+ gitCmd += ` -c ${key}=${quote(value)}`;
2672
+ }
2673
+ }
2674
+ gitCmd += ` ${command}`;
2675
+ return new Promise((resolve2, reject) => {
2676
+ exec(gitCmd, { cwd: workDir, timeout, encoding: "utf-8" }, (error, stdout, stderr) => {
2677
+ const stdoutText = stdout ? stdout.trim() : "";
2678
+ const stderrText = stderr ? stderr.trim() : "";
2679
+ if (error) {
2680
+ if (error.signal === "SIGTERM") {
2681
+ reject(new ToolExecutionError(`Git \u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF08\u8D85\u8FC7 ${timeout / 1e3} \u79D2\uFF09`));
2682
+ return;
2683
+ }
2684
+ const errorMsg = stderrText || stdoutText || error.message;
2685
+ reject(new ToolExecutionError(`Git \u547D\u4EE4\u6267\u884C\u5931\u8D25: ${errorMsg}`));
2686
+ return;
2687
+ }
2688
+ resolve2(stdoutText || "\u547D\u4EE4\u6267\u884C\u6210\u529F\uFF0C\u65E0\u8F93\u51FA");
2689
+ });
2690
+ });
2691
+ }
2692
+ /**
2693
+ * Get current branch name.
2694
+ */
2695
+ async _getCurrentBranch(cwd, config2) {
2696
+ const result = await this._executeGitCommand("rev-parse --abbrev-ref HEAD", cwd, 3e4, config2);
2697
+ return result.trim();
2698
+ }
2699
+ async init(cwd, bare = false, initialBranch, config2) {
2700
+ let command = "init";
2701
+ if (bare) command += " --bare";
2702
+ if (initialBranch) command += ` --initial-branch=${initialBranch}`;
2703
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2704
+ return `Git \u4ED3\u5E93\u521D\u59CB\u5316\u5B8C\u6210
2705
+ ${result}`;
2706
+ }
2707
+ async status(cwd, config2) {
2708
+ return await this._executeGitCommand("status", cwd, 3e4, config2);
2709
+ }
2710
+ async add(files, cwd, config2) {
2711
+ const result = await this._executeGitCommand(`add ${files}`, cwd, 3e4, config2);
2712
+ return `\u6210\u529F\u5C06\u6587\u4EF6\u6DFB\u52A0\u5230\u6682\u5B58\u533A: ${files}
2713
+ ${result}`;
2714
+ }
2715
+ async commit(message, cwd, allowEmpty = false, config2) {
2716
+ const allowEmptyFlag = allowEmpty ? " --allow-empty" : "";
2717
+ const result = await this._executeGitCommand(`commit -m ${quote(message)}${allowEmptyFlag}`, cwd, 3e4, config2);
2718
+ return `\u63D0\u4EA4\u6210\u529F
2719
+ ${result}`;
2720
+ }
2721
+ async push(remote = "origin", branch, cwd, force = false, config2) {
2722
+ const targetBranch = branch || await this._getCurrentBranch(cwd, config2);
2723
+ const forceFlag = force ? " --force" : "";
2724
+ const result = await this._executeGitCommand(`push${forceFlag} ${remote} ${targetBranch}`, cwd, 6e4, config2);
2725
+ return `\u6210\u529F\u63A8\u9001\u5230 ${remote}/${targetBranch}
2726
+ ${result}`;
2727
+ }
2728
+ async pull(remote = "origin", branch, cwd, config2) {
2729
+ const targetBranch = branch || await this._getCurrentBranch(cwd, config2);
2730
+ const result = await this._executeGitCommand(`pull ${remote} ${targetBranch}`, cwd, 6e4, config2);
2731
+ return `\u6210\u529F\u4ECE ${remote}/${targetBranch} \u62C9\u53D6\u66F4\u6539
2732
+ ${result}`;
2733
+ }
2734
+ async checkout(target, cwd, createBranch = true, config2) {
2735
+ const createFlag = createBranch ? " -b" : "";
2736
+ const result = await this._executeGitCommand(`checkout${createFlag} ${target}`, cwd, 3e4, config2);
2737
+ return `\u6210\u529F\u5207\u6362\u5230 ${target}
2738
+ ${result}`;
2739
+ }
2740
+ async branch(name, cwd, deleteBranch = false, config2) {
2741
+ if (!name) {
2742
+ const result = await this._executeGitCommand("branch -a", cwd, 3e4, config2);
2743
+ return `\u6240\u6709\u5206\u652F\u5217\u8868:
2744
+ ${result}`;
2745
+ } else if (deleteBranch) {
2746
+ const result = await this._executeGitCommand(`branch -d ${name}`, cwd, 3e4, config2);
2747
+ return `\u6210\u529F\u5220\u9664\u5206\u652F ${name}
2748
+ ${result}`;
2749
+ } else {
2750
+ const result = await this._executeGitCommand(`branch ${name}`, cwd, 3e4, config2);
2751
+ return `\u6210\u529F\u521B\u5EFA\u5206\u652F ${name}
2752
+ ${result}`;
2753
+ }
2754
+ }
2755
+ async log(cwd, maxCount, oneline = false, filePath, config2) {
2756
+ let command = "log";
2757
+ if (oneline) command += " --oneline";
2758
+ if (maxCount) command += ` -${maxCount}`;
2759
+ if (filePath) command += ` -- ${filePath}`;
2760
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2761
+ return `\u63D0\u4EA4\u5386\u53F2:
2762
+ ${result}`;
2763
+ }
2764
+ async diff(cwd, staged = false, filePath, commit1, commit2, config2) {
2765
+ let command = "diff";
2766
+ if (staged) command += " --staged";
2767
+ if (commit1 && commit2) {
2768
+ command += ` ${commit1} ${commit2}`;
2769
+ } else if (commit1) {
2770
+ command += ` ${commit1}`;
2771
+ }
2772
+ if (filePath) command += ` -- ${filePath}`;
2773
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2774
+ return `\u5DEE\u5F02\u5185\u5BB9:
2775
+ ${result}`;
2776
+ }
2777
+ async remote(action = "list", name, url, cwd, config2) {
2778
+ if (action === "list") {
2779
+ const result = await this._executeGitCommand("remote -v", cwd, 3e4, config2);
2780
+ return `\u8FDC\u7A0B\u4ED3\u5E93\u5217\u8868:
2781
+ ${result}`;
2782
+ } else if (action === "add") {
2783
+ if (!name || !url) throw new ToolExecutionError("\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93\u9700\u8981\u63D0\u4F9B name \u548C url \u53C2\u6570");
2784
+ const result = await this._executeGitCommand(`remote add ${name} ${url}`, cwd, 3e4, config2);
2785
+ return `\u6210\u529F\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93 ${name}: ${url}
2786
+ ${result}`;
2787
+ } else if (action === "remove") {
2788
+ if (!name) throw new ToolExecutionError("\u5220\u9664\u8FDC\u7A0B\u4ED3\u5E93\u9700\u8981\u63D0\u4F9B name \u53C2\u6570");
2789
+ const result = await this._executeGitCommand(`remote remove ${name}`, cwd, 3e4, config2);
2790
+ return `\u6210\u529F\u5220\u9664\u8FDC\u7A0B\u4ED3\u5E93 ${name}
2791
+ ${result}`;
2792
+ } else if (action === "set-url") {
2793
+ if (!name || !url) throw new ToolExecutionError("\u8BBE\u7F6E\u8FDC\u7A0B\u4ED3\u5E93 URL \u9700\u8981\u63D0\u4F9B name \u548C url \u53C2\u6570");
2794
+ const result = await this._executeGitCommand(`remote set-url ${name} ${url}`, cwd, 3e4, config2);
2795
+ return `\u6210\u529F\u8BBE\u7F6E\u8FDC\u7A0B\u4ED3\u5E93 ${name} \u7684 URL \u4E3A {url}
2796
+ ${result}`;
2797
+ } else {
2798
+ throw new ToolExecutionError(`\u4E0D\u652F\u6301\u7684\u64CD\u4F5C\u7C7B\u578B: ${action}\uFF0C\u652F\u6301\u7684\u64CD\u4F5C: list, add, remove, set-url`);
2799
+ }
2800
+ }
2801
+ async clone(url, directory, cwd, config2) {
2802
+ const workDir = cwd || process.cwd();
2803
+ let command = `clone ${url}`;
2804
+ if (directory) command += ` ${directory}`;
2805
+ const result = await this._executeGitCommand(command, workDir, 12e4, config2);
2806
+ return `\u6210\u529F\u514B\u9686\u4ED3\u5E93 ${url}
2807
+ ${result}`;
2808
+ }
2809
+ async fetch(remote = "origin", cwd, config2) {
2810
+ const result = await this._executeGitCommand(`fetch ${remote}`, cwd, 6e4, config2);
2811
+ return `\u6210\u529F\u4ECE ${remote} \u83B7\u53D6\u66F4\u65B0
2812
+ ${result}`;
2813
+ }
2814
+ async merge(branch, cwd, config2) {
2815
+ const noFfFlag = "";
2816
+ const result = await this._executeGitCommand(`merge${noFfFlag} ${branch}`, cwd, 3e4, config2);
2817
+ return `\u6210\u529F\u5408\u5E76\u5206\u652F ${branch}
2818
+ ${result}`;
2819
+ }
2820
+ async show(object, cwd, stat = false, nameOnly = false, format2, config2) {
2821
+ let command = "show";
2822
+ if (object) command += ` ${object}`;
2823
+ if (stat) command += " --stat";
2824
+ if (nameOnly) command += " --name-only";
2825
+ if (format2) command += ` --format=${format2}`;
2826
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2827
+ return `\u663E\u793A\u5BF9\u8C61\u4FE1\u606F:
2828
+ ${result}`;
2829
+ }
2830
+ async tag(name, cwd, message, deleteTag = false, listAll = false, annotate = false, config2) {
2831
+ if (!name) {
2832
+ let command = "tag";
2833
+ if (listAll) command += " -l";
2834
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2835
+ return `\u6807\u7B7E\u5217\u8868:
2836
+ ${result}`;
2837
+ } else if (deleteTag) {
2838
+ const result = await this._executeGitCommand(`tag -d ${name}`, cwd, 3e4, config2);
2839
+ return `\u6210\u529F\u5220\u9664\u6807\u7B7E ${name}
2840
+ ${result}`;
2841
+ } else {
2842
+ let command = "tag";
2843
+ if (annotate || message) command += " -a";
2844
+ if (message) command += ` -m ${quote(message)}`;
2845
+ command += ` ${name}`;
2846
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2847
+ return `\u6210\u529F\u521B\u5EFA\u6807\u7B7E ${name}
2848
+ ${result}`;
2849
+ }
2850
+ }
2851
+ async revert(commit, cwd, noCommit = false, noEdit = true, mainline, config2) {
2852
+ let command = "revert";
2853
+ if (noCommit) command += " --no-commit";
2854
+ if (noEdit) command += " --no-edit";
2855
+ if (mainline) command += ` -m ${mainline}`;
2856
+ command += ` ${commit}`;
2857
+ const result = await this._executeGitCommand(command, cwd, 3e4, config2);
2858
+ return `\u6210\u529F\u64A4\u9500\u63D0\u4EA4 ${commit}
2859
+ ${result}`;
2860
+ }
2861
+ };
2862
+ GitTool = __decorateClass([
2863
+ tools(gitToolConfig)
2864
+ ], GitTool);
2865
+
2866
+ // src/model.ts
2867
+ import OpenAI from "openai";
2868
+ import Anthropic from "@anthropic-ai/sdk";
2869
+ import { GoogleGenerativeAI } from "@google/generative-ai";
2870
+ var Model = class {
2871
+ modelName;
2872
+ config;
2873
+ openaiClient;
2874
+ anthropicClient;
2875
+ geminiClient;
2876
+ constructor(model) {
2877
+ if (typeof model === "string" || model === void 0) {
2878
+ this.modelName = model || "deepseek";
2879
+ this.config = loadModelConfig(this.modelName);
2880
+ } else {
2881
+ this.config = model;
2882
+ this.modelName = model.model || "deepseek";
2883
+ }
2884
+ this._initializeClient();
2885
+ }
2886
+ /**
2887
+ * Initialize the appropriate SDK client based on provider
2888
+ */
2889
+ _initializeClient() {
2890
+ const provider = this.config.provider.toLowerCase();
2891
+ switch (provider) {
2892
+ case "openai":
2893
+ this.openaiClient = new OpenAI({
2894
+ apiKey: this.config.apiKey || process.env.OPENAI_API_KEY,
2895
+ baseURL: this.config.baseUrl,
2896
+ timeout: 6e4
2897
+ });
2898
+ break;
2899
+ case "deepseek":
2900
+ this.openaiClient = new OpenAI({
2901
+ apiKey: this.config.apiKey || process.env.DEEPSEEK_API_KEY,
2902
+ baseURL: this.config.baseUrl || "https://api.deepseek.com",
2903
+ timeout: 6e4
2904
+ });
2905
+ break;
2906
+ case "anthropic":
2907
+ if (this.config.baseUrl.endsWith("/v1") || this.config.baseUrl.endsWith("v1/")) {
2908
+ this.config.baseUrl = this.config.baseUrl.slice(0, -3);
2909
+ }
2910
+ this.anthropicClient = new Anthropic({
2911
+ apiKey: this.config.apiKey || process.env.ANTHROPIC_API_KEY,
2912
+ baseURL: this.config.baseUrl,
2913
+ timeout: 6e4
2914
+ });
2915
+ break;
2916
+ case "gemini":
2917
+ const apiKey = this.config.apiKey || process.env.GEMINI_API_KEY || "";
2918
+ this.geminiClient = new GoogleGenerativeAI(apiKey);
2919
+ break;
2920
+ default:
2921
+ throw new ModelError(`Unsupported provider: ${provider}`);
2922
+ }
2923
+ }
2924
+ /**
2925
+ * Asynchronous chat completion
2926
+ */
2927
+ async achat(messages, tools2, stream = true) {
2928
+ const provider = this.config.provider.toLowerCase();
2929
+ const useStream = stream !== void 0 ? stream : !!this.config.stream;
2930
+ try {
2931
+ switch (provider) {
2932
+ case "openai":
2933
+ case "deepseek":
2934
+ return await this._callOpenAICompatible(messages, tools2, useStream);
2935
+ case "anthropic":
2936
+ return await this._callAnthropic(messages, tools2, useStream);
2937
+ case "gemini":
2938
+ return await this._callGemini(messages, tools2, useStream);
2939
+ default:
2940
+ throw new ModelError(`Unsupported provider: ${provider}`);
2941
+ }
2942
+ } catch (error) {
2943
+ logger.error(`Model call failed: ${error}`);
2944
+ throw error;
2945
+ }
2946
+ }
2947
+ /**
2948
+ * Call OpenAI-compatible API (OpenAI, DeepSeek, etc.)
2949
+ */
2950
+ async _callOpenAICompatible(messages, tools2, stream = false) {
2951
+ if (!this.openaiClient) {
2952
+ throw new ModelError("OpenAI client not initialized");
2953
+ }
2954
+ try {
2955
+ const params = {
2956
+ model: this.config.model || "gpt-3.5-turbo",
2957
+ messages,
2958
+ temperature: this.config.temperature || 0.7,
2959
+ max_tokens: this.config.maxOutputTokens || 1024,
2960
+ top_p: this.config.topP || 0.9,
2961
+ stream
2962
+ };
2963
+ if (tools2 && tools2.length > 0) {
2964
+ params.tools = tools2;
2965
+ params.tool_choice = "auto";
2966
+ }
2967
+ if (stream) {
2968
+ const streamResponse = await this.openaiClient.chat.completions.create({
2969
+ ...params,
2970
+ stream: true
2971
+ });
2972
+ let fullContent = "";
2973
+ let toolCallsMap = {};
2974
+ for await (const chunk of streamResponse) {
2975
+ const delta = chunk.choices[0]?.delta;
2976
+ if (!delta) continue;
2977
+ if (delta.content) {
2978
+ streamLogger2.info(delta.content);
2979
+ fullContent += delta.content;
2980
+ }
2981
+ if (delta.tool_calls) {
2982
+ for (const tc of delta.tool_calls) {
2983
+ const index = tc.index;
2984
+ if (!toolCallsMap[index]) {
2985
+ toolCallsMap[index] = {
2986
+ id: tc.id || "",
2987
+ type: "function",
2988
+ function: {
2989
+ name: tc.function?.name || "",
2990
+ arguments: tc.function?.arguments || ""
2991
+ }
2992
+ };
2993
+ if (tc.function?.name) {
2994
+ streamLogger2.info(`
2995
+ Tool Call: ${tc.function.name}
2996
+ Arguments: `);
2997
+ }
2998
+ } else {
2999
+ if (tc.function?.arguments) {
3000
+ toolCallsMap[index].function.arguments += tc.function.arguments;
3001
+ streamLogger2.info(tc.function.arguments);
3002
+ }
3003
+ }
3004
+ }
3005
+ }
3006
+ }
3007
+ streamLogger2.info("\n");
3008
+ const toolCalls = Object.values(toolCallsMap);
3009
+ const hasContent = fullContent.trim().length > 0;
3010
+ const hasToolCalls = toolCalls.length > 0;
3011
+ if (hasToolCalls) {
3012
+ return [
3013
+ {
3014
+ type: "user",
3015
+ extractedResult: () => ({
3016
+ role: "assistant",
3017
+ content: fullContent,
3018
+ tool_calls: toolCalls
3019
+ })
3020
+ }
3021
+ ];
3022
+ }
3023
+ return [
3024
+ {
3025
+ type: "system",
3026
+ extractedResult: () => fullContent,
3027
+ rawContentFromLlm: fullContent
3028
+ }
3029
+ ];
3030
+ } else {
3031
+ const response = await this.openaiClient.chat.completions.create(params);
3032
+ if (!response.choices || response.choices.length === 0) {
3033
+ throw new ModelError("No choices returned from OpenAI API");
3034
+ }
3035
+ const message = response.choices[0].message;
3036
+ const messageContent = message.content || "";
3037
+ const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
3038
+ if (hasToolCalls) {
3039
+ return [
3040
+ {
3041
+ type: "user",
3042
+ extractedResult: () => ({
3043
+ role: "assistant",
3044
+ content: messageContent,
3045
+ tool_calls: message.tool_calls
3046
+ })
3047
+ }
3048
+ ];
3049
+ }
3050
+ return [
3051
+ {
3052
+ type: "system",
3053
+ extractedResult: () => messageContent,
3054
+ rawContentFromLlm: messageContent
3055
+ }
3056
+ ];
3057
+ }
3058
+ } catch (error) {
3059
+ const errorMsg = error.message || "Unknown error";
3060
+ throw new ModelError(`OpenAI-compatible API call failed: ${errorMsg}, model config: ${JSON.stringify(this.config)}`);
3061
+ }
3062
+ }
3063
+ /**
3064
+ * Call Anthropic API
3065
+ */
3066
+ async _callAnthropic(messages, tools2, stream = false) {
3067
+ if (!this.anthropicClient) {
3068
+ throw new ModelError("Anthropic client not initialized");
3069
+ }
3070
+ try {
3071
+ const systemMessage = messages.find((m) => m.role === "system");
3072
+ const nonSystemMessages = messages.filter((m) => m.role !== "system");
3073
+ const params = {
3074
+ model: this.config.model || "claude-3-sonnet-20240229",
3075
+ messages: nonSystemMessages,
3076
+ max_tokens: this.config.maxOutputTokens || 4096,
3077
+ temperature: this.config.temperature || 0.7,
3078
+ top_p: this.config.topP || 0.9,
3079
+ stream
3080
+ };
3081
+ if (systemMessage) {
3082
+ params.system = systemMessage.content;
3083
+ }
3084
+ if (tools2 && tools2.length > 0) {
3085
+ params.tools = tools2.map((tool) => ({
3086
+ name: tool.function?.name || tool.name,
3087
+ description: tool.function?.description || tool.description,
3088
+ input_schema: tool.function?.parameters || tool.input_schema
3089
+ }));
3090
+ }
3091
+ if (stream) {
3092
+ const streamResponse = await this.anthropicClient.messages.stream({
3093
+ ...params,
3094
+ stream: true
3095
+ });
3096
+ let fullContent = "";
3097
+ let toolUses = [];
3098
+ for await (const event of streamResponse) {
3099
+ if (event.type === "content_block_start") {
3100
+ if (event.content_block.type === "tool_use") {
3101
+ const toolUse = event.content_block;
3102
+ streamLogger2.info(`
3103
+ Tool Call: ${toolUse.name}
3104
+ Arguments: `);
3105
+ }
3106
+ } else if (event.type === "content_block_delta") {
3107
+ if (event.delta.type === "text_delta") {
3108
+ streamLogger2.info(event.delta.text);
3109
+ fullContent += event.delta.text;
3110
+ } else if (event.delta.type === "input_json_delta") {
3111
+ streamLogger2.info(event.delta.partial_json);
3112
+ }
3113
+ } else if (event.type === "message_delta") {
3114
+ }
3115
+ }
3116
+ streamLogger2.info("\n");
3117
+ const hasContent = fullContent.trim().length > 0;
3118
+ const hasToolUses = toolUses.length > 0;
3119
+ return [
3120
+ {
3121
+ type: "system",
3122
+ extractedResult: () => fullContent || toolUses,
3123
+ rawContentFromLlm: fullContent
3124
+ }
3125
+ ];
3126
+ } else {
3127
+ const response = await this.anthropicClient.messages.create(params);
3128
+ if (!response.content || response.content.length === 0) {
3129
+ throw new ModelError("No content returned from Anthropic API");
3130
+ }
3131
+ const toolUse = response.content.find((c) => c.type === "tool_use");
3132
+ if (toolUse) {
3133
+ return [
3134
+ {
3135
+ type: "system",
3136
+ extractedResult: () => [toolUse]
3137
+ }
3138
+ ];
3139
+ }
3140
+ const textContent = response.content.find((c) => c.type === "text");
3141
+ const messageContent = textContent?.text || "";
3142
+ return [
3143
+ {
3144
+ type: "system",
3145
+ extractedResult: () => messageContent,
3146
+ rawContentFromLlm: messageContent
3147
+ }
3148
+ ];
3149
+ }
3150
+ } catch (error) {
3151
+ const errorMsg = error.message || "Unknown error";
3152
+ throw new ModelError(`Anthropic API call failed: ${errorMsg}`);
3153
+ }
3154
+ }
3155
+ /**
3156
+ * Call Google Gemini API
3157
+ */
3158
+ async _callGemini(messages, tools2, stream = false) {
3159
+ if (!this.geminiClient) {
3160
+ throw new ModelError("Gemini client not initialized");
3161
+ }
3162
+ try {
3163
+ const modelName = this.config.model || "gemini-pro";
3164
+ const model = this.geminiClient.getGenerativeModel({
3165
+ model: modelName,
3166
+ generationConfig: {
3167
+ temperature: this.config.temperature || 0.7,
3168
+ maxOutputTokens: this.config.maxOutputTokens || 2048,
3169
+ topP: this.config.topP || 0.9
3170
+ }
3171
+ });
3172
+ const contents = this._convertMessagesToGeminiFormat(messages);
3173
+ if (stream) {
3174
+ const result = await model.generateContentStream({ contents });
3175
+ let fullContent = "";
3176
+ let functionCalls = [];
3177
+ for await (const chunk of result.stream) {
3178
+ try {
3179
+ const chunkText = await chunk.text();
3180
+ if (chunkText) {
3181
+ streamLogger2.info(chunkText);
3182
+ fullContent += chunkText;
3183
+ }
3184
+ } catch (e) {
3185
+ }
3186
+ const candidates = chunk.candidates;
3187
+ if (candidates && candidates[0]?.content?.parts) {
3188
+ for (const part of candidates[0].content.parts) {
3189
+ if (part.functionCall) {
3190
+ functionCalls.push(part.functionCall);
3191
+ }
3192
+ }
3193
+ }
3194
+ }
3195
+ streamLogger2.info("\n");
3196
+ const hasContent = fullContent.trim().length > 0;
3197
+ const hasFunctionCalls = functionCalls.length > 0;
3198
+ if (hasFunctionCalls) {
3199
+ const toolCalls = functionCalls.map((fc, index) => ({
3200
+ id: `call_${Date.now()}_${index}`,
3201
+ type: "function",
3202
+ function: {
3203
+ name: fc.name,
3204
+ arguments: JSON.stringify(fc.args)
3205
+ }
3206
+ }));
3207
+ return [
3208
+ {
3209
+ type: "user",
3210
+ extractedResult: () => ({
3211
+ role: "assistant",
3212
+ content: fullContent,
3213
+ tool_calls: toolCalls
3214
+ })
3215
+ }
3216
+ ];
3217
+ }
3218
+ return [
3219
+ {
3220
+ type: "system",
3221
+ extractedResult: () => fullContent,
3222
+ rawContentFromLlm: fullContent
3223
+ }
3224
+ ];
3225
+ } else {
3226
+ const result = await model.generateContent({ contents });
3227
+ const response = result.response;
3228
+ if (!response.candidates || response.candidates.length === 0) {
3229
+ throw new ModelError("No candidates returned from Gemini API");
3230
+ }
3231
+ const candidate = response.candidates[0];
3232
+ const content = candidate.content;
3233
+ if (!content || !content.parts || content.parts.length === 0) {
3234
+ throw new ModelError("No content parts returned from Gemini API");
3235
+ }
3236
+ const functionCalls = content.parts.filter((part) => part.functionCall);
3237
+ const hasFunctionCalls = functionCalls.length > 0;
3238
+ if (hasFunctionCalls) {
3239
+ const toolCalls = functionCalls.map((part, index) => ({
3240
+ id: `call_${Date.now()}_${index}`,
3241
+ type: "function",
3242
+ function: {
3243
+ name: part.functionCall.name,
3244
+ arguments: JSON.stringify(part.functionCall.args)
3245
+ }
3246
+ }));
3247
+ const textParts2 = content.parts.filter((part) => part.text);
3248
+ const textContent2 = textParts2.map((part) => part.text).join("");
3249
+ return [
3250
+ {
3251
+ type: "user",
3252
+ extractedResult: () => ({
3253
+ role: "assistant",
3254
+ content: textContent2,
3255
+ tool_calls: toolCalls
3256
+ })
3257
+ }
3258
+ ];
3259
+ }
3260
+ const textParts = content.parts.filter((part) => part.text);
3261
+ const textContent = textParts.map((part) => part.text).join("");
3262
+ return [
3263
+ {
3264
+ type: "system",
3265
+ extractedResult: () => textContent,
3266
+ rawContentFromLlm: textContent
3267
+ }
3268
+ ];
3269
+ }
3270
+ } catch (error) {
3271
+ const errorMsg = error.message || "Unknown error";
3272
+ throw new ModelError(`Gemini API call failed: ${errorMsg}`);
3273
+ }
3274
+ }
3275
+ /**
3276
+ * Convert OpenAI format messages to Gemini format
3277
+ */
3278
+ _convertMessagesToGeminiFormat(messages) {
3279
+ const contents = [];
3280
+ for (const message of messages) {
3281
+ if (message.role === "system") {
3282
+ contents.push({
3283
+ role: "user",
3284
+ parts: [{ text: message.content }]
3285
+ });
3286
+ } else if (message.role === "user") {
3287
+ contents.push({
3288
+ role: "user",
3289
+ parts: [{ text: message.content }]
3290
+ });
3291
+ } else if (message.role === "assistant") {
3292
+ const parts = [];
3293
+ if (message.content) {
3294
+ parts.push({ text: message.content });
3295
+ }
3296
+ if (message.tool_calls) {
3297
+ for (const toolCall of message.tool_calls) {
3298
+ parts.push({
3299
+ functionCall: {
3300
+ name: toolCall.function.name,
3301
+ args: JSON.parse(toolCall.function.arguments)
3302
+ }
3303
+ });
3304
+ }
3305
+ }
3306
+ contents.push({
3307
+ role: "model",
3308
+ parts
3309
+ });
3310
+ } else if (message.role === "tool") {
3311
+ contents.push({
3312
+ role: "function",
3313
+ parts: [
3314
+ {
3315
+ functionResponse: {
3316
+ name: message.name,
3317
+ response: {
3318
+ content: message.content
3319
+ }
3320
+ }
3321
+ }
3322
+ ]
3323
+ });
3324
+ }
3325
+ }
3326
+ return contents;
3327
+ }
3328
+ /**
3329
+ * Get model configuration
3330
+ */
3331
+ getConfig() {
3332
+ return { ...this.config };
3333
+ }
3334
+ /**
3335
+ * Get model name
3336
+ */
3337
+ getName() {
3338
+ return this.modelName;
3339
+ }
3340
+ /**
3341
+ * Check if model supports tool calling
3342
+ */
3343
+ supportsToolCalling() {
3344
+ const supportedModels = ["gpt-3.5-turbo", "gpt-4", "claude-3", "deepseek-chat", "gemini-pro", "gemini-1.5"];
3345
+ return supportedModels.some((model) => this.config.model.includes(model));
3346
+ }
3347
+ };
3348
+
3349
+ // src/schemas/message.ts
3350
+ import * as fs7 from "fs";
3351
+ var Message = class _Message {
3352
+ role;
3353
+ content;
3354
+ images;
3355
+ type;
3356
+ constructor(role, content, images, type) {
3357
+ this.role = role;
3358
+ this.content = content;
3359
+ this.images = images;
3360
+ this.type = type;
3361
+ }
3362
+ /**
3363
+ * Create message from user input
3364
+ */
3365
+ static fromUserMsg(content, images) {
3366
+ return new _Message("user", content, images);
3367
+ }
3368
+ /**
3369
+ * Create message from assistant response
3370
+ */
3371
+ static fromAssistantMsg(content) {
3372
+ return new _Message("assistant", content);
3373
+ }
3374
+ /**
3375
+ * Create system message
3376
+ */
3377
+ static fromSystemMsg(content) {
3378
+ return new _Message("system", content);
3379
+ }
3380
+ /**
3381
+ * Convert to plain object for API calls
3382
+ */
3383
+ toObject() {
3384
+ const obj = {
3385
+ role: this.role,
3386
+ content: this.content
3387
+ };
3388
+ if (this.images) {
3389
+ obj.images = this.images;
3390
+ }
3391
+ if (this.type) {
3392
+ obj.type = this.type;
3393
+ }
3394
+ return obj;
3395
+ }
3396
+ /**
3397
+ * Check if message contains images
3398
+ */
3399
+ hasImages() {
3400
+ return !!this.images && (Array.isArray(this.images) ? this.images.length > 0 : true);
3401
+ }
3402
+ /**
3403
+ * Get message content length
3404
+ */
3405
+ getContentLength() {
3406
+ return this.content.length;
3407
+ }
3408
+ /**
3409
+ * Convert to string representation
3410
+ */
3411
+ toString() {
3412
+ return `${this.role}: ${this.content}`;
3413
+ }
3414
+ /**
3415
+ * Convert to OpenAI Vision API format with base64-encoded images
3416
+ * This method handles:
3417
+ * - HTTP/HTTPS URLs: Downloads and converts to base64
3418
+ * - Local file paths: Reads file and converts to base64
3419
+ * - Already base64 strings: Passes through
3420
+ */
3421
+ async toChatMessage() {
3422
+ const role = this.role;
3423
+ if (!this.hasImages()) {
3424
+ return { role, content: this.content };
3425
+ }
3426
+ const content = [{ type: "text", text: this.content }];
3427
+ const imageArray = Array.isArray(this.images) ? this.images : [this.images];
3428
+ for (const img of imageArray) {
3429
+ let base64Data;
3430
+ if (img.startsWith("http://") || img.startsWith("https://")) {
3431
+ base64Data = await this.encodeHttpImage(img);
3432
+ } else if (fs7.existsSync(img)) {
3433
+ base64Data = await this.encodeLocalFile(img);
3434
+ } else {
3435
+ base64Data = img;
3436
+ }
3437
+ const mimeType = this.getMimeType(img);
3438
+ content.push({
3439
+ type: "image_url",
3440
+ image_url: { url: `data:${mimeType};base64,${base64Data}` }
3441
+ });
3442
+ }
3443
+ return { role, content };
3444
+ }
3445
+ /**
3446
+ * Get MIME type from file path or URL
3447
+ */
3448
+ getMimeType(path5) {
3449
+ const ext = path5.toLowerCase().split(".").pop();
3450
+ const mimeTypes = {
3451
+ png: "image/png",
3452
+ jpg: "image/jpeg",
3453
+ jpeg: "image/jpeg",
3454
+ gif: "image/gif",
3455
+ webp: "image/webp",
3456
+ bmp: "image/bmp"
3457
+ };
3458
+ return mimeTypes[ext || ""] || "image/jpeg";
3459
+ }
3460
+ /**
3461
+ * Encode local file to base64
3462
+ */
3463
+ async encodeLocalFile(filePath) {
3464
+ const fileBuffer = await fs7.promises.readFile(filePath);
3465
+ return fileBuffer.toString("base64");
3466
+ }
3467
+ /**
3468
+ * Fetch and encode HTTP image to base64
3469
+ */
3470
+ async encodeHttpImage(url) {
3471
+ const response = await fetch(url);
3472
+ if (!response.ok) {
3473
+ throw new Error(`Failed to fetch image from ${url}: ${response.statusText}`);
3474
+ }
3475
+ const buffer = await response.arrayBuffer();
3476
+ return Buffer.from(buffer).toString("base64");
3477
+ }
3478
+ };
3479
+
3480
+ // src/memory/messageHistory.ts
3481
+ var MessageHistory = class {
3482
+ messages = [];
3483
+ systemPrompt;
3484
+ model;
3485
+ contextWindowTokens;
3486
+ currentTokens = 0;
3487
+ constructor(model, system, contextWindowTokens) {
3488
+ this.model = model;
3489
+ this.systemPrompt = system;
3490
+ this.contextWindowTokens = contextWindowTokens;
3491
+ if (system) {
3492
+ const systemMessage = new Message("system", system);
3493
+ this.messages.push(systemMessage);
3494
+ this.currentTokens += this.estimateTokens(system);
3495
+ }
3496
+ }
3497
+ addMessage(arg1, arg2) {
3498
+ let message;
3499
+ if (arg1 instanceof Message) {
3500
+ message = arg1;
3501
+ } else if (typeof arg1 === "string") {
3502
+ message = new Message(arg1, arg2);
3503
+ } else if (typeof arg1 === "object" && arg1 !== null) {
3504
+ this.messages.push(arg1);
3505
+ const contentStr = arg1.content || JSON.stringify(arg1);
3506
+ this.currentTokens += this.estimateTokens(contentStr);
3507
+ return;
3508
+ } else {
3509
+ throw new Error(`Invalid message format: ${arg1}`);
3510
+ }
3511
+ this.messages.push(message);
3512
+ this.currentTokens += this.estimateTokens(message.content);
3513
+ }
3514
+ /**
3515
+ * Get all messages
3516
+ */
3517
+ getMessages() {
3518
+ return [...this.messages];
3519
+ }
3520
+ /**
3521
+ * Get messages formatted for API calls
3522
+ * Async version to handle base64 image encoding
3523
+ */
3524
+ async formatForApi() {
3525
+ const results = [];
3526
+ for (const msg of this.messages) {
3527
+ if (msg instanceof Message) {
3528
+ if (msg.hasImages()) {
3529
+ results.push(await msg.toChatMessage());
3530
+ } else {
3531
+ results.push(msg.toObject());
3532
+ }
3533
+ } else if (typeof msg.toObject === "function") {
3534
+ results.push(msg.toObject());
3535
+ } else {
3536
+ results.push(msg);
3537
+ }
3538
+ }
3539
+ return results;
3540
+ }
3541
+ /**
3542
+ * Update system prompt
3543
+ */
3544
+ updateSystem(system) {
3545
+ this.messages = this.messages.filter((msg) => {
3546
+ if (msg instanceof Message) {
3547
+ return msg.role !== "system";
3548
+ }
3549
+ return msg.role !== "system";
3550
+ });
3551
+ this.currentTokens = 0;
3552
+ if (system) {
3553
+ const systemMessage = new Message("system", system);
3554
+ this.messages.unshift(systemMessage);
3555
+ this.currentTokens += this.estimateTokens(system);
3556
+ }
3557
+ for (const message of this.messages) {
3558
+ if (message instanceof Message) {
3559
+ if (message.role !== "system") {
3560
+ this.currentTokens += this.estimateTokens(message.content);
3561
+ }
3562
+ } else {
3563
+ const contentStr = message.content || JSON.stringify(message);
3564
+ this.currentTokens += this.estimateTokens(contentStr);
3565
+ }
3566
+ }
3567
+ }
3568
+ /**
3569
+ * Truncate history to fit context window
3570
+ * Preserves tool call chains: assistant(with tool_calls) → tool messages
3571
+ */
3572
+ truncate() {
3573
+ if (this.currentTokens <= this.contextWindowTokens) {
3574
+ return;
3575
+ }
3576
+ let systemMessageIndex = -1;
3577
+ for (let i2 = 0; i2 < this.messages.length; i2++) {
3578
+ const msg = this.messages[i2];
3579
+ if (msg instanceof Message && msg.role === "system" || msg.role === "system") {
3580
+ systemMessageIndex = i2;
3581
+ break;
3582
+ }
3583
+ }
3584
+ const systemMessage = systemMessageIndex >= 0 ? this.messages[systemMessageIndex] : null;
3585
+ const otherMessages = this.messages.filter((msg, index) => index !== systemMessageIndex);
3586
+ const toolCallDependencies = /* @__PURE__ */ new Map();
3587
+ for (let i2 = 0; i2 < otherMessages.length; i2++) {
3588
+ const msg = otherMessages[i2];
3589
+ const role = msg instanceof Message ? msg.role : msg.role;
3590
+ if (role === "assistant" && !(msg instanceof Message)) {
3591
+ const toolCalls = msg.tool_calls;
3592
+ if (toolCalls && Array.isArray(toolCalls)) {
3593
+ for (const tc of toolCalls) {
3594
+ if (tc.id) {
3595
+ toolCallDependencies.set(tc.id, i2);
3596
+ }
3597
+ }
3598
+ }
3599
+ }
3600
+ }
3601
+ const mustKeepIndices = /* @__PURE__ */ new Set();
3602
+ for (let i2 = 0; i2 < otherMessages.length; i2++) {
3603
+ const msg = otherMessages[i2];
3604
+ const role = msg instanceof Message ? msg.role : msg.role;
3605
+ if (role === "tool" && !(msg instanceof Message)) {
3606
+ const toolCallId = msg.tool_call_id;
3607
+ if (toolCallId) {
3608
+ const assistantIndex = toolCallDependencies.get(toolCallId);
3609
+ if (assistantIndex !== void 0) {
3610
+ mustKeepIndices.add(assistantIndex);
3611
+ mustKeepIndices.add(i2);
3612
+ }
3613
+ }
3614
+ }
3615
+ }
3616
+ let i = 0;
3617
+ while (this.currentTokens > this.contextWindowTokens && i < otherMessages.length) {
3618
+ if (mustKeepIndices.has(i)) {
3619
+ i++;
3620
+ continue;
3621
+ }
3622
+ const msg = otherMessages[i];
3623
+ const role = msg instanceof Message ? msg.role : msg.role;
3624
+ let hasDependentToolMessages = false;
3625
+ if (role === "assistant" && !(msg instanceof Message)) {
3626
+ const toolCalls = msg.tool_calls;
3627
+ if (toolCalls && Array.isArray(toolCalls)) {
3628
+ for (const tc of toolCalls) {
3629
+ if (tc.id) {
3630
+ for (let j = i + 1; j < otherMessages.length; j++) {
3631
+ const laterMsg = otherMessages[j];
3632
+ const laterRole = laterMsg instanceof Message ? laterMsg.role : laterMsg.role;
3633
+ if (laterRole === "tool" && !(laterMsg instanceof Message)) {
3634
+ const laterToolCallId = laterMsg.tool_call_id;
3635
+ if (laterToolCallId === tc.id) {
3636
+ hasDependentToolMessages = true;
3637
+ break;
3638
+ }
3639
+ }
3640
+ }
3641
+ }
3642
+ }
3643
+ }
3644
+ }
3645
+ if (hasDependentToolMessages) {
3646
+ i++;
3647
+ continue;
3648
+ }
3649
+ const removed = otherMessages.splice(i, 1)[0];
3650
+ if (removed) {
3651
+ let contentStr = "";
3652
+ if (removed instanceof Message) {
3653
+ contentStr = removed.content;
3654
+ } else {
3655
+ contentStr = removed.content || JSON.stringify(removed);
3656
+ }
3657
+ this.currentTokens -= this.estimateTokens(contentStr);
3658
+ const newMustKeepIndices = /* @__PURE__ */ new Set();
3659
+ for (const idx of mustKeepIndices) {
3660
+ if (idx > i) {
3661
+ newMustKeepIndices.add(idx - 1);
3662
+ } else if (idx < i) {
3663
+ newMustKeepIndices.add(idx);
3664
+ }
3665
+ }
3666
+ mustKeepIndices.clear();
3667
+ for (const idx of newMustKeepIndices) {
3668
+ mustKeepIndices.add(idx);
3669
+ }
3670
+ }
3671
+ }
3672
+ this.messages = [];
3673
+ if (systemMessage) {
3674
+ this.messages.push(systemMessage);
3675
+ }
3676
+ this.messages.push(...otherMessages);
3677
+ }
3678
+ /**
3679
+ * Clear all messages except system
3680
+ */
3681
+ clear() {
3682
+ let systemMessage;
3683
+ for (const msg of this.messages) {
3684
+ if (msg instanceof Message && msg.role === "system" || msg.role === "system") {
3685
+ systemMessage = msg;
3686
+ break;
3687
+ }
3688
+ }
3689
+ this.messages = systemMessage ? [systemMessage] : [];
3690
+ if (systemMessage) {
3691
+ if (systemMessage instanceof Message) {
3692
+ this.currentTokens = this.estimateTokens(systemMessage.content);
3693
+ } else {
3694
+ this.currentTokens = this.estimateTokens(systemMessage.content || JSON.stringify(systemMessage));
3695
+ }
3696
+ } else {
3697
+ this.currentTokens = 0;
3698
+ }
3699
+ }
3700
+ /**
3701
+ * Get the last message
3702
+ */
3703
+ getLastMessage() {
3704
+ return this.messages.length > 0 ? this.messages[this.messages.length - 1] : null;
3705
+ }
3706
+ /**
3707
+ * Get message count
3708
+ */
3709
+ getMessageCount() {
3710
+ return this.messages.length;
3711
+ }
3712
+ /**
3713
+ * Get formatted context usage information
3714
+ */
3715
+ get formattedContextUsage() {
3716
+ const usagePercent = this.currentTokens / this.contextWindowTokens * 100;
3717
+ return `Tokens: ${this.currentTokens}/${this.contextWindowTokens} (${usagePercent.toFixed(1)}%)`;
3718
+ }
3719
+ /**
3720
+ * Estimate tokens for text (simplified implementation)
3721
+ */
3722
+ estimateTokens(text) {
3723
+ if (!text) return 0;
3724
+ return Math.ceil(text.length / 4);
3725
+ }
3726
+ /**
3727
+ * Get conversation as string
3728
+ */
3729
+ toString() {
3730
+ return this.messages.map((msg) => {
3731
+ if (msg instanceof Message) {
3732
+ return msg.toString();
3733
+ }
3734
+ return JSON.stringify(msg);
3735
+ }).join("\n");
3736
+ }
3737
+ };
3738
+
3739
+ // src/tools/toolcallManager.ts
3740
+ import { randomUUID as randomUUID2 } from "crypto";
3741
+ var ToolcallManager = class {
3742
+ poolSize;
3743
+ semaphore;
3744
+ tasks = /* @__PURE__ */ new Set();
3745
+ todo = /* @__PURE__ */ new Map();
3746
+ done = /* @__PURE__ */ new Map();
3747
+ failed = /* @__PURE__ */ new Map();
3748
+ toolStores;
3749
+ executedResults = [];
3750
+ // Background process management
3751
+ backgroundProcesses = /* @__PURE__ */ new Map();
3752
+ monitorTasks = /* @__PURE__ */ new Map();
3753
+ constructor(poolSize = 5, toolStore = []) {
3754
+ this.poolSize = poolSize;
3755
+ this.semaphore = { available: poolSize };
3756
+ this.toolStores = toolStore;
3757
+ }
3758
+ /**
3759
+ * Get executed results
3760
+ */
3761
+ getExecutedResults() {
3762
+ return Array.from(this.done.values()).concat(Array.from(this.failed.values()));
3763
+ }
3764
+ /**
3765
+ * Clear executed results
3766
+ */
3767
+ clear() {
3768
+ this.todo.clear();
3769
+ this.done.clear();
3770
+ this.failed.clear();
3771
+ this.executedResults = [];
3772
+ }
3773
+ /**
3774
+ * Add tool calls to be executed
3775
+ */
3776
+ addToolcall(toolCall) {
3777
+ if (Array.isArray(toolCall)) {
3778
+ toolCall.forEach((tc) => {
3779
+ this.todo.set(tc.toolCallId, tc);
3780
+ });
3781
+ logger.debug(`ToolcallManager: Added ${toolCall.length} toolcalls`);
3782
+ } else {
3783
+ this.todo.set(toolCall.toolCallId, toolCall);
3784
+ logger.debug(`ToolcallManager: Added toolcall: ${toolCall.name}`);
3785
+ }
3786
+ }
3787
+ /**
3788
+ * Execute single task with pool control
3789
+ */
3790
+ async executeWithPool(toolcall) {
3791
+ if (!toolcall || !toolcall.name) {
3792
+ return;
3793
+ }
3794
+ if (!toolcall.isExtractedSuccess && toolcall.type === "user") {
3795
+ this.failed.set(toolcall.toolCallId, toolcall);
3796
+ return;
3797
+ }
3798
+ while (this.semaphore.available <= 0) {
3799
+ await new Promise((resolve2) => setTimeout(resolve2, 100));
3800
+ }
3801
+ this.semaphore.available--;
3802
+ try {
3803
+ toolcall.executedState = "running";
3804
+ let toolcallInputStr = JSON.stringify(toolcall.input);
3805
+ if (toolcallInputStr.length > 200) {
3806
+ toolcallInputStr = toolcallInputStr.substring(0, 100) + " ...(truncated by 100 characters)";
3807
+ }
3808
+ const toolcallDescription = `${toolcall.name}(${toolcallInputStr})`;
3809
+ logger.debug(`\u5F00\u59CB\u6267\u884C\u4EFB\u52A1: ${toolcallDescription}`);
3810
+ const result = await runWithManager(this, () => executeSingleTool(toolcall, this.toolStores));
3811
+ const obs = result.executedResult();
3812
+ if (typeof obs === "object" && "content" in obs) {
3813
+ logger.debug(`Observation of ${toolcall.name}, tool_call_id: ${toolcall.toolCallId}:
3814
+ ${obs.content}`);
3815
+ } else {
3816
+ logger.debug(`Observation of ${toolcall.name}:
3817
+ ${obs}`);
3818
+ }
3819
+ if (result.executedState === "success") {
3820
+ logger.debug(`\u4EFB\u52A1\u6267\u884C\u6210\u529F: ${toolcallDescription}`);
3821
+ this.done.set(toolcall.toolCallId, result);
3822
+ } else if (result.executedState === "failed") {
3823
+ logger.error(`\u4EFB\u52A1\u6267\u884C\u5931\u8D25: ${toolcallDescription}, \u9519\u8BEF: ${result.executedContent || "Unknown error"}`);
3824
+ this.failed.set(toolcall.toolCallId, result);
3825
+ } else if (result.executedState === "running") {
3826
+ logger.warn(`\u4EFB\u52A1\u6267\u884C\u4E2D: ${toolcallDescription}`);
3827
+ } else {
3828
+ logger.warn(`\u4EFB\u52A1\u6267\u884C\u72B6\u6001\u672A\u77E5: ${toolcallDescription}`);
3829
+ }
3830
+ const [backgroundProcessStatus, backgroundResult] = this.listBackgroundProcesses();
3831
+ if (backgroundProcessStatus === "running" /* RUNNING */) {
3832
+ if (typeof obs === "object" && "content" in obs) {
3833
+ const newObs = { ...obs };
3834
+ if (typeof backgroundResult === "string") {
3835
+ newObs.content = `${newObs.content}
3836
+
3837
+ ${backgroundResult}`;
3838
+ } else if (typeof backgroundResult === "object") {
3839
+ newObs.content = `${newObs.content}
3840
+
3841
+ background process observation: ${backgroundResult.content}`;
3842
+ }
3843
+ this.executedResults.push(newObs);
3844
+ } else if (typeof obs === "string") {
3845
+ if (typeof backgroundResult === "string") {
3846
+ this.executedResults.push(obs + "\n\n" + backgroundResult);
3847
+ } else {
3848
+ this.executedResults.push(obs + "\n\nbackground process observation: " + backgroundResult.content);
3849
+ }
3850
+ } else {
3851
+ this.executedResults.push(obs);
3852
+ }
3853
+ } else {
3854
+ this.executedResults.push(obs);
3855
+ }
3856
+ } catch (error) {
3857
+ logger.error(`\u4EFB\u52A1\u6267\u884C\u5F02\u5E38: ${toolcall.name}, \u9519\u8BEF: ${error}`);
3858
+ toolcall.executedState = "failed";
3859
+ toolcall.executedContent = String(error);
3860
+ this.failed.set(toolcall.toolCallId, toolcall);
3861
+ this.executedResults.push(toolcall.executedResult());
3862
+ } finally {
3863
+ this.semaphore.available++;
3864
+ }
3865
+ }
3866
+ /**
3867
+ * Execute all pending tasks (background execution, returns immediately)
3868
+ */
3869
+ async execute() {
3870
+ const executionPromises = [];
3871
+ for (const [toolcallId, toolcall] of this.todo) {
3872
+ this.todo.delete(toolcallId);
3873
+ const executionPromise = this.executeWithPool(toolcall);
3874
+ this.tasks.add(executionPromise);
3875
+ executionPromise.finally(() => {
3876
+ this.tasks.delete(executionPromise);
3877
+ });
3878
+ executionPromises.push(executionPromise);
3879
+ }
3880
+ await Promise.all(executionPromises);
3881
+ return this.executedResults;
3882
+ }
3883
+ /**
3884
+ * Observe execution results
3885
+ */
3886
+ async observe(waitAll = false, timeout = null) {
3887
+ await this.execute();
3888
+ if (this.tasks.size > 0 && !waitAll) {
3889
+ await new Promise((resolve2) => setTimeout(resolve2, 1e3));
3890
+ }
3891
+ if (waitAll && this.tasks.size > 0) {
3892
+ if (timeout) {
3893
+ try {
3894
+ await Promise.race([
3895
+ Promise.all(Array.from(this.tasks)),
3896
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${timeout}ms`)), timeout * 1e3))
3897
+ ]);
3898
+ } catch (error) {
3899
+ logger.warn(`\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210\u8D85\u65F6 (${timeout}\u79D2)\uFF0C\u5F53\u524D\u8FD8\u6709 ${this.tasks.size} \u4E2A\u4EFB\u52A1\u5728\u8FD0\u884C`);
3900
+ }
3901
+ } else {
3902
+ await Promise.all(Array.from(this.tasks));
3903
+ }
3904
+ }
3905
+ if (this.executedResults.length === 0) {
3906
+ return "";
3907
+ }
3908
+ const results = [...this.executedResults];
3909
+ this.clear();
3910
+ return results;
3911
+ }
3912
+ /**
3913
+ * Wait for all tasks to complete
3914
+ */
3915
+ async waitAll() {
3916
+ if (this.tasks.size > 0) {
3917
+ await Promise.all(Array.from(this.tasks));
3918
+ logger.info("\u6240\u6709\u4EFB\u52A1\u5DF2\u5B8C\u6210");
3919
+ }
3920
+ }
3921
+ /**
3922
+ * Get current status
3923
+ */
3924
+ getStatus() {
3925
+ return {
3926
+ pool_size: this.poolSize,
3927
+ running_tasks: this.tasks.size,
3928
+ pending: this.todo.size,
3929
+ done: this.done.size,
3930
+ failed: this.failed.size,
3931
+ background_processes: this.backgroundProcesses.size,
3932
+ monitor_tasks: this.monitorTasks.size
3933
+ };
3934
+ }
3935
+ /**
3936
+ * Get pending tool call count
3937
+ */
3938
+ getPendingCount() {
3939
+ return this.todo.size;
3940
+ }
3941
+ // Background process management methods
3942
+ /**
3943
+ * Register a background process
3944
+ */
3945
+ registerBackgroundProcess(process2, command, cwd) {
3946
+ const processId = randomUUID2();
3947
+ this.backgroundProcesses.set(processId, {
3948
+ process: process2,
3949
+ command,
3950
+ pid: process2.pid,
3951
+ cwd
3952
+ });
3953
+ const monitorTask = this.monitorProcess(processId, process2);
3954
+ this.monitorTasks.set(processId, monitorTask);
3955
+ logger.info(`\u6CE8\u518C\u540E\u53F0\u8FDB\u7A0B: ${command} (PID: ${process2.pid}, ID: ${processId})`);
3956
+ return processId;
3957
+ }
3958
+ /**
3959
+ * Monitor process until it ends
3960
+ */
3961
+ async monitorProcess(processId, process2) {
3962
+ try {
3963
+ await new Promise((resolve2, reject) => {
3964
+ process2.on("exit", (code) => {
3965
+ if (this.backgroundProcesses.has(processId)) {
3966
+ const command = this.backgroundProcesses.get(processId).command;
3967
+ this.backgroundProcesses.delete(processId);
3968
+ logger.info(`\u540E\u53F0\u8FDB\u7A0B\u5DF2\u7ED3\u675F: ${command} (PID: ${process2.pid}, \u8FD4\u56DE\u7801: ${code})`);
3969
+ }
3970
+ if (this.monitorTasks.has(processId)) {
3971
+ this.monitorTasks.delete(processId);
3972
+ }
3973
+ resolve2();
3974
+ });
3975
+ process2.on("error", (error) => {
3976
+ reject(error);
3977
+ });
3978
+ });
3979
+ } catch (error) {
3980
+ logger.error(`\u76D1\u63A7\u8FDB\u7A0B ${processId} \u65F6\u53D1\u751F\u9519\u8BEF: ${error}`);
3981
+ if (this.monitorTasks.has(processId)) {
3982
+ this.monitorTasks.delete(processId);
3983
+ }
3984
+ }
3985
+ }
3986
+ /**
3987
+ * Observe process stdout and stderr
3988
+ */
3989
+ async observeProcess(processId, timeout = 5) {
3990
+ if (!this.backgroundProcesses.has(processId)) {
3991
+ return `\u672A\u627E\u5230\u8FDB\u7A0BID: ${processId}`;
3992
+ }
3993
+ const info = this.backgroundProcesses.get(processId);
3994
+ const process2 = info.process;
3995
+ return `\u8FDB\u7A0BID: ${processId}
3996
+ \u547D\u4EE4: ${info.command}
3997
+ PID: ${info.pid}`;
3998
+ }
3999
+ /**
4000
+ * Stop specified background process
4001
+ */
4002
+ async stopBackgroundProcess(processId, force = false) {
4003
+ if (!this.backgroundProcesses.has(processId)) {
4004
+ return `\u672A\u627E\u5230\u8FDB\u7A0BID: ${processId}`;
4005
+ }
4006
+ try {
4007
+ const info = this.backgroundProcesses.get(processId);
4008
+ if (!info) {
4009
+ return `\u8FDB\u7A0BID ${processId} \u5DF2\u88AB\u79FB\u9664`;
4010
+ }
4011
+ const process2 = info.process;
4012
+ const command = info.command;
4013
+ if (process2.exitCode !== null) {
4014
+ return `\u8FDB\u7A0B\u5DF2\u7ECF\u7ED3\u675F (\u8FD4\u56DE\u7801: ${process2.exitCode})
4015
+ \u547D\u4EE4: ${command}`;
4016
+ }
4017
+ if (force) {
4018
+ process2.kill("SIGKILL");
4019
+ logger.info(`\u5F3A\u5236\u6740\u6B7B\u540E\u53F0\u8FDB\u7A0B: ${command} (PID: ${process2.pid})`);
4020
+ } else {
4021
+ process2.kill("SIGTERM");
4022
+ logger.info(`\u7EC8\u6B62\u540E\u53F0\u8FDB\u7A0B: ${command} (PID: ${process2.pid})`);
4023
+ }
4024
+ try {
4025
+ await new Promise((resolve2) => {
4026
+ const timeoutId = setTimeout(() => {
4027
+ if (!force) {
4028
+ process2.kill("SIGKILL");
4029
+ logger.warn(`\u540E\u53F0\u8FDB\u7A0B\u672A\u54CD\u5E94\u7EC8\u6B62\u4FE1\u53F7\uFF0C\u5DF2\u5F3A\u5236\u6740\u6B7B: ${command}`);
4030
+ }
4031
+ resolve2();
4032
+ }, 5e3);
4033
+ process2.on("exit", () => {
4034
+ clearTimeout(timeoutId);
4035
+ resolve2();
4036
+ });
4037
+ });
4038
+ } catch (error) {
4039
+ logger.error(`\u7B49\u5F85\u8FDB\u7A0B\u7ED3\u675F\u5931\u8D25: ${error}`);
4040
+ }
4041
+ if (this.monitorTasks.has(processId)) {
4042
+ const task = this.monitorTasks.get(processId);
4043
+ if (task) {
4044
+ this.monitorTasks.delete(processId);
4045
+ }
4046
+ }
4047
+ this.backgroundProcesses.delete(processId);
4048
+ return `\u540E\u53F0\u8FDB\u7A0B\u5DF2\u505C\u6B62
4049
+ \u8FDB\u7A0BID: ${processId}
4050
+ \u547D\u4EE4: ${command}
4051
+ \u8FD4\u56DE\u7801: ${process2.exitCode}`;
4052
+ } catch (error) {
4053
+ logger.error(`\u505C\u6B62\u540E\u53F0\u8FDB\u7A0B ${processId} \u65F6\u53D1\u751F\u9519\u8BEF: ${error}`);
4054
+ throw error;
4055
+ }
4056
+ }
4057
+ /**
4058
+ * Clean up all background processes
4059
+ */
4060
+ async cleanupBackgroundProcesses() {
4061
+ if (this.backgroundProcesses.size === 0) {
4062
+ return "\u6CA1\u6709\u9700\u8981\u6E05\u7406\u7684\u540E\u53F0\u8FDB\u7A0B";
4063
+ }
4064
+ const count = this.backgroundProcesses.size;
4065
+ const processIds = Array.from(this.backgroundProcesses.keys());
4066
+ const results = [];
4067
+ for (const processId of processIds) {
4068
+ try {
4069
+ const result = await this.stopBackgroundProcess(processId);
4070
+ results.push(result);
4071
+ } catch (error) {
4072
+ logger.error(`\u6E05\u7406\u540E\u53F0\u8FDB\u7A0B ${processId} \u65F6\u53D1\u751F\u9519\u8BEF: ${error}`);
4073
+ results.push(`\u6E05\u7406\u8FDB\u7A0B ${processId} \u5931\u8D25: ${error}`);
4074
+ }
4075
+ }
4076
+ return `\u5DF2\u6E05\u7406 ${count} \u4E2A\u540E\u53F0\u8FDB\u7A0B:
4077
+ ` + results.join("\n---\n");
4078
+ }
4079
+ /**
4080
+ * List all background processes
4081
+ */
4082
+ listBackgroundProcesses() {
4083
+ if (this.backgroundProcesses.size === 0) {
4084
+ return ["idle" /* IDLE */, "\u5F53\u524D\u6CA1\u6709\u8FD0\u884C\u7684\u540E\u53F0\u8FDB\u7A0B\u3002"];
4085
+ }
4086
+ const finishedIds = [];
4087
+ for (const [processId, info] of this.backgroundProcesses) {
4088
+ if (info.process.exitCode !== null) {
4089
+ finishedIds.push(processId);
4090
+ }
4091
+ }
4092
+ for (const processId of finishedIds) {
4093
+ this.backgroundProcesses.delete(processId);
4094
+ }
4095
+ if (this.backgroundProcesses.size === 0) {
4096
+ return ["idle" /* IDLE */, "\u5F53\u524D\u6CA1\u6709\u8FD0\u884C\u7684\u540E\u53F0\u8FDB\u7A0B\u3002"];
4097
+ }
4098
+ const result = `\u5F53\u524D\u6709 ${this.backgroundProcesses.size} \u4E2A\u540E\u53F0\u8FDB\u7A0B:
4099
+ ` + Array.from(this.backgroundProcesses.values()).map((process2) => `PID: ${process2.pid}, Command: ${process2.command}
4100
+ `).join("");
4101
+ return ["running" /* RUNNING */, result];
4102
+ }
4103
+ /**
4104
+ * Async context manager entry
4105
+ */
4106
+ async enter() {
4107
+ return this;
4108
+ }
4109
+ /**
4110
+ * Async context manager exit, clean up all resources
4111
+ */
4112
+ async exit() {
4113
+ await this.cleanupBackgroundProcesses();
4114
+ await this.waitAll();
4115
+ }
4116
+ };
4117
+
4118
+ // src/prompts/tools.ts
4119
+ var OUTPUT_FORMAT_PROMPT = `<System Tools OutputFormat>
4120
+
4121
+ We have three types of tasks: Generative Tasks, Analytical Tasks, and Operational Tasks.
4122
+ You should choose the appropriate task type based on the task description.
4123
+
4124
+ #### Generative Tasks Output Format
4125
+ <Generative Tasks Purpose>Create Something New</Generative Tasks Purpose>
4126
+
4127
+ <Generative Tasks Definition>
4128
+ These tasks focus on creating new artifacts from scratch, such as text, code, designs, or configurations.
4129
+ The model synthesizes information and produces original outputs.
4130
+ </Generative Tasks Definition>
4131
+
4132
+ <Generative Tasks Output Format>
4133
+ Output a sequence of tool calls in the format below. Replace <ToolName.method_name> and <args_name> with actual tool and parameter names.
4134
+
4135
+ You may interleave tool calls with reasoning or explanations as needed:
4136
+
4137
+ [Your reasoning or explanation here...]
4138
+ <ToolName.method_name><args_name1>args_value1</args_name1><args_name2>args_value2</args_name2>...</ToolName.method_name>
4139
+
4140
+ [Additional thoughts or context...]
4141
+ <ToolName2.method_name2><args_name1>args_value1</args_name1><args_name2>args_value2</args_name2>...</ToolName2.method_name2>
4142
+ ...
4143
+ </Generative Tasks Output Format>
4144
+
4145
+
4146
+ ### Analytical Tasks Output Format
4147
+ <Analytical Tasks Purpose>Understand, Diagnose & Evaluate Existing Information</Analytical Tasks Purpose>
4148
+
4149
+ <Analytical Tasks Definition>
4150
+ Analytical tasks focus on understanding, decomposing, diagnosing, and evaluating existing information.
4151
+ They include requirement analysis, code and system comprehension, quality evaluation, debugging and root-cause analysis, and data or behavioral analysis.
4152
+ Such tasks produce structured insights and decisions that guide subsequent generative or operational steps.
4153
+ </Analytical Tasks Definition>
4154
+
4155
+ <Analytical Tasks Output Format>
4156
+ You should fellow the format below, replace the <ToolName.method_name> and <args_name> with the actual name.
4157
+
4158
+ Thoughts: ...
4159
+ ToolCall: <ToolName.method_name><args_name1>args_value1</args_name1><args_name2>args_value2</args_name2>...</ToolName.method_name>
4160
+ // stop ToolCall here, and wait for the Observation of the ToolCall.
4161
+
4162
+ </Analytical Tasks Output Format>
4163
+
4164
+ ### Operational Tasks Output Format
4165
+
4166
+ <Operational Tasks Purpose>Act & Operate Tools</Operational Tasks Purpose>
4167
+
4168
+ <Operational Tasks Definition>
4169
+ These tasks involve performing concrete actions through tools, systems, or commands.
4170
+ The focus is on executing operations rather than generating or analyzing content.
4171
+ </Operational Tasks Definition>
4172
+
4173
+ <Operational Tasks Output Format>
4174
+ You should follow the format below, replace the <ToolName.method_name> and <args_name> with the actual name.
4175
+
4176
+ <ToolName.method_name><args_name1>args_value1</args_name1><args_name2>args_value2</args_name2>...</ToolName.method_name>
4177
+ </Operational Tasks Output Format>
4178
+
4179
+ **YOUR OUTPUT MUST INCLUDE THE ACTUAL <args_name> AND <args_value>!!!**
4180
+ **If the task is completed, simply return the completion information like <TaskCompletion>your_completion_information</TaskCompletion>, No any tool call should be included.**
4181
+ </System Tools OutputFormat>
4182
+ `;
4183
+ var SYSTEM_TOOLS_PROMPT = `
4184
+ ## System Tools And System Tools Call Format
4185
+
4186
+ System Tools are represented by a predefined XML-like syntax structure. This structure encapsulates parameter lists within tags such as \`<ToolName.method_name>\`.
4187
+ By identifying and matching keywords inside these tags, the system automatically parses the target tool name and its corresponding input parameter values to execute subsequent tool calls.
4188
+
4189
+ ### Available System Tools
4190
+ {availableSystemTools}
4191
+
4192
+ ### Description of Available System Tools
4193
+ {descOfSystemTools}
4194
+
4195
+ ### System Tools Output Format
4196
+ {outputFormat}
4197
+ `;
4198
+
4199
+ // src/agent.ts
4200
+ var Agent = class {
4201
+ name;
4202
+ profile;
4203
+ system;
4204
+ tools;
4205
+ functionCallingTools = [];
4206
+ mcpServerNames;
4207
+ modelConfig;
4208
+ verbose;
4209
+ model;
4210
+ history;
4211
+ subAgents = [];
4212
+ toolcallManagerPoolSize;
4213
+ postProcessor;
4214
+ useFunctionCalling;
4215
+ constructor(config2) {
4216
+ const {
4217
+ name,
4218
+ profile,
4219
+ system,
4220
+ tools: tools2 = [],
4221
+ subAgents = [],
4222
+ mcpServerNames = [],
4223
+ modelConfig,
4224
+ verbose = false,
4225
+ useFunctionCalling = false,
4226
+ postProcessor = null,
4227
+ toolcallManagerPoolSize = 5
4228
+ } = config2;
4229
+ this.name = name;
4230
+ this.profile = profile;
4231
+ this.verbose = verbose;
4232
+ this.modelConfig = modelConfig || "deepseek";
4233
+ this.subAgents = subAgents || [];
4234
+ this.postProcessor = postProcessor;
4235
+ this.useFunctionCalling = useFunctionCalling;
4236
+ const agentToolNames = registerAgentAsTool(this.subAgents, Boolean(this.verbose));
4237
+ this.tools = [...tools2, ...agentToolNames];
4238
+ this.mcpServerNames = mcpServerNames;
4239
+ const systemPrompt = system || profile || "";
4240
+ this.system = this.tools.length > 0 ? this.setSystem(systemPrompt, this.tools) : systemPrompt;
4241
+ this.model = new Model(this.modelConfig);
4242
+ const modelNameForHistory = typeof this.modelConfig === "string" ? this.modelConfig : this.modelConfig.model || "deepseek";
4243
+ this.history = new MessageHistory(modelNameForHistory, this.system, this.model.getConfig().contextWindowTokens);
4244
+ if (this.useFunctionCalling) {
4245
+ this.functionCallingTools = this.setFunctionCallingTools(this.tools);
4246
+ }
4247
+ if (this.verbose) {
4248
+ logger.info(`
4249
+ ========== [${this.name}] System Prompt ==========`);
4250
+ logger.info(this.system);
4251
+ logger.info(`========================================
4252
+ `);
4253
+ if (typeof this.verbose === "number" && this.verbose > 1) {
4254
+ logger.info(`[${this.name}] Tools: ${this.tools.join(", ")}`);
4255
+ logger.info("");
4256
+ }
4257
+ }
4258
+ this.toolcallManagerPoolSize = toolcallManagerPoolSize;
4259
+ }
4260
+ /**
4261
+ * Get the current system prompt
4262
+ */
4263
+ get systemPrompt() {
4264
+ return this.system;
4265
+ }
4266
+ /**
4267
+ * Set the system prompt and update history
4268
+ */
4269
+ set systemPrompt(value) {
4270
+ this.system = value;
4271
+ if (this.history) {
4272
+ this.history.updateSystem(value);
4273
+ }
4274
+ }
4275
+ /**
4276
+ * Set the system prompt with system tools descriptions
4277
+ * @private
4278
+ */
4279
+ setSystem(system, systemTools) {
4280
+ let toolDescriptions = "";
4281
+ for (const tool of systemTools) {
4282
+ if (SystemToolStore.hasTool(tool)) {
4283
+ const toolDesc = SystemToolStore.getTool(tool);
4284
+ toolDescriptions += (toolDesc?.desc || "") + "\n\n";
4285
+ }
4286
+ }
4287
+ if (systemTools.length > 0) {
4288
+ const availableSystemTools = systemTools.map((t) => `- ${t}`).join("\n");
4289
+ return system + "\n" + SYSTEM_TOOLS_PROMPT.replace("{availableSystemTools}", availableSystemTools).replace("{descOfSystemTools}", toolDescriptions).replace("{outputFormat}", OUTPUT_FORMAT_PROMPT);
4290
+ }
4291
+ return system;
4292
+ }
4293
+ /**
4294
+ * Set up function calling tools for OpenAI-style function calling
4295
+ * @private
4296
+ */
4297
+ setFunctionCallingTools(tools2) {
4298
+ const openaiToolCalls = [];
4299
+ for (let tool of tools2) {
4300
+ tool = tool.replace(".", "-");
4301
+ if (!FunctionCallingStore.hasTool(tool)) {
4302
+ logger.warn(`Tool ${tool} not registered in FunctionCallingStore.`);
4303
+ } else {
4304
+ const toolSchema = FunctionCallingStore.getToolcallSchema(tool, "openai");
4305
+ if (toolSchema && Object.keys(toolSchema).length > 0) {
4306
+ openaiToolCalls.push(toolSchema);
4307
+ }
4308
+ }
4309
+ }
4310
+ return openaiToolCalls;
4311
+ }
4312
+ /**
4313
+ * Agent loop - processes user input and handles tool calls
4314
+ * @private
4315
+ */
4316
+ async _agentLoop(instruction, images) {
4317
+ const instructionMsg = Message.fromUserMsg(instruction, images);
4318
+ this.history.addMessage(instructionMsg);
4319
+ if (this.verbose) {
4320
+ logger.info(`
4321
+ [${this.name}] Received: ${instruction}`);
4322
+ }
4323
+ while (true) {
4324
+ this.history.truncate();
4325
+ if (typeof this.verbose === "number" && this.verbose > 2) {
4326
+ logger.debug(
4327
+ `History raw messages before extract toolcall messages:
4328
+ ${JSON.stringify(await this.history.formatForApi())}`
4329
+ );
4330
+ }
4331
+ const response = await this.model.achat(
4332
+ await this.history.formatForApi(),
4333
+ this.useFunctionCalling ? this.functionCallingTools : void 0
4334
+ );
4335
+ const systemToolcallResponses = response.filter((r) => r.type === "system").map((r) => r.extractedResult()).filter((r) => typeof r === "string");
4336
+ if (systemToolcallResponses.length > 0) {
4337
+ const systemToolcallResponse = systemToolcallResponses.join("\n");
4338
+ this.history.addMessage("assistant", systemToolcallResponse);
4339
+ }
4340
+ const userToolcallMessages = response.filter((r) => r.type === "user").map((r) => r.extractedResult());
4341
+ if (userToolcallMessages.length > 0) {
4342
+ const userToolcallMessagesFlattened = [];
4343
+ for (const item of userToolcallMessages) {
4344
+ if (Array.isArray(item)) {
4345
+ userToolcallMessagesFlattened.push(...item);
4346
+ } else {
4347
+ userToolcallMessagesFlattened.push(item);
4348
+ }
4349
+ }
4350
+ for (const toolcall of userToolcallMessagesFlattened) {
4351
+ this.history.addMessage(toolcall);
4352
+ }
4353
+ }
4354
+ if (typeof this.verbose === "number" && this.verbose > 1) {
4355
+ const messages = await this.history.formatForApi();
4356
+ const last3 = messages.slice(-3);
4357
+ logger.debug(`History raw messages after extract toolcall messages (last 3):
4358
+ ${JSON.stringify(last3)}`);
4359
+ }
4360
+ logger.debug(`History usage: ${this.history.formattedContextUsage}`);
4361
+ const toolcallManager = new ToolcallManager(this.toolcallManagerPoolSize, [SystemToolStore, FunctionCallingStore]);
4362
+ const allToolCalls = [];
4363
+ const systemToolMap = {};
4364
+ const systemToolNames = SystemToolStore.listTools();
4365
+ for (const name of systemToolNames) {
4366
+ const tool = SystemToolStore.getTool(name);
4367
+ if (tool) {
4368
+ systemToolMap[name] = tool;
4369
+ }
4370
+ }
4371
+ for (const r of response) {
4372
+ const result = r.extractedResult();
4373
+ if (typeof result === "string") {
4374
+ if (result.trim().length > 0) {
4375
+ const extracted = extractToolcallsFromStr(result, systemToolMap);
4376
+ allToolCalls.push(...extracted);
4377
+ }
4378
+ } else if (typeof result === "object" && result !== null) {
4379
+ if (!Array.isArray(result) && result.role === "assistant" && result.tool_calls && Array.isArray(result.tool_calls)) {
4380
+ for (const tc of result.tool_calls) {
4381
+ if (tc.type === "function" && tc.function) {
4382
+ let args = {};
4383
+ try {
4384
+ args = JSON.parse(tc.function.arguments);
4385
+ } catch (e) {
4386
+ logger.warn(`Failed to parse arguments for tool ${tc.function.name}: ${tc.function.arguments}`);
4387
+ args = { raw_args: tc.function.arguments };
4388
+ }
4389
+ allToolCalls.push(
4390
+ new Toolcall({
4391
+ name: tc.function.name,
4392
+ input: args,
4393
+ toolCallId: tc.id,
4394
+ type: "user",
4395
+ rawContentFromLlm: tc.function.arguments
4396
+ })
4397
+ );
4398
+ }
4399
+ }
4400
+ } else if (Array.isArray(result)) {
4401
+ for (const item of result) {
4402
+ if (item.type === "function" && item.function) {
4403
+ let args = {};
4404
+ try {
4405
+ args = JSON.parse(item.function.arguments);
4406
+ } catch (e) {
4407
+ logger.warn(`Failed to parse arguments for tool ${item.function.name}: ${item.function.arguments}`);
4408
+ args = { raw_args: item.function.arguments };
4409
+ }
4410
+ allToolCalls.push(
4411
+ new Toolcall({
4412
+ name: item.function.name,
4413
+ input: args,
4414
+ toolCallId: item.id,
4415
+ type: "user",
4416
+ rawContentFromLlm: item.function.arguments
4417
+ })
4418
+ );
4419
+ } else if (item.type === "tool_use") {
4420
+ allToolCalls.push(
4421
+ new Toolcall({
4422
+ name: item.name,
4423
+ input: item.input,
4424
+ toolCallId: item.id,
4425
+ type: "user"
4426
+ })
4427
+ );
4428
+ }
4429
+ }
4430
+ }
4431
+ }
4432
+ }
4433
+ if (allToolCalls.length > 0) {
4434
+ toolcallManager.addToolcall(allToolCalls);
4435
+ const obs = await toolcallManager.observe(true, 60);
4436
+ if (Array.isArray(obs)) {
4437
+ for (const item of obs) {
4438
+ if (typeof item === "object") {
4439
+ this.history.addMessage(item);
4440
+ } else if (typeof item === "string") {
4441
+ this.history.addMessage("user", item);
4442
+ }
4443
+ }
4444
+ } else if (typeof obs === "string") {
4445
+ this.history.addMessage("user", obs);
4446
+ } else if (typeof obs === "object") {
4447
+ this.history.addMessage(obs);
4448
+ } else {
4449
+ logger.warn(`Unknown observation type: ${typeof obs}`);
4450
+ }
4451
+ } else {
4452
+ for (const r of response) {
4453
+ if (r.type === "system") {
4454
+ const result = r.extractedResult();
4455
+ if (typeof result === "string") {
4456
+ const cleanResult = result.replace(/<TaskCompletion>/g, "").replace(/<\/TaskCompletion>/g, "").trim();
4457
+ return cleanResult;
4458
+ }
4459
+ }
4460
+ }
4461
+ return "";
4462
+ }
4463
+ }
4464
+ }
4465
+ /**
4466
+ * Run the agent with given instruction
4467
+ */
4468
+ async run(instruction, images) {
4469
+ const stack = new AsyncExitStack();
4470
+ try {
4471
+ for (const serverName of this.mcpServerNames) {
4472
+ await FunctionCallingStore.addMcpTools?.(this.name, serverName, stack);
4473
+ const mcpTools = FunctionCallingStore.getMcpToolsSchemas?.(this.name, serverName, "openai") || [];
4474
+ if (this.verbose) {
4475
+ logger.info(`[${this.name}] Loaded MCP tools from ${serverName}: ${mcpTools.length} tools found.`);
4476
+ if (typeof this.verbose === "number" && this.verbose > 1) {
4477
+ logger.info(`[${this.name}] MCP tools sample: ${JSON.stringify(mcpTools).substring(0, 200)} ...`);
4478
+ }
4479
+ }
4480
+ if (this.useFunctionCalling) {
4481
+ this.functionCallingTools.push(...mcpTools);
4482
+ }
4483
+ }
4484
+ const responseText = await this._agentLoop(instruction, images);
4485
+ if (this.postProcessor) {
4486
+ try {
4487
+ return await this.postProcessor(responseText);
4488
+ } catch (error) {
4489
+ logger.error(`Post-processor error in agent ${this.name}:`, error);
4490
+ throw new Error(`Post-processor failed: ${error instanceof Error ? error.message : String(error)}`);
4491
+ }
4492
+ }
4493
+ return responseText;
4494
+ } catch (error) {
4495
+ logger.error(`Agent ${this.name} execution error:`);
4496
+ logger.error(error);
4497
+ if (error instanceof Error) {
4498
+ logger.error(`Error message: ${error.message}`);
4499
+ logger.error(`Error stack: ${error.stack}`);
4500
+ }
4501
+ throw error;
4502
+ } finally {
4503
+ await stack.close();
4504
+ }
4505
+ }
4506
+ /**
4507
+ * Get agent profile
4508
+ */
4509
+ getProfile() {
4510
+ return this.profile;
4511
+ }
4512
+ /**
4513
+ * Get tools
4514
+ */
4515
+ getTools() {
4516
+ return [...this.tools];
4517
+ }
4518
+ /**
4519
+ * Get function calling tools schemas
4520
+ */
4521
+ getFunctionCallingTools() {
4522
+ return [...this.functionCallingTools];
4523
+ }
4524
+ /**
4525
+ * Get MCP server names
4526
+ */
4527
+ getMcpServerNames() {
4528
+ return [...this.mcpServerNames];
4529
+ }
4530
+ /**
4531
+ * Get model config (string or ModelConfig object)
4532
+ */
4533
+ getModelConfig() {
4534
+ return this.modelConfig;
4535
+ }
4536
+ /**
4537
+ * Get model name (for backward compatibility)
4538
+ */
4539
+ getModelName() {
4540
+ if (typeof this.modelConfig === "string") {
4541
+ return this.modelConfig;
4542
+ }
4543
+ return this.modelConfig.model || "deepseek";
4544
+ }
4545
+ /**
4546
+ * Get verbose setting
4547
+ */
4548
+ getVerbose() {
4549
+ return this.verbose;
4550
+ }
4551
+ /**
4552
+ * Get sub-agents
4553
+ */
4554
+ getSubAgents() {
4555
+ return [...this.subAgents];
4556
+ }
4557
+ };
4558
+
4559
+ // src/environment/base.ts
4560
+ var BaseEnvironment = class {
4561
+ /**
4562
+ * List of agents in the environment
4563
+ */
4564
+ agents = [];
4565
+ /**
4566
+ * Assign skills to agent with their names
4567
+ */
4568
+ agentSkills = {};
4569
+ constructor(agents = [], agentSkills = {}) {
4570
+ this.agents = agents;
4571
+ this.agentSkills = agentSkills;
4572
+ this.setAgentSkills();
4573
+ }
4574
+ /**
4575
+ * Set agent skills after initialization
4576
+ */
4577
+ setAgentSkills() {
4578
+ if (this.agents.length === 0 || Object.keys(this.agentSkills).length === 0) {
4579
+ return;
4580
+ }
4581
+ const skiller = new SkillsTool(SKILLS_DIR);
4582
+ if ("all" in this.agentSkills) {
4583
+ for (const agent of this.agents) {
4584
+ this.agentSkills[agent.name] = this.agentSkills["all"];
4585
+ }
4586
+ delete this.agentSkills["all"];
4587
+ }
4588
+ logger.debug(`Assigning skills to agents: ${JSON.stringify(this.agentSkills)}`);
4589
+ for (const [agentName, skillNames] of Object.entries(this.agentSkills)) {
4590
+ for (const agent of this.agents) {
4591
+ if (agent.name === agentName) {
4592
+ const skillDescriptions = [];
4593
+ (async () => {
4594
+ for (const skillName of skillNames) {
4595
+ try {
4596
+ const skillDescription2 = await skiller.readSkillDescription(skillName);
4597
+ skillDescriptions.push(skillDescription2);
4598
+ } catch (error) {
4599
+ logger.warn(`Failed to read skill description for ${skillName}:`, error);
4600
+ }
4601
+ }
4602
+ const skillDescription = "\n--- <SKILLS START> ---\n" + skillDescriptions.join("\n-----\n") + "\n--- <SKILLS END> ---\n";
4603
+ agent.systemPrompt = agent.systemPrompt + skillDescription;
4604
+ })();
4605
+ }
4606
+ }
4607
+ }
4608
+ }
4609
+ /**
4610
+ * Check if instruction has agent name
4611
+ */
4612
+ hasAgentName(instruction) {
4613
+ if (!instruction.includes("@")) {
4614
+ return false;
4615
+ }
4616
+ for (const agent of this.agents) {
4617
+ if (instruction.includes(`@${agent.name}`)) {
4618
+ return true;
4619
+ }
4620
+ }
4621
+ return false;
4622
+ }
4623
+ /**
4624
+ * Post process instruction
4625
+ */
4626
+ postProcessInstruction(instruction, agentNames) {
4627
+ if (["/q", "exit", "quit"].includes(instruction.toLowerCase()) || agentNames.length === 0) {
4628
+ return ["quit" /* QUIT */, instruction];
4629
+ }
4630
+ if (agentNames.length === 1) {
4631
+ return ["valid" /* VALID */, `${instruction}@${agentNames[0]}`];
4632
+ }
4633
+ if (instruction.includes("@all")) {
4634
+ return ["sendToAll" /* SEND_TO_ALL */, instruction];
4635
+ }
4636
+ if (this.hasAgentName(instruction)) {
4637
+ return ["valid" /* VALID */, instruction];
4638
+ }
4639
+ return ["noAvailableAgentName" /* NO_AVAILABLE_AGENT_NAME */, instruction];
4640
+ }
4641
+ /**
4642
+ * Run with a single goal until completion (non-interactive mode)
4643
+ */
4644
+ async runGoal(goal) {
4645
+ if (this.agents.length === 0) {
4646
+ logger.error("No agents in the environment.");
4647
+ return;
4648
+ }
4649
+ const [instructionType, processedInstruction] = this.postProcessInstruction(
4650
+ goal,
4651
+ this.agents.map((agent) => agent.name)
4652
+ );
4653
+ if (instructionType === "quit" /* QUIT */) {
4654
+ logger.info("Invalid goal instruction.");
4655
+ return;
4656
+ }
4657
+ if (instructionType === "noAvailableAgentName" /* NO_AVAILABLE_AGENT_NAME */) {
4658
+ logger.warn("No available agent name in instruction. Please provide instruction with '@agent_name'.");
4659
+ return;
4660
+ }
4661
+ logger.info("Goal:", goal);
4662
+ logger.info("Processing goal...\n");
4663
+ for (const agent of this.agents) {
4664
+ if (instructionType === "sendToAll" /* SEND_TO_ALL */ || processedInstruction.includes(`@${agent.name}`)) {
4665
+ try {
4666
+ const response = await agent.run(processedInstruction);
4667
+ logger.info(`
4668
+ > Agent ${agent.name} completed the goal.`);
4669
+ logger.info(`Final response: ${response}`);
4670
+ } catch (error) {
4671
+ logger.error(`Error running agent ${agent.name}:`, error);
4672
+ }
4673
+ }
4674
+ }
4675
+ }
4676
+ /**
4677
+ * Run the environment (interactive mode)
4678
+ */
4679
+ async run() {
4680
+ const readline = await import("readline");
4681
+ const rl = readline.createInterface({
4682
+ input: process.stdin,
4683
+ output: process.stdout
4684
+ });
4685
+ const question = (prompt) => {
4686
+ return new Promise((resolve2) => {
4687
+ rl.question(prompt, resolve2);
4688
+ });
4689
+ };
4690
+ try {
4691
+ while (true) {
4692
+ try {
4693
+ let instruction;
4694
+ if (this.agents.length === 0) {
4695
+ logger.error("No agents in the environment.");
4696
+ break;
4697
+ } else if (this.agents.length === 1) {
4698
+ instruction = await question("Enter your instruction (or '/q' to quit): ");
4699
+ } else {
4700
+ const agentNames = this.agents.map((agent) => agent.name).join(", ");
4701
+ instruction = await question(
4702
+ `Enter your instruction with '@agent_name' (or '/q' to quit), available agents: ${agentNames}: `
4703
+ );
4704
+ }
4705
+ const [instructionType, processedInstruction] = this.postProcessInstruction(
4706
+ instruction,
4707
+ this.agents.map((agent) => agent.name)
4708
+ );
4709
+ if (instructionType === "quit" /* QUIT */) {
4710
+ logger.info("Quitting...");
4711
+ break;
4712
+ } else if (instructionType === "noAvailableAgentName" /* NO_AVAILABLE_AGENT_NAME */) {
4713
+ logger.warn("No available agent name in instruction. Please enter your instruction with '@agent_name'.");
4714
+ continue;
4715
+ }
4716
+ logger.info("Processing your request...");
4717
+ for (const agent of this.agents) {
4718
+ if (instructionType === "sendToAll" /* SEND_TO_ALL */ || processedInstruction.includes(`@${agent.name}`)) {
4719
+ const response = await agent.run(processedInstruction);
4720
+ logger.info(`Agent ${agent.name} response:`, response);
4721
+ }
4722
+ }
4723
+ } catch (error) {
4724
+ logger.error("Error processing instruction:", error);
4725
+ }
4726
+ }
4727
+ } finally {
4728
+ rl.close();
4729
+ }
4730
+ }
4731
+ };
4732
+
4733
+ // src/environment/coding.ts
4734
+ import * as fs8 from "fs";
4735
+ var CodingEnvironment = class extends BaseEnvironment {
4736
+ /**
4737
+ * Workspace directory
4738
+ */
4739
+ workspaceDir = "";
4740
+ constructor(agents = [], agentSkills = {}, workspaceDir = "") {
4741
+ super(agents, agentSkills);
4742
+ this.workspaceDir = workspaceDir;
4743
+ this.setWorkspaceDir();
4744
+ }
4745
+ /**
4746
+ * Set workspace directory after initialization
4747
+ */
4748
+ setWorkspaceDir() {
4749
+ if (!this.workspaceDir) {
4750
+ this.workspaceDir = WORKSPACE_DIR;
4751
+ }
4752
+ if (!fs8.existsSync(this.workspaceDir)) {
4753
+ fs8.mkdirSync(this.workspaceDir, { recursive: true });
4754
+ } else {
4755
+ logger.debug(`Workspace directory already exists: ${this.workspaceDir}`);
4756
+ }
4757
+ for (const agent of this.agents) {
4758
+ if (!agent.systemPrompt.includes(this.workspaceDir)) {
4759
+ agent.systemPrompt = agent.systemPrompt + `
4760
+
4761
+ Your workspace directory is: <workspace>${this.workspaceDir}</workspace>
4762
+
4763
+ **Note**: your any output files must be saved in ${this.workspaceDir}`;
4764
+ }
4765
+ }
4766
+ logger.debug(`Setting workspace directory: ${this.workspaceDir}`);
4767
+ for (const agent of this.agents) {
4768
+ logger.debug(`Agent ${agent.name} system: ${agent.systemPrompt}`);
4769
+ }
4770
+ }
4771
+ };
4772
+ export {
4773
+ Agent,
4774
+ ApiTool,
4775
+ BaseEnvironment,
4776
+ CodingEnvironment,
4777
+ CommandLineTool,
4778
+ DEFAULT_CONFIG,
4779
+ DEFAULT_SETTINGS,
4780
+ ENV_VARS,
4781
+ ERROR_MESSAGES,
4782
+ EvoltError,
4783
+ ExtendStateMachineTool,
4784
+ FileEditor,
4785
+ FunctionCallingStore,
4786
+ GitTool,
4787
+ LOG_LEVELS,
4788
+ MESSAGE_ROLES,
4789
+ Message,
4790
+ MessageHistory,
4791
+ Model,
4792
+ ModelError,
4793
+ ReflectTool,
4794
+ Reply2HumanTool,
4795
+ SKILLS_DIR,
4796
+ SkillsTool,
4797
+ SystemToolStore,
4798
+ TOOL_CALL_TYPES,
4799
+ TOOL_CONSTANTS,
4800
+ ThinkTool,
4801
+ TodoListTool,
4802
+ ToolExecutionError,
4803
+ Toolcall,
4804
+ UserToolStore,
4805
+ WORKSPACE_DIR,
4806
+ WriteUIDesignDocument,
4807
+ ensureDir,
4808
+ fileExists,
4809
+ getCacheDir,
4810
+ getConfigDir,
4811
+ getConfigPath2 as getConfigPath,
4812
+ getFileExtension,
4813
+ getLogsDir,
4814
+ getSettings,
4815
+ getSkillsDir,
4816
+ getTempFilePath,
4817
+ getWorkspaceDir,
4818
+ getWorkspacePath,
4819
+ initializeSettings,
4820
+ isInWorkspace,
4821
+ loadModelConfig,
4822
+ logger_default as logger,
4823
+ normalizePath,
4824
+ registerAgentAsTool,
4825
+ settings,
4826
+ tools,
4827
+ updateSettings
4828
+ };
4829
+ //# sourceMappingURL=index.js.map