inspiration-agent 0.0.1

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.
@@ -0,0 +1,712 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const os = require("os");
4
+ const logger = require("../utils/logger");
5
+
6
+ const DeepSeekService = require("../model/deepseek.service");
7
+ const KimiService = require("../model/kimi.service");
8
+ const ZhipuService = require("../model/zhipu.service");
9
+ const MiniMaxService = require("../model/minimax.service");
10
+ const FileTools = require("../tools/file.tools");
11
+ const CommandTools = require("../tools/command.tools");
12
+ const SearchTools = require("../tools/search.tools");
13
+ const BrowserTools = require("../tools/browser.tools");
14
+ const SchedulerTools = require("../tools/scheduler.tools");
15
+ const MemoryTools = require("../tools/memory.tools");
16
+ const DatabaseService = require("../services/database.service");
17
+ const MemoryManager = require("../services/memory.manager");
18
+ const MessageQueue = require("../services/message.queue");
19
+ const TerminalMarkdownRenderer = require("../utils/markdown-renderer");
20
+
21
+ const SUPPORTED_LLM_PROVIDERS = {
22
+ deepseek: DeepSeekService,
23
+ kimi: KimiService,
24
+ zhipu: ZhipuService,
25
+ minimax: MiniMaxService,
26
+ };
27
+
28
+ /**
29
+ * AI 智能体类
30
+ * 负责处理用户消息,调用工具,并管理记忆
31
+ */
32
+ class AIAgent {
33
+ constructor() {
34
+ this.llm = this.createLLMService();
35
+ this.fileTools = new FileTools();
36
+ this.commandTools = new CommandTools();
37
+ this.searchTools = new SearchTools();
38
+ this.browserTools = new BrowserTools();
39
+ this.dbService = new DatabaseService();
40
+ this.schedulerTools = new SchedulerTools(this.dbService, (prompt) =>
41
+ this.executeScheduledPrompt(prompt)
42
+ );
43
+ this.memoryManager = new MemoryManager(this.dbService, 20);
44
+ this.memoryTools = new MemoryTools(this.memoryManager);
45
+ this.messageQueue = new MessageQueue();
46
+ this.systemPrompt = this.loadSystemPrompt();
47
+ this.enableStream = process.env.ENABLE_STREAM !== "false";
48
+ this.markdownRenderer = new TerminalMarkdownRenderer();
49
+ this.startTime = Date.now();
50
+ this.shouldShutdown = false;
51
+
52
+ this.llm.setTokenUsageCallback((inputTokens, outputTokens) => {
53
+ this.recordTokenUsage(inputTokens, outputTokens);
54
+ });
55
+
56
+ this.setupMessageQueue();
57
+ this.registerToolHandlers();
58
+ }
59
+
60
+ createLLMService() {
61
+ const provider = (process.env.LLM_PROVIDER || "deepseek").toLowerCase();
62
+ const ServiceClass = SUPPORTED_LLM_PROVIDERS[provider];
63
+
64
+ if (!ServiceClass) {
65
+ logger.warn(`未知的 LLM 提供商: ${provider},使用默认的 deepseek`);
66
+ return new DeepSeekService();
67
+ }
68
+
69
+ logger.info(`使用 LLM 提供商: ${provider}`);
70
+ return new ServiceClass();
71
+ }
72
+
73
+ getLLMProvider() {
74
+ return process.env.LLM_PROVIDER || "deepseek";
75
+ }
76
+
77
+ getLLMModel() {
78
+ return this.llm.model;
79
+ }
80
+
81
+ setupMessageQueue() {
82
+ this.messageQueue.registerHandler("feishu", async (message, metadata) => {
83
+ return await this.processMessageInternal(message, metadata);
84
+ });
85
+
86
+ this.messageQueue.registerHandler("terminal", async (message, metadata) => {
87
+ return await this.processMessageInternal(message, metadata);
88
+ });
89
+
90
+ this.messageQueue.registerHandler("scheduled", async (message, metadata) => {
91
+ return await this.processMessageInternal(message, metadata);
92
+ });
93
+
94
+ this.messageQueue.registerHandler("cli", async (message, metadata) => {
95
+ return await this.processMessageInternal(message, metadata);
96
+ });
97
+ }
98
+
99
+ async processMessageInternal(message, metadata = {}) {
100
+ let result;
101
+ if (this.enableStream) {
102
+ const response = await this.processMessageStream(message);
103
+ result = response?.content || "";
104
+ this.lastProcessedResponse = result;
105
+ } else {
106
+ const response = await this.processMessage(message);
107
+ result = response.content;
108
+ this.lastProcessedResponse = result;
109
+ }
110
+ return result;
111
+ }
112
+
113
+ enqueueMessage(message, source = "terminal", metadata = {}) {
114
+ return this.messageQueue.enqueue(message, source, metadata);
115
+ }
116
+
117
+ getQueueStatus() {
118
+ return this.messageQueue.getStatus();
119
+ }
120
+
121
+ /**
122
+ * 加载系统提示词
123
+ * @returns {string} 系统提示词内容
124
+ */
125
+ loadSystemPrompt() {
126
+ try {
127
+ const promptPath = path.join(__dirname, "../config/system.prompt.txt");
128
+ const prompt = fs.readFileSync(promptPath, "utf-8");
129
+ return prompt.trim();
130
+ } catch (error) {
131
+ logger.error(`无法读取 system prompt 文件: ${error.message}`);
132
+ return "你是一个智能 AI 助手。";
133
+ }
134
+ }
135
+
136
+ /**
137
+ * 初始化数据库
138
+ * @returns {Promise<{success: boolean, message: string}>} 初始化结果
139
+ */
140
+ async initDatabase() {
141
+ try {
142
+ await this.dbService.connect();
143
+ await this.dbService.initTables();
144
+ await this.schedulerTools.init();
145
+ return { success: true, message: "数据库初始化成功" };
146
+ } catch (error) {
147
+ logger.error(`数据库初始化失败: ${error.message}`);
148
+ return { success: false, message: `数据库初始化失败: ${error.message}` };
149
+ }
150
+ }
151
+
152
+ /**
153
+ * 设置飞书服务(用于定时任务推送)
154
+ * @param {Object} feishuService - 飞书服务实例
155
+ * @param {string} chatId - 默认推送的聊天 ID
156
+ */
157
+ setFeishuService(feishuService, chatId = null) {
158
+ this.schedulerTools.setFeishuService(feishuService);
159
+ if (chatId) {
160
+ this.schedulerTools.setDefaultChatId(chatId);
161
+ }
162
+ logger.info("已为定时任务设置飞书服务");
163
+ }
164
+
165
+ /**
166
+ * 注册工具处理器
167
+ * 将文件工具、命令行工具、智能体工具、搜索工具和浏览器工具注册到 DeepSeek 服务中
168
+ */
169
+ registerToolHandlers() {
170
+ // File tools handlers
171
+ this.llm.registerToolHandler("read_file", (args) => this.fileTools.readFile(args));
172
+ this.llm.registerToolHandler("write_file", (args) => this.fileTools.writeFile(args));
173
+ this.llm.registerToolHandler("list_files", (args) => this.fileTools.listFiles(args));
174
+ this.llm.registerToolHandler("delete_file", (args) => this.fileTools.deleteFile(args));
175
+
176
+ // Command tools handlers
177
+ this.llm.registerToolHandler("execute_command", (args) =>
178
+ this.commandTools.executeCommand(args)
179
+ );
180
+
181
+ // Search tools handlers
182
+ this.llm.registerToolHandler("web_search", (args) => this.searchTools.webSearch(args));
183
+ this.llm.registerToolHandler("fetch_web_page", (args) =>
184
+ this.searchTools.fetchWebPage(args)
185
+ );
186
+
187
+ // Browser tools handlers
188
+ this.llm.registerToolHandler("launch_browser", (args) =>
189
+ this.browserTools.launchBrowser(args)
190
+ );
191
+ this.llm.registerToolHandler("navigate_to", (args) => this.browserTools.navigateTo(args));
192
+ this.llm.registerToolHandler("click_element", (args) =>
193
+ this.browserTools.clickElement(args)
194
+ );
195
+ this.llm.registerToolHandler("fill_input", (args) => this.browserTools.fillInput(args));
196
+ this.llm.registerToolHandler("get_page_content", (args) =>
197
+ this.browserTools.getPageContent(args)
198
+ );
199
+ this.llm.registerToolHandler("wait_for_element", (args) =>
200
+ this.browserTools.waitForElement(args)
201
+ );
202
+ this.llm.registerToolHandler("execute_script", (args) =>
203
+ this.browserTools.executeScript(args)
204
+ );
205
+ this.llm.registerToolHandler("close_browser", (args) =>
206
+ this.browserTools.closeBrowser(args)
207
+ );
208
+
209
+ // Scheduler tools handlers
210
+ this.llm.registerToolHandler("create_scheduled_task", (args) =>
211
+ this.schedulerTools.createScheduledTask(args)
212
+ );
213
+ this.llm.registerToolHandler("get_all_scheduled_tasks", (args) =>
214
+ this.schedulerTools.getAllScheduledTasks(args)
215
+ );
216
+ this.llm.registerToolHandler("get_scheduled_task", (args) =>
217
+ this.schedulerTools.getScheduledTask(args)
218
+ );
219
+ this.llm.registerToolHandler("update_scheduled_task", (args) =>
220
+ this.schedulerTools.updateScheduledTask(args)
221
+ );
222
+ this.llm.registerToolHandler("delete_scheduled_task", (args) =>
223
+ this.schedulerTools.deleteScheduledTask(args)
224
+ );
225
+ this.llm.registerToolHandler("toggle_scheduled_task", (args) =>
226
+ this.schedulerTools.toggleScheduledTask(args)
227
+ );
228
+
229
+ // Memory tools handlers
230
+ this.llm.registerToolHandler("save_memory", (args) => this.memoryTools.saveMemory(args));
231
+ this.llm.registerToolHandler("save_short_term_memory", (args) =>
232
+ this.memoryTools.saveShortTermMemory(args)
233
+ );
234
+ this.llm.registerToolHandler("search_memories", (args) =>
235
+ this.memoryTools.searchMemories(args)
236
+ );
237
+ this.llm.registerToolHandler("get_all_memories", (args) =>
238
+ this.memoryTools.getAllMemories(args)
239
+ );
240
+ this.llm.registerToolHandler("delete_memory", (args) =>
241
+ this.memoryTools.deleteMemory(args)
242
+ );
243
+ this.llm.registerToolHandler("clear_short_term_memory", (args) =>
244
+ this.memoryTools.clearShortTermMemory(args)
245
+ );
246
+ this.llm.registerToolHandler("get_memory_stats", (args) =>
247
+ this.memoryTools.getMemoryStats(args)
248
+ );
249
+ }
250
+
251
+ /**
252
+ * 处理用户消息(流式输出)
253
+ * 构建上下文,调用 DeepSeek API,并更新记忆
254
+ * 支持函数调用,当模型返回 tool_calls 时自动处理
255
+ * @param {string} userMessage - 用户消息
256
+ * @returns {Promise<Object>} AI 响应
257
+ */
258
+ async processMessageStream(userMessage) {
259
+ const context = await this.memoryManager.buildFullContext(userMessage);
260
+
261
+ const messages = [
262
+ {
263
+ role: "system",
264
+ content: this.systemPrompt,
265
+ },
266
+ ...context,
267
+ {
268
+ role: "user",
269
+ content: userMessage,
270
+ },
271
+ ];
272
+
273
+ const limitedMessages = this.memoryManager.limitContextLength(messages);
274
+
275
+ const fileTools = this.fileTools.getFunctionDefinitions();
276
+ const commandTools = this.commandTools.getFunctionDefinitions();
277
+ const searchTools = this.searchTools.getFunctionDefinitions();
278
+ const browserTools = this.browserTools.getFunctionDefinitions();
279
+ const schedulerTools = this.schedulerTools.getFunctionDefinitions();
280
+ const memoryTools = this.memoryTools.getFunctionDefinitions();
281
+ const tools = [
282
+ ...fileTools,
283
+ ...commandTools,
284
+ ...searchTools,
285
+ ...browserTools,
286
+ ...schedulerTools,
287
+ ...memoryTools,
288
+ ];
289
+
290
+ let buffer = "";
291
+ let lastVisibleLength = 0;
292
+
293
+ process.stdout.write("AI: ");
294
+
295
+ const response = await this.llm.chatWithFunctionCallsStream(
296
+ limitedMessages,
297
+ (chunk) => {
298
+ buffer += chunk;
299
+ const rendered = this.markdownRenderer.render(buffer);
300
+ const currentVisibleLength = this.markdownRenderer.getVisibleLength(rendered);
301
+ const newContent = this.markdownRenderer.sliceByVisibleLength(
302
+ rendered,
303
+ lastVisibleLength,
304
+ currentVisibleLength
305
+ );
306
+ if (newContent) {
307
+ process.stdout.write(newContent);
308
+ lastVisibleLength = currentVisibleLength;
309
+ }
310
+ },
311
+ tools
312
+ );
313
+
314
+ process.stdout.write("\n\n");
315
+
316
+ this.memoryManager.addMessage("user", userMessage);
317
+ this.memoryManager.addMessage("assistant", response.content);
318
+
319
+ return response;
320
+ }
321
+
322
+ /**
323
+ * 处理用户消息
324
+ * 构建上下文,调用 DeepSeek API,并更新记忆
325
+ * @param {string} userMessage - 用户消息
326
+ * @returns {Promise<Object>} AI 响应
327
+ */
328
+ async processMessage(userMessage) {
329
+ const context = await this.memoryManager.buildFullContext(userMessage);
330
+
331
+ const messages = [
332
+ {
333
+ role: "system",
334
+ content: this.systemPrompt,
335
+ },
336
+ ...context,
337
+ {
338
+ role: "user",
339
+ content: userMessage,
340
+ },
341
+ ];
342
+
343
+ const limitedMessages = this.memoryManager.limitContextLength(messages);
344
+
345
+ const fileTools = this.fileTools.getFunctionDefinitions();
346
+ const commandTools = this.commandTools.getFunctionDefinitions();
347
+ const searchTools = this.searchTools.getFunctionDefinitions();
348
+ const browserTools = this.browserTools.getFunctionDefinitions();
349
+ const schedulerTools = this.schedulerTools.getFunctionDefinitions();
350
+ const memoryTools = this.memoryTools.getFunctionDefinitions();
351
+ const tools = [
352
+ ...fileTools,
353
+ ...commandTools,
354
+ ...searchTools,
355
+ ...browserTools,
356
+ ...schedulerTools,
357
+ ...memoryTools,
358
+ ];
359
+
360
+ const response = await this.llm.chatWithFunctionCalls(limitedMessages, tools);
361
+
362
+ const renderedContent = this.markdownRenderer.render(response.content);
363
+
364
+ this.memoryManager.addMessage("user", userMessage);
365
+ this.memoryManager.addMessage("assistant", response.content);
366
+
367
+ return response;
368
+ }
369
+
370
+ /**
371
+ * 清空会话上下文
372
+ */
373
+ clearContext() {
374
+ this.memoryManager.clearShortTerm();
375
+ logger.info("会话上下文已清空");
376
+ }
377
+
378
+ /**
379
+ * 执行定时任务的提示词
380
+ * @param {string} prompt - 定时任务的提示词
381
+ * @returns {Promise<string>} 执行结果
382
+ */
383
+ async executeScheduledPrompt(prompt) {
384
+ try {
385
+ logger.info(`执行定时任务提示词: ${prompt.substring(0, 50)}...`);
386
+
387
+ const queueStatus = this.getQueueStatus();
388
+ if (queueStatus.queueLength > 0 || queueStatus.isProcessing) {
389
+ logger.info(
390
+ `定时任务已加入队列 (队列长度: ${queueStatus.queueLength}, 处理中: ${queueStatus.isProcessing})`
391
+ );
392
+ }
393
+
394
+ this.enqueueMessage(prompt, "scheduled");
395
+
396
+ await this.messageQueue.waitForIdle(300000);
397
+
398
+ const result = this.lastProcessedResponse;
399
+ if (result) {
400
+ logger.info(`定时任务执行结果: ${result.substring(0, 100)}...`);
401
+ }
402
+ return result;
403
+ } catch (error) {
404
+ logger.error(`执行定时任务提示词失败: ${error.message}`);
405
+ return null;
406
+ }
407
+ }
408
+
409
+ /**
410
+ * 记录 token 使用量
411
+ * @param {number} inputTokens - 输入 token 数量
412
+ * @param {number} outputTokens - 输出 token 数量
413
+ */
414
+ async recordTokenUsage(inputTokens, outputTokens) {
415
+ try {
416
+ await this.dbService.recordTokenUsage(inputTokens, outputTokens);
417
+ logger.debug(`Token 使用已记录: 输入 ${inputTokens}, 输出 ${outputTokens}`);
418
+ } catch (error) {
419
+ logger.error(`记录 token 使用失败: ${error.message}`);
420
+ }
421
+ }
422
+
423
+ /**
424
+ * 获取 token 使用统计
425
+ * @returns {Promise<Object>} token 使用统计
426
+ */
427
+ async getTokenStats() {
428
+ try {
429
+ const todayUsage = await this.dbService?.getTodayTokenUsage() || {
430
+ date: new Date().toISOString().split("T")[0],
431
+ inputTokens: 0,
432
+ outputTokens: 0,
433
+ totalTokens: 0,
434
+ requestCount: 0,
435
+ };
436
+ const totalUsage = await this.dbService?.getTotalTokenUsage() || {
437
+ totalInputTokens: 0,
438
+ totalOutputTokens: 0,
439
+ totalTokens: 0,
440
+ totalRequestCount: 0,
441
+ };
442
+ return {
443
+ today: todayUsage,
444
+ total: totalUsage,
445
+ };
446
+ } catch (error) {
447
+ logger.error(`获取 token 统计失败: ${error.message}`);
448
+ return null;
449
+ }
450
+ }
451
+
452
+ /**
453
+ * 显示 token 使用统计
454
+ */
455
+ async showTokenStats() {
456
+ try {
457
+ const stats = await this.getTokenStats();
458
+ if (!stats) {
459
+ process.stdout.write("\n无法获取 token 统计信息\n\n");
460
+ return;
461
+ }
462
+
463
+ const formatNumber = (num) => num.toLocaleString();
464
+
465
+ process.stdout.write("\n========== Token 使用统计 ==========\n");
466
+ process.stdout.write(`\n今日消耗 (${stats.today.date}):\n`);
467
+ process.stdout.write(` 输入 Token: ${formatNumber(stats.today.inputTokens)}\n`);
468
+ process.stdout.write(` 输出 Token: ${formatNumber(stats.today.outputTokens)}\n`);
469
+ process.stdout.write(` 总计 Token: ${formatNumber(stats.today.totalTokens)}\n`);
470
+ process.stdout.write(` 请求次数: ${formatNumber(stats.today.requestCount)}\n`);
471
+ process.stdout.write(`\n累计消耗:\n`);
472
+ process.stdout.write(` 输入 Token: ${formatNumber(stats.total.totalInputTokens)}\n`);
473
+ process.stdout.write(` 输出 Token: ${formatNumber(stats.total.totalOutputTokens)}\n`);
474
+ process.stdout.write(` 总计 Token: ${formatNumber(stats.total.totalTokens)}\n`);
475
+ process.stdout.write(` 请求次数: ${formatNumber(stats.total.totalRequestCount)}\n`);
476
+ process.stdout.write("====================================\n\n");
477
+ } catch (error) {
478
+ process.stdout.write(`\n获取 token 统计失败: ${error.message}\n\n`);
479
+ }
480
+ }
481
+
482
+ async getStatus() {
483
+ const memoryStats = await this.memoryManager?.getStats() || {
484
+ shortTermCount: 0,
485
+ shortTermLimit: 20,
486
+ longTermCount: 0,
487
+ archiveQueueLength: 0,
488
+ memoryExpiryDays: 30,
489
+ };
490
+ const queueStatus = this.messageQueue?.getStatus() || {
491
+ queueLength: 0,
492
+ isProcessing: false,
493
+ stats: {},
494
+ };
495
+ const uptime = Date.now() - this.startTime;
496
+ const uptimeHours = Math.floor(uptime / (1000 * 60 * 60));
497
+ const uptimeMinutes = Math.floor((uptime % (1000 * 60 * 60)) / (1000 * 60));
498
+ const uptimeSeconds = Math.floor((uptime % (1000 * 60)) / 1000);
499
+
500
+ const memoryUsage = process.memoryUsage();
501
+ const cpuUsage = process.cpuUsage();
502
+ const loadAvg = os.loadavg();
503
+
504
+ return {
505
+ status: "running",
506
+ uptime: `${uptimeHours}小时 ${uptimeMinutes}分钟 ${uptimeSeconds}秒`,
507
+ startTime: new Date(this.startTime).toISOString(),
508
+ memory: {
509
+ shortTermCount: memoryStats.shortTermCount,
510
+ shortTermLimit: memoryStats.shortTermLimit,
511
+ longTermCount: memoryStats.longTermCount,
512
+ archiveQueueLength: memoryStats.archiveQueueLength,
513
+ },
514
+ queue: {
515
+ length: queueStatus.queueLength,
516
+ isProcessing: queueStatus.isProcessing,
517
+ stats: queueStatus.stats,
518
+ },
519
+ config: {
520
+ enableStream: this.enableStream,
521
+ maxContextTokens: this.memoryManager?.maxContextTokens || 100000,
522
+ memoryExpiryDays: memoryStats.memoryExpiryDays,
523
+ },
524
+ system: {
525
+ nodeVersion: process.version,
526
+ platform: `${os.type()} ${os.release()}`,
527
+ arch: os.arch(),
528
+ cpuCores: os.cpus().length,
529
+ loadAverage: loadAvg.map((v) => v.toFixed(2)).join(", "),
530
+ totalMemory: this.formatBytes(os.totalmem()),
531
+ freeMemory: this.formatBytes(os.freemem()),
532
+ usedMemory: this.formatBytes(os.totalmem() - os.freemem()),
533
+ memoryUsagePercent: ((1 - os.freemem() / os.totalmem()) * 100).toFixed(1),
534
+ },
535
+ process: {
536
+ pid: process.pid,
537
+ memoryRSS: this.formatBytes(memoryUsage.rss),
538
+ memoryHeapTotal: this.formatBytes(memoryUsage.heapTotal),
539
+ memoryHeapUsed: this.formatBytes(memoryUsage.heapUsed),
540
+ memoryExternal: this.formatBytes(memoryUsage.external),
541
+ heapUsagePercent: ((memoryUsage.heapUsed / memoryUsage.heapTotal) * 100).toFixed(1),
542
+ cpuUser: (cpuUsage.user / 1000).toFixed(0),
543
+ cpuSystem: (cpuUsage.system / 1000).toFixed(0),
544
+ },
545
+ };
546
+ }
547
+
548
+ formatBytes(bytes) {
549
+ if (bytes === 0) return "0 B";
550
+ const k = 1024;
551
+ const sizes = ["B", "KB", "MB", "GB", "TB"];
552
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
553
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
554
+ }
555
+
556
+ /**
557
+ * 停止服务
558
+ */
559
+ async shutdown() {
560
+ logger.info("正在停止服务...");
561
+ this.shouldShutdown = true;
562
+ this.schedulerTools.stopAllTasks();
563
+ await this.dbService.close();
564
+ logger.info("服务已停止");
565
+ process.exit(0);
566
+ }
567
+
568
+ async handleSpecialCommand(command, returnResult = false) {
569
+ const trimmedCommand = command.trim().toLowerCase();
570
+
571
+ if (trimmedCommand === "/new") {
572
+ this.clearContext();
573
+ return returnResult ? "上下文已清空" : true;
574
+ }
575
+
576
+ if (trimmedCommand === "/tokens") {
577
+ const stats = await this.getTokenStats();
578
+ if (returnResult) {
579
+ return stats;
580
+ }
581
+ await this.showTokenStats();
582
+ return true;
583
+ }
584
+
585
+ if (trimmedCommand === "/status") {
586
+ const status = await this.getStatus();
587
+ if (returnResult) {
588
+ return status;
589
+ }
590
+ process.stdout.write("\n========== 服务器状态 ==========\n");
591
+ process.stdout.write(`状态: ${status.status}\n`);
592
+ process.stdout.write(`运行时间: ${status.uptime}\n`);
593
+ process.stdout.write(`启动时间: ${status.startTime}\n`);
594
+ process.stdout.write(`\n记忆:\n`);
595
+ process.stdout.write(
596
+ ` 短期记忆: ${status.memory.shortTermCount}/${status.memory.shortTermLimit}\n`
597
+ );
598
+ process.stdout.write(` 长期记忆: ${status.memory.longTermCount}\n`);
599
+ process.stdout.write(` 归档队列: ${status.memory.archiveQueueLength}\n`);
600
+ process.stdout.write(`\n消息队列:\n`);
601
+ process.stdout.write(` 队列长度: ${status.queue.length}\n`);
602
+ process.stdout.write(` 处理中: ${status.queue.isProcessing ? "是" : "否"}\n`);
603
+ process.stdout.write(` 总接收: ${status.queue.stats.totalReceived}\n`);
604
+ process.stdout.write(` 总处理: ${status.queue.stats.totalProcessed}\n`);
605
+ process.stdout.write(` 总丢弃: ${status.queue.stats.totalDropped}\n`);
606
+ process.stdout.write(`\n配置:\n`);
607
+ process.stdout.write(` 流式输出: ${status.config.enableStream ? "启用" : "禁用"}\n`);
608
+ process.stdout.write(` 最大上下文 Token: ${status.config.maxContextTokens}\n`);
609
+ process.stdout.write(` 记忆过期天数: ${status.config.memoryExpiryDays}\n`);
610
+ process.stdout.write(`\n系统信息:\n`);
611
+ process.stdout.write(` Node.js: ${status.system.nodeVersion}\n`);
612
+ process.stdout.write(` 平台: ${status.system.platform}\n`);
613
+ process.stdout.write(` 架构: ${status.system.arch}\n`);
614
+ process.stdout.write(` CPU 核心数: ${status.system.cpuCores}\n`);
615
+ process.stdout.write(` 系统负载: ${status.system.loadAverage}\n`);
616
+ process.stdout.write(` 总内存: ${status.system.totalMemory}\n`);
617
+ process.stdout.write(` 已用内存: ${status.system.usedMemory} (${status.system.memoryUsagePercent}%)\n`);
618
+ process.stdout.write(` 空闲内存: ${status.system.freeMemory}\n`);
619
+ process.stdout.write(`\n进程信息:\n`);
620
+ process.stdout.write(` PID: ${status.process.pid}\n`);
621
+ process.stdout.write(` 内存占用 (RSS): ${status.process.memoryRSS}\n`);
622
+ process.stdout.write(` 堆内存: ${status.process.memoryHeapUsed} / ${status.process.memoryHeapTotal} (${status.process.heapUsagePercent}%)\n`);
623
+ process.stdout.write(` 外部内存: ${status.process.memoryExternal}\n`);
624
+ process.stdout.write(` CPU 用户态: ${status.process.cpuUser}ms\n`);
625
+ process.stdout.write(` CPU 内核态: ${status.process.cpuSystem}ms\n`);
626
+ process.stdout.write("===============================\n\n");
627
+ return true;
628
+ }
629
+
630
+ if (trimmedCommand === "/shutdown") {
631
+ this.shutdown();
632
+ return returnResult ? "服务正在停止..." : true;
633
+ }
634
+
635
+ return false;
636
+ }
637
+
638
+ /**
639
+ * 启动交互式聊天循环
640
+ * 持续接收用户输入并处理,直到用户输入 exit 或 quit
641
+ */
642
+ async chatLoop() {
643
+ const readline = require("readline");
644
+ const rl = readline.createInterface({
645
+ input: process.stdin,
646
+ output: process.stdout,
647
+ });
648
+
649
+ await this.initDatabase();
650
+
651
+ process.stdout.write("\n========================================\n");
652
+ process.stdout.write(" AI 智能体 - 单智能体版\n");
653
+ process.stdout.write("========================================\n");
654
+ process.stdout.write('输入你的问题或指令,输入 "exit" 或 "quit" 退出\n');
655
+ process.stdout.write(
656
+ "特殊命令: /new (清空上下文), /tokens (查看token统计), /status (查看状态), /shutdown (停止服务)\n\n"
657
+ );
658
+
659
+ const askQuestion = (query) => {
660
+ return new Promise((resolve) => {
661
+ rl.question(query, resolve);
662
+ });
663
+ };
664
+
665
+ while (true) {
666
+ const userInput = await askQuestion("你: ");
667
+
668
+ if (this.shouldShutdown) {
669
+ break;
670
+ }
671
+
672
+ if (userInput.toLowerCase() === "exit" || userInput.toLowerCase() === "quit") {
673
+ process.stdout.write("\n再见!\n");
674
+ rl.close();
675
+ break;
676
+ }
677
+
678
+ if (userInput.trim() === "") {
679
+ continue;
680
+ }
681
+
682
+ if (await this.handleSpecialCommand(userInput)) {
683
+ continue;
684
+ }
685
+
686
+ try {
687
+ const queueStatus = this.getQueueStatus();
688
+ if (queueStatus.queueLength > 0 || queueStatus.isProcessing) {
689
+ process.stdout.write(
690
+ `消息已加入队列 (队列长度: ${queueStatus.queueLength}, 处理中: ${queueStatus.isProcessing ? "是" : "否"})\n`
691
+ );
692
+ }
693
+
694
+ this.enqueueMessage(userInput, "terminal");
695
+
696
+ await this.messageQueue.waitForIdle(300000);
697
+
698
+ if (this.lastProcessedResponse) {
699
+ const renderedContent = this.markdownRenderer.render(this.lastProcessedResponse);
700
+ process.stdout.write(`\nAI:\n${renderedContent}\n\n`);
701
+ }
702
+ } catch (error) {
703
+ logger.error(`处理消息失败: ${error.message}`, { error });
704
+ process.stdout.write(`\n错误: ${error.message}\n\n`);
705
+ }
706
+ }
707
+
708
+ await this.dbService.close();
709
+ }
710
+ }
711
+
712
+ module.exports = AIAgent;