foliko 1.1.63 → 1.1.65

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.
Files changed (48) hide show
  1. package/.agent/data/plugins-state.json +8 -0
  2. package/.agent/sessions/cli_default.json +258 -260
  3. package/cli/bin/foliko.js +2 -2
  4. package/cli/src/commands/chat.js +15 -26
  5. package/cli/src/ui/chat-ui.js +102 -165
  6. package/cli/src/ui/footer-bar.js +7 -32
  7. package/cli/src/ui/message-bubble.js +24 -2
  8. package/cli/src/ui/status-bar.js +177 -0
  9. package/package.json +1 -2
  10. package/plugins/audit-plugin.js +11 -7
  11. package/plugins/coordinator-plugin.js +14 -12
  12. package/plugins/data-splitter-plugin.js +323 -0
  13. package/plugins/default-plugins.js +12 -1
  14. package/plugins/extension-executor-plugin.js +2 -2
  15. package/plugins/file-system-plugin.js +68 -50
  16. package/plugins/gate-trading.js +10 -10
  17. package/plugins/install-plugin.js +3 -3
  18. package/plugins/memory-plugin.js +8 -11
  19. package/plugins/plugin-manager-plugin.js +9 -11
  20. package/plugins/qq-plugin.js +9 -9
  21. package/plugins/rules-plugin.js +7 -7
  22. package/plugins/scheduler-plugin.js +22 -18
  23. package/plugins/session-plugin.js +14 -14
  24. package/plugins/storage-plugin.js +11 -10
  25. package/plugins/subagent-plugin.js +13 -9
  26. package/plugins/think-plugin.js +63 -59
  27. package/plugins/tools-plugin.js +8 -8
  28. package/plugins/weixin-plugin.js +5 -5
  29. package/src/capabilities/skill-manager.js +23 -15
  30. package/src/capabilities/workflow-engine.js +2 -2
  31. package/src/core/agent-chat.js +70 -26
  32. package/src/core/agent.js +17 -27
  33. package/src/core/chat-session.js +7 -161
  34. package/src/core/constants.js +198 -0
  35. package/src/core/context-compressor.js +6 -181
  36. package/src/core/framework.js +125 -6
  37. package/src/core/plugin-base.js +7 -5
  38. package/src/core/provider.js +6 -0
  39. package/src/core/subagent.js +16 -135
  40. package/src/core/tool-executor.js +2 -70
  41. package/src/executors/mcp-executor.js +12 -10
  42. package/src/utils/chat-queue.js +11 -22
  43. package/src/utils/data-splitter.js +345 -0
  44. package/src/utils/download.js +5 -4
  45. package/src/utils/message-validator.js +283 -0
  46. package/src/utils/retry.js +168 -22
  47. package/src/utils/sandbox.js +60 -207
  48. package/cli/src/utils/debounce.js +0 -106
@@ -14,20 +14,24 @@ const {
14
14
  tool: aiTool,
15
15
  ToolLoopAgent,
16
16
  isLoopFinished,
17
- generateText,
18
- streamText,
19
- RetryError,
20
- APICallError,
21
17
  } = require('ai');
22
- const { prepareMessagesForAPI, cleanResponse } = require('../utils');
18
+ const { autoSplitToolResult } = require('../../plugins/data-splitter-plugin');
19
+ const { cleanResponse } = require('../utils');
23
20
  const { ChatQueueManager } = require('../utils/chat-queue');
24
21
  const { TokenCounter } = require('./token-counter');
25
22
  const { isThinkingModel } = require('./provider');
26
- const fs = require('fs/promises');
27
23
  // 新模块
28
24
  const { ChatSession } = require('./chat-session');
29
25
  const { ToolExecutor } = require('./tool-executor');
30
26
  const { ContextCompressor } = require('./context-compressor');
27
+ const {
28
+ DEFAULT_MAX_OUTPUT_TOKENS,
29
+ DEFAULT_TEMPERATURE,
30
+ DEFAULT_MAX_STEPS,
31
+ DEFAULT_MAX_CONCURRENT,
32
+ DEFAULT_RETRY_ATTEMPTS,
33
+ DEFAULT_RETRY_DELAY_MS,
34
+ } = require('./constants');
31
35
 
32
36
  class AgentChatHandler extends EventEmitter {
33
37
  /**
@@ -104,9 +108,9 @@ class AgentChatHandler extends EventEmitter {
104
108
 
105
109
  // ChatQueueManager: 队列管理
106
110
  this.queueManager = new ChatQueueManager({
107
- maxConcurrent: config.maxConcurrent || 1,
108
- retryAttempts: config.retryAttempts || 3,
109
- retryDelay: config.retryDelay || 1000,
111
+ maxConcurrent: config.maxConcurrent || DEFAULT_MAX_CONCURRENT,
112
+ retryAttempts: config.retryAttempts || DEFAULT_RETRY_ATTEMPTS,
113
+ retryDelay: config.retryDelay || DEFAULT_RETRY_DELAY_MS,
110
114
  });
111
115
 
112
116
  // AI client
@@ -183,10 +187,15 @@ class AgentChatHandler extends EventEmitter {
183
187
 
184
188
  // ==================== 工具管理(委托给 ToolExecutor) ====================
185
189
 
190
+ /** AI tools 格式缓存 (避免每次 chat 重建) */
191
+ _aiToolsCache = null;
192
+ _aiToolsCacheKey = ''; // 工具列表的哈希摘要
193
+
186
194
  registerTool(tool) {
187
195
  this._toolExecutor.registerTool(tool);
188
196
  // 工具列表变了,清除缓存
189
197
  this._toolsTokensCacheVersion = 0;
198
+ this._aiToolsCache = null; // 清除 AI tools 缓存
190
199
  return this;
191
200
  }
192
201
 
@@ -463,8 +472,7 @@ class AgentChatHandler extends EventEmitter {
463
472
  throw new Error('AI client not configured.');
464
473
  }
465
474
 
466
- const systemPrompt = framework._mainAgent._buildSystemPrompt();
467
- // await fs.writeFile('system.md',systemPrompt)
475
+ const systemPrompt = framework.getSystemPrompt();
468
476
  const tools = this._getAITools(aiTool);
469
477
  const agent = new ToolLoopAgent({
470
478
  model: this._aiClient,
@@ -576,7 +584,9 @@ class AgentChatHandler extends EventEmitter {
576
584
  yield { type: 'error', error: friendlyMessage };
577
585
  } finally {
578
586
  const messageStore = this._getSessionMessageStore(sessionId);
579
- messageStore.save();
587
+ messageStore.save().catch((err) => {
588
+ logger.error(`[${sessionId}] Failed to save message store: ${err.message}`);
589
+ });
580
590
  }
581
591
  }
582
592
 
@@ -602,10 +612,14 @@ class AgentChatHandler extends EventEmitter {
602
612
  }
603
613
 
604
614
  /**
605
- * 入队消息
615
+ * 入队消息(走共享的 ChatQueueManager,与 sendMessage 共用同一队列)
606
616
  */
607
617
  enqueue(sessionId, message, options = {}) {
608
- return this._chatSession.enqueue(sessionId, message, options);
618
+ const requestId = this.generateRequestId();
619
+ return this.queueManager.enqueue(requestId, sessionId, message, {
620
+ ...options,
621
+ executeFunction: this.chatStream.bind(this),
622
+ });
609
623
  }
610
624
 
611
625
  /**
@@ -621,7 +635,7 @@ class AgentChatHandler extends EventEmitter {
621
635
  if (!this._aiClient) {
622
636
  throw new Error('AI client not configured.');
623
637
  }
624
- const systemPrompt = framework._mainAgent._buildSystemPrompt();
638
+ const systemPrompt = framework.getSystemPrompt();
625
639
  const tools = this._getAITools(aiTool);
626
640
 
627
641
  // DeepSeek thinking mode: 处理参数
@@ -688,7 +702,11 @@ class AgentChatHandler extends EventEmitter {
688
702
  };
689
703
  } finally {
690
704
  const messageStore = this._getSessionMessageStore(sessionId);
691
- messageStore.save();
705
+ try {
706
+ await messageStore.save();
707
+ } catch (err) {
708
+ logger.error(`[${sessionId}] Failed to save message store: ${err.message}`);
709
+ }
692
710
  }
693
711
  }
694
712
 
@@ -799,11 +817,25 @@ class AgentChatHandler extends EventEmitter {
799
817
  }
800
818
 
801
819
  /**
802
- * 获取 AI 工具格式
820
+ * 计算工具列表缓存 key
821
+ * @private
822
+ */
823
+ _computeToolsCacheKey() {
824
+ const allTools = this.agent.framework.getTools();
825
+ return allTools.map((t) => `${t.name}:${t.description ? t.description.length : 0}`).join('|');
826
+ }
827
+
828
+ /**
829
+ * 获取 AI 工具格式(带缓存)
803
830
  * 使用 AI SDK 的 tool() 格式
804
831
  * @private
805
832
  */
806
833
  _getAITools(toolFn) {
834
+ const currentKey = this._computeToolsCacheKey();
835
+ if (this._aiToolsCache && this._aiToolsCacheKey === currentKey) {
836
+ return this._aiToolsCache;
837
+ }
838
+
807
839
  const tools = {};
808
840
  const allTools = this.agent.framework.getTools();
809
841
  for (const toolDef of allTools) {
@@ -822,19 +854,29 @@ class AgentChatHandler extends EventEmitter {
822
854
  logger.info(`[Tool] Call: ${toolName}`);
823
855
  try {
824
856
  const result = await toolDef.execute(cleanedArgs, this.agent.framework);
825
- this.emit('tool-result', { name: toolName, args: cleanedArgs, result });
826
- // 确保返回字符串或可序列化的对象
827
- if (result === null || result === undefined) {
828
- return 'OK';
829
- }
830
- if (typeof result === 'object') {
831
- return JSON.stringify(result);
857
+
858
+ // 自动检测大工具结果,透明分拆
859
+ // 仅在数据分拆插件已加载时生效
860
+ let finalResult = result;
861
+ try {
862
+ const splitCheck = await autoSplitToolResult(toolName, result, this.agent.framework);
863
+ if (splitCheck.wasSplit && splitCheck.result) {
864
+ finalResult = splitCheck.result;
865
+ logger.info(
866
+ `[AutoSplit] 工具 "${toolName}" 结果过大,已自动分拆处理`
867
+ );
868
+ }
869
+ } catch (splitErr) {
870
+ // 分拆失败不阻断主流程,继续使用原始结果
871
+ logger.warn(`[AutoSplit] 自动分拆跳过: ${splitErr.message}`);
832
872
  }
833
- return String(result);
873
+
874
+ this.emit('tool-result', { name: toolName, args: cleanedArgs, result: finalResult });
875
+ return finalResult;
834
876
  } catch (err) {
835
877
  this.emit('tool-error', { name: toolName, args: cleanedArgs, error: err.message });
836
878
  // 返回错误信息字符串,而不是抛出异常
837
- return JSON.stringify({ error: err.message, success: false });
879
+ return { success: false,error: err.message}
838
880
  }
839
881
  },
840
882
  };
@@ -850,6 +892,8 @@ class AgentChatHandler extends EventEmitter {
850
892
  tools[toolName] = toolFn(toolConfig);
851
893
  }
852
894
 
895
+ this._aiToolsCache = tools;
896
+ this._aiToolsCacheKey = currentKey;
853
897
  return tools;
854
898
  }
855
899
 
package/src/core/agent.js CHANGED
@@ -9,39 +9,21 @@ const { SystemPromptBuilder } = require('./system-prompt-builder');
9
9
  const { NotificationManager } = require('./notification-manager');
10
10
  const { Logger, LOG_LEVELS } = require('../utils/logger');
11
11
  const os = require('os');
12
-
13
- /**
14
- * System Prompt 优先级常量
15
- * 统一管理所有 prompt 部分的优先级,避免魔法数字
16
- */
17
- const PROMPT_PRIORITY = {
18
- DATETIME: 50,
19
- ORIGINAL_PROMPT: 100,
20
- SHARED_PROMPT: 200,
21
- METADATA: 300,
22
- TOOLS: 400,
23
- SKILLS: 500,
24
- SUB_AGENTS: 600,
25
- CAPABILITIES: 700,
26
- MCP_TOOLS: 750,
27
- EXTENSION_TOOLS: 800,
28
- TOOL_CORE_RULES: 1000,
29
- };
12
+ const {
13
+ PROMPT_PRIORITY,
14
+ DEFAULT_MAX_OUTPUT_TOKENS,
15
+ DEFAULT_TEMPERATURE,
16
+ } = require('./constants');
30
17
 
31
18
  /**
32
19
  * Agent 配置常量
33
- * 统一管理配置参数,避免魔法数字
34
20
  */
35
21
  const AGENT_CONFIG = {
36
- // AI 模型配置
37
- MAX_OUTPUT_TOKENS: 8192,
38
- TEMPERATURE: 0.3,
39
- // 通知数量限制
22
+ MAX_OUTPUT_TOKENS: DEFAULT_MAX_OUTPUT_TOKENS,
23
+ TEMPERATURE: DEFAULT_TEMPERATURE,
40
24
  MAX_NOTIFICATIONS: 5,
41
- // 元数据提取配置
42
25
  CAPABILITY_MAX_LENGTH: 50,
43
26
  CAPABILITY_MAX_PARTS: 3,
44
- // 错误重试配置
45
27
  MAX_RETRIES: 3,
46
28
  };
47
29
 
@@ -77,8 +59,8 @@ class Agent extends EventEmitter {
77
59
  this.provider = config.provider || 'deepseek';
78
60
  this.providerOptions = {
79
61
  ...config.providerOptions,
80
- maxOutputTokens: config.providerOptions?.maxOutputTokens ?? AGENT_CONFIG.MAX_OUTPUT_TOKENS,
81
- temperature: config.providerOptions?.temperature ?? AGENT_CONFIG.TEMPERATURE,
62
+ maxOutputTokens: config.providerOptions?.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS,
63
+ temperature: config.providerOptions?.temperature ?? DEFAULT_TEMPERATURE,
82
64
  };
83
65
  // 原始 system prompt
84
66
  this._originalPrompt =
@@ -439,6 +421,14 @@ class Agent extends EventEmitter {
439
421
  this._syncTools();
440
422
  }
441
423
 
424
+ /**
425
+ * 获取原始系统提示文本
426
+ * @returns {string}
427
+ */
428
+ getOriginalPrompt() {
429
+ return this._originalPrompt;
430
+ }
431
+
442
432
  /**
443
433
  * 设置系统提示
444
434
  */
@@ -9,7 +9,6 @@
9
9
  */
10
10
 
11
11
  const { EventEmitter } = require('../utils/event-emitter');
12
- const { ChatQueueManager } = require('../utils/chat-queue');
13
12
  const { logger } = require('../utils/logger');
14
13
 
15
14
  /**
@@ -113,21 +112,8 @@ class ChatSession extends EventEmitter {
113
112
  // Session 消息存储 Map: sessionId -> { messages: [], historyLoaded: false, compressionState: {} }
114
113
  this._sessionMessageStores = new Map();
115
114
 
116
- // Session 队列: sessionId -> Queue of {message, options, resolve, reject}
117
- this._sessionQueues = new Map();
118
- this._processingSessions = new Set();
119
-
120
115
  // Session 事件作用域 Map: sessionId -> Set<{event, handler}>
121
116
  this._sessionScopes = new Map();
122
-
123
- // 队列管理器
124
- this.queueManager = new ChatQueueManager({
125
- maxConcurrent: config.maxConcurrent || 1,
126
- retryAttempts: config.retryAttempts || 3,
127
- retryDelay: config.retryDelay || 1000,
128
- });
129
-
130
- this._setupQueueEvents();
131
117
  }
132
118
 
133
119
  /**
@@ -138,29 +124,7 @@ class ChatSession extends EventEmitter {
138
124
  this._messageProcessor = processor;
139
125
  }
140
126
 
141
- /**
142
- * 设置队列事件转发
143
- * @private
144
- */
145
- _setupQueueEvents() {
146
- const events = [
147
- 'queue:added',
148
- 'queue:processing',
149
- 'queue:completed',
150
- 'queue:failed',
151
- 'queue:retry',
152
- 'queue:empty',
153
- 'queue:cleared',
154
- 'queue:session-removed',
155
- 'stream:chunk',
156
- ];
157
127
 
158
- events.forEach((eventName) => {
159
- this.queueManager.on(eventName, (data) => {
160
- this.emit(eventName, data);
161
- });
162
- });
163
- }
164
128
 
165
129
  /**
166
130
  * 获取或创建 SessionScope
@@ -219,6 +183,7 @@ class ChatSession extends EventEmitter {
219
183
  },
220
184
  save: () => {
221
185
  this.saveHistory(sessionId, store.messages);
186
+ return Promise.resolve();
222
187
  },
223
188
  };
224
189
  this._sessionMessageStores.set(sessionId, store);
@@ -310,123 +275,24 @@ class ChatSession extends EventEmitter {
310
275
  }
311
276
 
312
277
  /**
313
- * 入队消息
278
+ * 入队消息(直接调用消息处理器,排队由上层 ChatQueueManager 处理)
314
279
  * @param {string} sessionId - Session ID
315
280
  * @param {Object} message - 消息
316
281
  * @param {Object} options - 选项
317
282
  * @returns {Promise}
318
283
  */
319
284
  enqueue(sessionId, message, options = {}) {
320
- if (!this._sessionQueues.has(sessionId)) {
321
- this._sessionQueues.set(sessionId, []);
322
- }
323
-
324
- return new Promise((resolve, reject) => {
325
- const item = {
326
- message,
327
- options,
328
- resolve,
329
- reject,
330
- timestamp: Date.now(),
331
- executeFunction: options.executeFunction,
332
- };
333
- this._sessionQueues.get(sessionId).push(item);
334
- this.emit('queue:added', {
335
- sessionId,
336
- message,
337
- queueSize: this._sessionQueues.get(sessionId).length,
338
- });
339
-
340
- // 触发队列处理
341
- this._processNext(sessionId);
342
- });
285
+ return this._processMessageDirect(sessionId, message, options);
343
286
  }
344
287
 
345
288
  /**
346
- * 处理队列中的下一条消息
347
- * @param {string} sessionId - Session ID
289
+ * 直接处理消息(不经过额外的队列)
348
290
  * @private
349
291
  */
350
- async _processNext(sessionId) {
351
- if (this._processingSessions.has(sessionId)) {
352
- return;
353
- }
354
-
355
- const queue = this._sessionQueues.get(sessionId);
356
- if (!queue || queue.length === 0) {
357
- this.emit('queue:empty', { sessionId });
358
- return;
359
- }
360
-
361
- this._processingSessions.add(sessionId);
362
- this.emit('queue:processing', { sessionId });
363
-
364
- const item = queue.shift();
365
- try {
366
- // 如果有 executeFunction,使用流式处理
367
- if (item.executeFunction) {
368
- const chunks = [];
369
- const stream = item.executeFunction(item.message, { ...item.options, sessionId });
370
- let hasError = false;
371
- let errorMessage = '';
372
-
373
- for await (const chunk of stream) {
374
- // 检查是否是错误 chunk,如果是立即拒绝并终止
375
- if (chunk.type === 'error') {
376
- hasError = true;
377
- errorMessage = chunk.error || 'Unknown error';
378
- this.emit('message:error', { sessionId, error: errorMessage });
379
- item.reject(new Error(errorMessage));
380
- return; // 立即返回,不继续迭代
381
- }
382
- chunks.push(chunk);
383
- this.emit('stream:chunk', {
384
- sessionId,
385
- chunk,
386
- accumulated: chunks.length,
387
- });
388
- }
389
-
390
- if (hasError) {
391
- // 有错误 chunk,拒绝 Promise
392
- this.emit('message:error', { sessionId, error: errorMessage });
393
- item.reject(new Error(errorMessage));
394
- } else {
395
- const fullText = chunks
396
- .filter((a) => a.type === 'text')
397
- .map((item) => item.text)
398
- .join('');
399
-
400
- item.resolve({ text: fullText, chunks });
401
- }
402
- } else {
403
- const result = await this._processMessage(sessionId, item.message, item.options);
404
- item.resolve(result);
405
- }
406
- } catch (err) {
407
- this.emit('message:error', { sessionId, error: err.message });
408
- item.reject(err);
409
- } finally {
410
- this._processingSessions.delete(sessionId);
411
- // 处理下一条
412
- setImmediate(() => this._processNext(sessionId));
413
- }
414
- }
415
-
416
- /**
417
- * 处理单条消息(子类实现)
418
- * @param {string} sessionId - Session ID
419
- * @param {Object} message - 消息
420
- * @param {Object} options - 选项
421
- * @returns {Promise}
422
- * @protected
423
- */
424
- async _processMessage(sessionId, message, options) {
425
- // 如果设置了处理器,使用处理器
292
+ async _processMessageDirect(sessionId, message, options) {
426
293
  if (this._messageProcessor) {
427
294
  return this._messageProcessor(sessionId, message, options);
428
295
  }
429
- // 否则使用 agent 的处理逻辑
430
296
  if (this.agent?._chatHandler) {
431
297
  return this.agent._chatHandler._processMessage(sessionId, message, options);
432
298
  }
@@ -434,18 +300,10 @@ class ChatSession extends EventEmitter {
434
300
  }
435
301
 
436
302
  /**
437
- * 取消会话队列
303
+ * 取消会话队列(委托给 ChatQueueManager)
438
304
  * @param {string} sessionId - Session ID
439
305
  */
440
306
  cancelSession(sessionId) {
441
- const queue = this._sessionQueues.get(sessionId);
442
- if (queue) {
443
- queue.forEach((item) => {
444
- item.reject(new Error('Session cancelled'));
445
- });
446
- queue.length = 0;
447
- }
448
- this._processingSessions.delete(sessionId);
449
307
  this.emit('queue:session-removed', { sessionId });
450
308
  }
451
309
 
@@ -455,12 +313,7 @@ class ChatSession extends EventEmitter {
455
313
  * @returns {Object}
456
314
  */
457
315
  getQueueStatus(sessionId) {
458
- const queue = this._sessionQueues.get(sessionId) || [];
459
- return {
460
- sessionId,
461
- size: queue.length,
462
- processing: this._processingSessions.has(sessionId),
463
- };
316
+ return { sessionId, size: 0, processing: false };
464
317
  }
465
318
 
466
319
  /**
@@ -468,13 +321,6 @@ class ChatSession extends EventEmitter {
468
321
  * @param {string} sessionId - Session ID
469
322
  */
470
323
  clearQueue(sessionId) {
471
- const queue = this._sessionQueues.get(sessionId);
472
- if (queue) {
473
- queue.forEach((item) => {
474
- item.reject(new Error('Queue cleared'));
475
- });
476
- queue.length = 0;
477
- }
478
324
  this.emit('queue:cleared', { sessionId });
479
325
  }
480
326
 
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Foliko Framework 统一常量
3
+ *
4
+ * 集中管理所有 magic numbers / strings,消除散落各处的重复值。
5
+ * 所有模块应引用此文件而非硬编码。
6
+ */
7
+
8
+ const path = require('path');
9
+
10
+ // ============================================================================
11
+ // AI 模型与提供者
12
+ // ============================================================================
13
+
14
+ /** 默认 AI 提供者 */
15
+ const DEFAULT_PROVIDER = 'deepseek';
16
+
17
+ /** 默认 AI 模型 */
18
+ const DEFAULT_MODEL = 'deepseek-chat';
19
+
20
+ /** 默认 Max Output Tokens */
21
+ const DEFAULT_MAX_OUTPUT_TOKENS = 8192;
22
+
23
+ /** 默认 Temperature */
24
+ const DEFAULT_TEMPERATURE = 0.3;
25
+
26
+ /** 默认 Max Steps(工具调用最大轮数) */
27
+ const DEFAULT_MAX_STEPS = 20;
28
+
29
+ /** 需要禁用 temperature 的 thinking mode 模型列表 */
30
+ const THINKING_MODELS = [
31
+ 'deepseek-v4-pro',
32
+ 'deepseek-v4-flash',
33
+ 'deepseek-reasoner',
34
+ ];
35
+
36
+ // ============================================================================
37
+ // Session 上下文
38
+ // ============================================================================
39
+
40
+ /** Session TTL:默认 30 分钟 */
41
+ const DEFAULT_SESSION_TTL_MS = 30 * 60 * 1000;
42
+
43
+ /** Session 清理检查间隔 */
44
+ const DEFAULT_SESSION_CLEANUP_INTERVAL_MS = 60 * 1000;
45
+
46
+ /** 每个 Session 最大消息数 */
47
+ const DEFAULT_MAX_MESSAGES_PER_SESSION = 1000;
48
+
49
+ // ============================================================================
50
+ // 上下文压缩
51
+ // ============================================================================
52
+
53
+ /** 保留最近的 N 条消息 */
54
+ const KEEP_RECENT_MESSAGES = 20;
55
+
56
+ /** 智能压缩启用 */
57
+ const ENABLE_SMART_COMPRESS = true;
58
+
59
+ /** 压缩超时(毫秒) */
60
+ const COMPRESSION_TIMEOUT_MS = 1_200_000;
61
+
62
+ /** 工具结果最大字符数 */
63
+ const MAX_TOOL_RESULT_SIZE = 4000;
64
+
65
+ // ============================================================================
66
+ // 消息队列
67
+ // ============================================================================
68
+
69
+ /** 默认最大并发数 */
70
+ const DEFAULT_MAX_CONCURRENT = 1;
71
+
72
+ /** 默认重试次数 */
73
+ const DEFAULT_RETRY_ATTEMPTS = 3;
74
+
75
+ /** 默认重试延迟(毫秒) */
76
+ const DEFAULT_RETRY_DELAY_MS = 2000;
77
+
78
+ // ============================================================================
79
+ // System Prompt 优先级
80
+ // ============================================================================
81
+
82
+ const PROMPT_PRIORITY = {
83
+ DATETIME: 50,
84
+ ORIGINAL_PROMPT: 100,
85
+ SHARED_PROMPT: 200,
86
+ METADATA: 300,
87
+ TOOLS: 400,
88
+ SKILLS: 500,
89
+ SUB_AGENTS: 600,
90
+ CAPABILITIES: 700,
91
+ MCP_TOOLS: 750,
92
+ EXTENSION_TOOLS: 800,
93
+ TOOL_CORE_RULES: 95,
94
+ };
95
+
96
+ // ============================================================================
97
+ // 熔断器
98
+ // ============================================================================
99
+
100
+ /** 熔断器默认失败阈值 */
101
+ const DEFAULT_CIRCUIT_FAILURE_THRESHOLD = 3;
102
+
103
+ /** 熔断器默认成功阈值 */
104
+ const DEFAULT_CIRCUIT_SUCCESS_THRESHOLD = 2;
105
+
106
+ /** 熔断器默认超时(毫秒) */
107
+ const DEFAULT_CIRCUIT_TIMEOUT_MS = 60_000;
108
+
109
+ // ============================================================================
110
+ // 插件
111
+ // ============================================================================
112
+
113
+ /** 默认插件优先级 */
114
+ const DEFAULT_PLUGIN_PRIORITY = 100;
115
+
116
+ /** 系统插件名称集合 */
117
+ const SYSTEM_PLUGINS = new Set([
118
+ 'ai', 'defaults', 'tools', 'skill-manager', 'session',
119
+ 'storage', 'audit', 'rules', 'file-system',
120
+ ]);
121
+
122
+ /** Agent 配置目录名 */
123
+ const AGENT_DIR = '.agent';
124
+
125
+ // ============================================================================
126
+ // Session 存储
127
+ // ============================================================================
128
+
129
+ /** 默认 Session 存储类型 */
130
+ const DEFAULT_SESSION_STORAGE_TYPE = 'file';
131
+
132
+ /** 默认 Session 存储目录 */
133
+ const DEFAULT_SESSION_STORAGE_DIR = path.join(AGENT_DIR, 'sessions');
134
+
135
+ // ============================================================================
136
+ // Token 计数(估算系数)
137
+ // ============================================================================
138
+
139
+ /** 每字符对应的 token 数(中文系数更大) */
140
+ const TOKENS_PER_CHAR = 0.25;
141
+
142
+ /** 每工具对应的 token 数 */
143
+ const TOKENS_PER_TOOL = 500;
144
+
145
+ /** 每消息固定开销 token */
146
+ const TOKENS_PER_MESSAGE_OVERHEAD = 4;
147
+
148
+ // ============================================================================
149
+ // 导出
150
+ // ============================================================================
151
+
152
+ module.exports = {
153
+ // AI
154
+ DEFAULT_PROVIDER,
155
+ DEFAULT_MODEL,
156
+ DEFAULT_MAX_OUTPUT_TOKENS,
157
+ DEFAULT_TEMPERATURE,
158
+ DEFAULT_MAX_STEPS,
159
+ THINKING_MODELS,
160
+
161
+ // Session
162
+ DEFAULT_SESSION_TTL_MS,
163
+ DEFAULT_SESSION_CLEANUP_INTERVAL_MS,
164
+ DEFAULT_MAX_MESSAGES_PER_SESSION,
165
+
166
+ // Compression
167
+ KEEP_RECENT_MESSAGES,
168
+ ENABLE_SMART_COMPRESS,
169
+ COMPRESSION_TIMEOUT_MS,
170
+ MAX_TOOL_RESULT_SIZE,
171
+
172
+ // Queue
173
+ DEFAULT_MAX_CONCURRENT,
174
+ DEFAULT_RETRY_ATTEMPTS,
175
+ DEFAULT_RETRY_DELAY_MS,
176
+
177
+ // Priority
178
+ PROMPT_PRIORITY,
179
+
180
+ // Circuit Breaker
181
+ DEFAULT_CIRCUIT_FAILURE_THRESHOLD,
182
+ DEFAULT_CIRCUIT_SUCCESS_THRESHOLD,
183
+ DEFAULT_CIRCUIT_TIMEOUT_MS,
184
+
185
+ // Plugin
186
+ DEFAULT_PLUGIN_PRIORITY,
187
+ SYSTEM_PLUGINS,
188
+ AGENT_DIR,
189
+
190
+ // Storage
191
+ DEFAULT_SESSION_STORAGE_TYPE,
192
+ DEFAULT_SESSION_STORAGE_DIR,
193
+
194
+ // Token
195
+ TOKENS_PER_CHAR,
196
+ TOKENS_PER_TOOL,
197
+ TOKENS_PER_MESSAGE_OVERHEAD,
198
+ };