foliko 1.0.75 → 1.0.76

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 (88) hide show
  1. package/.claude/settings.local.json +159 -157
  2. package/cli/bin/foliko.js +12 -12
  3. package/cli/src/commands/chat.js +143 -143
  4. package/cli/src/commands/list.js +93 -93
  5. package/cli/src/index.js +75 -75
  6. package/cli/src/ui/chat-ui.js +201 -201
  7. package/cli/src/utils/ansi.js +40 -40
  8. package/cli/src/utils/markdown.js +292 -292
  9. package/examples/ambient-example.js +194 -194
  10. package/examples/basic.js +115 -115
  11. package/examples/bootstrap.js +121 -121
  12. package/examples/mcp-example.js +56 -56
  13. package/examples/skill-example.js +49 -49
  14. package/examples/test-chat.js +137 -137
  15. package/examples/test-mcp.js +85 -85
  16. package/examples/test-reload.js +59 -59
  17. package/examples/test-telegram.js +50 -50
  18. package/examples/test-tg-bot.js +45 -45
  19. package/examples/test-tg-simple.js +47 -47
  20. package/examples/test-tg.js +62 -62
  21. package/examples/test-think.js +43 -43
  22. package/examples/test-web-plugin.js +103 -103
  23. package/examples/test-weixin-feishu.js +103 -103
  24. package/examples/workflow.js +158 -158
  25. package/package.json +1 -1
  26. package/plugins/ai-plugin.js +102 -102
  27. package/plugins/ambient-agent/EventWatcher.js +113 -113
  28. package/plugins/ambient-agent/ExplorerLoop.js +640 -640
  29. package/plugins/ambient-agent/GoalManager.js +197 -197
  30. package/plugins/ambient-agent/Reflector.js +95 -95
  31. package/plugins/ambient-agent/StateStore.js +90 -90
  32. package/plugins/ambient-agent/constants.js +101 -101
  33. package/plugins/ambient-agent/index.js +579 -579
  34. package/plugins/audit-plugin.js +187 -187
  35. package/plugins/default-plugins.js +662 -662
  36. package/plugins/email/constants.js +64 -64
  37. package/plugins/email/handlers.js +461 -461
  38. package/plugins/email/index.js +278 -278
  39. package/plugins/email/monitor.js +269 -269
  40. package/plugins/email/parser.js +138 -138
  41. package/plugins/email/reply.js +151 -151
  42. package/plugins/email/utils.js +124 -124
  43. package/plugins/feishu-plugin.js +481 -481
  44. package/plugins/file-system-plugin.js +826 -826
  45. package/plugins/install-plugin.js +199 -199
  46. package/plugins/python-executor-plugin.js +367 -367
  47. package/plugins/python-plugin-loader.js +481 -481
  48. package/plugins/rules-plugin.js +294 -294
  49. package/plugins/scheduler-plugin.js +691 -691
  50. package/plugins/session-plugin.js +369 -369
  51. package/plugins/shell-executor-plugin.js +197 -197
  52. package/plugins/storage-plugin.js +240 -240
  53. package/plugins/subagent-plugin.js +845 -845
  54. package/plugins/telegram-plugin.js +482 -482
  55. package/plugins/think-plugin.js +345 -345
  56. package/plugins/tools-plugin.js +196 -196
  57. package/plugins/web-plugin.js +606 -606
  58. package/plugins/weixin-plugin.js +545 -545
  59. package/src/capabilities/index.js +11 -11
  60. package/src/capabilities/skill-manager.js +609 -609
  61. package/src/capabilities/workflow-engine.js +1109 -1109
  62. package/src/core/agent-chat.js +882 -882
  63. package/src/core/agent.js +892 -892
  64. package/src/core/framework.js +465 -465
  65. package/src/core/index.js +19 -19
  66. package/src/core/plugin-base.js +219 -219
  67. package/src/core/plugin-manager.js +863 -863
  68. package/src/core/provider.js +114 -114
  69. package/src/core/sub-agent-config.js +264 -264
  70. package/src/core/system-prompt-builder.js +120 -120
  71. package/src/core/tool-registry.js +517 -517
  72. package/src/core/tool-router.js +297 -297
  73. package/src/executors/executor-base.js +58 -58
  74. package/src/executors/mcp-executor.js +741 -741
  75. package/src/index.js +25 -25
  76. package/src/utils/circuit-breaker.js +301 -301
  77. package/src/utils/error-boundary.js +363 -363
  78. package/src/utils/error.js +374 -374
  79. package/src/utils/event-emitter.js +97 -97
  80. package/src/utils/id.js +133 -133
  81. package/src/utils/index.js +217 -217
  82. package/src/utils/logger.js +181 -181
  83. package/src/utils/plugin-helpers.js +90 -90
  84. package/src/utils/retry.js +122 -122
  85. package/src/utils/sandbox.js +292 -292
  86. package/test/tool-registry-validation.test.js +218 -218
  87. package/website/script.js +136 -136
  88. package/foliko-1.0.75.tgz +0 -0
package/src/core/agent.js CHANGED
@@ -1,892 +1,892 @@
1
- /**
2
- * Agent 类
3
- * 负责对话和推理
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter');
7
- const { AgentChatHandler } = require('./agent-chat');
8
- const { SystemPromptBuilder } = require('./system-prompt-builder');
9
- const os = require('os');
10
-
11
- class Agent extends EventEmitter {
12
- /**
13
- * @param {Framework} framework - 框架实例
14
- * @param {Object} config - 配置
15
- * @param {string} [config.name] - Agent 名称
16
- * @param {string} [config.systemPrompt] - 系统提示
17
- * @param {string} [config.sharedPrompt] - 共享提示模板,支持 {{VAR}} 占位符
18
- * @param {Object} [config.metadata] - 元数据,注入到 sharedPrompt
19
- * @param {boolean} [config.enableToolRouting=true] - 是否启用工具路由
20
- */
21
- constructor(framework, config = {}) {
22
- super();
23
-
24
- this.framework = framework;
25
- this.config = config;
26
-
27
- this.name = config.name || 'Agent';
28
- this.model = config.model || 'deepseek-chat';
29
- this.apiKey = config.apiKey;
30
- this.baseURL = config.baseURL;
31
- this.provider = config.provider || 'deepseek';
32
- this.providerOptions = config.providerOptions || {};
33
- this.providerOptions.maxOutputTokens = 8192;
34
- this.providerOptions.temperature = 0.3; // 降低 temperature 减少生成错误 JSON 的概率
35
- // 原始 system prompt
36
- this._originalPrompt =
37
- config.systemPrompt ||
38
- '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。';
39
-
40
- // 共享提示模板
41
- this._sharedPrompt = config.sharedPrompt || '';
42
-
43
- // 元数据
44
- const metadata = config.metadata || {};
45
- this._metadata = new Map(Object.entries(metadata));
46
-
47
- this._chatHandler = null;
48
- this._tools = new Map();
49
- this._status = 'idle';
50
-
51
- // 子Agent管理
52
- this._subAgents = new Map();
53
-
54
- // 消息队列(用于 pushMessage)
55
- this._messageQueue = [];
56
- this._isProcessingQueue = false;
57
-
58
- // System prompt 构建器
59
- this._systemPromptBuilder = new SystemPromptBuilder();
60
- this._registerDefaultPromptParts();
61
-
62
- // 处理后的 system prompt (带上下文)
63
- this.systemPrompt = this._buildSystemPrompt();
64
-
65
- // 初始化聊天处理器
66
- this._initChatHandler();
67
- }
68
-
69
- /**
70
- * 注册默认的系统提示词部分
71
- * @private
72
- */
73
- _registerDefaultPromptParts() {
74
- // 1. 原始 system prompt (优先级 100)
75
- this._systemPromptBuilder.register('original-prompt', 100, () => this._originalPrompt);
76
-
77
- // 2. 共享提示模板 (优先级 200)
78
- this._systemPromptBuilder.register('shared-prompt', 200, () => {
79
- if (this._sharedPrompt) {
80
- return this._replacePlaceholders(this._sharedPrompt);
81
- }
82
- return null;
83
- });
84
-
85
- // 3. 元数据 (优先级 300)
86
- this._systemPromptBuilder.register('metadata', 300, () => {
87
- if (this._metadata.size === 0) {
88
- return null;
89
- }
90
- const metaParts = ['【元数据】'];
91
- for (const [key, value] of this._metadata) {
92
- if (typeof value === 'object') {
93
- metaParts.push(`- ${key}: ${JSON.stringify(value)}`);
94
- } else {
95
- metaParts.push(`- ${key}: ${value}`);
96
- }
97
- }
98
- return metaParts.join('\n');
99
- });
100
-
101
- // 4. 工具列表 (优先级 400)
102
- this._systemPromptBuilder.register('tools', 400, () => this._buildToolsDescription());
103
-
104
- // 5. 技能列表 (优先级 500)
105
- this._systemPromptBuilder.register('skills', 500, () => this._buildSkillsDescription());
106
-
107
- // 6. 子Agent列表 (优先级 600)
108
- this._systemPromptBuilder.register('subagents', 600, () => this._buildSubAgentsDescription());
109
-
110
- // 7. 系统能力 (优先级 700)
111
- this._systemPromptBuilder.register('capabilities', 700, () => this._buildCapabilitiesDescription());
112
-
113
- // 8. 工具调用核心规则 (优先级 1000)
114
- this._systemPromptBuilder.register('tool-core-rules', 1000, () => this._getToolCoreRules());
115
- }
116
-
117
- /**
118
- * 获取元数据值
119
- */
120
- _getMetadataValue(key) {
121
- // 优先从 metadata 获取
122
- if (this._metadata.has(key)) {
123
- return this._metadata.get(key);
124
- }
125
-
126
- // 内置变量
127
- switch (key) {
128
- case 'WORK_DIR':
129
- case 'CWD':
130
- return process.cwd();
131
- case 'HOME_DIR':
132
- return os.homedir();
133
- case 'HOST_NAME':
134
- return os.hostname();
135
- case 'PLATFORM':
136
- return process.platform;
137
- case 'TIME':
138
- return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
139
- case 'DATE':
140
- return new Date().toISOString().split('T')[0];
141
- default:
142
- return `{{${key}}}`;
143
- }
144
- }
145
-
146
- /**
147
- * 替换 sharedPrompt 中的占位符
148
- */
149
- _replacePlaceholders(template) {
150
- return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
151
- return this._getMetadataValue(key);
152
- });
153
- }
154
-
155
- /**
156
- * 构建工具描述
157
- */
158
- _buildToolsDescription() {
159
- if (this._tools.size === 0) {
160
- return '';
161
- }
162
-
163
- // 需要排除的子Agent相关工具(它们通过专门的子Agent部分提供)
164
- // const excludedTools = new Set(['subagent_call', 'subagent_list', 'subagent_reload']);
165
-
166
- let desc = '【可用工具】\n';
167
- for (const [name, tool] of this._tools) {
168
- // 跳过没有描述的工具(对LLM无帮助)
169
- if (!tool.description) continue;
170
- // // 跳过子Agent相关工具(通过专门的子Agent部分提供)
171
- // if (excludedTools.has(name)) continue;
172
- // // 跳过子Agent委托工具(通过专门的子Agent部分提供)
173
- // if (this._subAgents.has(name)) continue;
174
- desc += `- ${name}: ${tool.description}\n`;
175
- }
176
- return desc.trim();
177
- }
178
-
179
- /**
180
- * 构建技能描述
181
- */
182
- _buildSkillsDescription() {
183
- const skillManager = this.framework.pluginManager.get('skill-manager');
184
- if (!skillManager) {
185
- return '';
186
- }
187
-
188
- const skills = skillManager.getAllSkills();
189
- if (!skills || skills.length === 0) {
190
- return '';
191
- }
192
-
193
- let desc = '【可用技能】\n';
194
- for (const skill of skills) {
195
- const name = skill.metadata?.name || skill.name || 'unknown';
196
- const descText = skill.metadata?.description || '';
197
- desc += `- ${name}: ${descText}\n`;
198
- }
199
- desc +=
200
- '\n重要:当需要开发插件、执行专业任务时,必须先使用 loadSkill 工具加载对应技能,获取专业指导。';
201
- return desc.trim();
202
- }
203
-
204
- /**
205
- * 构建系统能力描述
206
- */
207
- _buildCapabilitiesDescription() {
208
- const plugins = this.framework.pluginManager.getAll();
209
- if (!plugins || plugins.length === 0) {
210
- return '';
211
- }
212
-
213
- // 过滤出有描述的关键插件(排除内部插件)
214
- const keyPlugins = plugins.filter((p) => {
215
- const name = p.name;
216
- // 排除默认配置插件和内部插件
217
- return name !== 'defaults' && name !== 'agent';
218
- });
219
-
220
- if (keyPlugins.length === 0) {
221
- return '';
222
- }
223
-
224
- let desc = '【系统能力】\n';
225
- for (const plugin of keyPlugins) {
226
- const name = plugin.instance?.name || plugin.name || 'unknown';
227
- const description = plugin.instance?.description || '无描述';
228
- desc += `- ${name}: ${description}\n`;
229
- }
230
-
231
- return desc.trim();
232
- }
233
-
234
- /**
235
- * 构建子Agent描述
236
- * 动态从配置文件读取每个子Agent的专业领域
237
- */
238
- _buildSubAgentsDescription() {
239
- const subAgentManager = this.framework.pluginManager.get('subagent-manager');
240
- if (!subAgentManager) {
241
- return '';
242
- }
243
- const allSubAgents = subAgentManager.getAllSubAgents();
244
- if (!allSubAgents || allSubAgents.length === 0) {
245
- return '';
246
- }
247
-
248
- let desc = '【子 Agent 匹配表 - 优先使用】\n';
249
-
250
- // 动态从配置文件读取每个子Agent的核心能力
251
- for (const plugin of allSubAgents) {
252
- const name = plugin.name;
253
- const role = plugin.role;
254
- const goal = plugin.description || '';
255
-
256
- // 优先使用 SubAgentConfigManager 获取详细信息
257
- const config = this.framework._subAgentConfigManager?.get(name);
258
- if (config) {
259
- const agentDesc = config.getDescription();
260
- const skills = config.getSkills();
261
- let info = agentDesc || role || goal || '子代理';
262
- if (skills && skills.length > 0) {
263
- info += ` (技能: ${skills.join(', ')})`;
264
- }
265
- desc += ` - ${name}: ${info}\n`;
266
- } else {
267
- // 回退到旧逻辑
268
- desc += ` - ${name}: ${role || goal || '子代理'}\n`;
269
- }
270
- }
271
-
272
- // 通用规则
273
- desc += '\n【子Agent匹配规则 - 必须遵守】\n';
274
- desc += ' - 根据上述【子 Agent 匹配表】,将任务委托给最匹配的子Agent处理\n';
275
- desc += ' - 使用 subagent_call 工具并指定 agentName 来委托任务\n';
276
- desc += ' - 只有当没有匹配的子Agent时,才直接调用工具\n';
277
-
278
- return desc.trim();
279
- }
280
-
281
- /**
282
- * 从配置文件动态读取子Agent的核心能力
283
- * 支持 .json 和 .md 格式
284
- * @private
285
- */
286
- _getSubAgentCapabilities(name) {
287
- try {
288
- const fs = require('fs');
289
- const path = require('path');
290
- const agentsDir = path.join(process.cwd(), '.agent', 'agents');
291
-
292
- // 尝试多种文件格式
293
- const possiblePaths = [
294
- path.join(agentsDir, `${name}.md`),
295
- path.join(agentsDir, `${name}.json`),
296
- ];
297
-
298
- let filePath = null;
299
- for (const p of possiblePaths) {
300
- if (fs.existsSync(p)) {
301
- filePath = p;
302
- break;
303
- }
304
- }
305
-
306
- if (!filePath) {
307
- return null;
308
- }
309
-
310
- const content = fs.readFileSync(filePath, 'utf-8');
311
-
312
- // .json 格式
313
- if (filePath.endsWith('.json')) {
314
- const config = JSON.parse(content);
315
- return this._extractCapabilitiesFromConfig(config);
316
- }
317
-
318
- // .md 格式(YAML front matter + markdown)
319
- if (filePath.endsWith('.md')) {
320
- return this._extractCapabilitiesFromMd(content);
321
- }
322
-
323
- return null;
324
- } catch (e) {
325
- return null;
326
- }
327
- }
328
-
329
- /**
330
- * 从 JSON 配置中提取核心能力
331
- */
332
- _extractCapabilitiesFromConfig(config) {
333
- if (config.instructions) {
334
- const match = config.instructions.match(/【核心能力】([\s\S]*?)(?=【|$)/);
335
- if (match) {
336
- const capabilities = match[1]
337
- .split('\n')
338
- .map((line) => line.replace(/^[·\-*]\s*/, '').trim())
339
- .filter((line) => line && !line.startsWith('你是一个'))
340
- .slice(0, 4)
341
- .join('、');
342
- return capabilities || config.description;
343
- }
344
- return config.description;
345
- }
346
- return config.description || null;
347
- }
348
-
349
- /**
350
- * 从 .md 文件(YAML front matter)中提取核心能力
351
- */
352
- _extractCapabilitiesFromMd(mdContent) {
353
- // 解析 YAML front matter
354
- const frontMatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---/);
355
- if (!frontMatterMatch) {
356
- return null;
357
- }
358
-
359
- const frontMatter = frontMatterMatch[1];
360
- const config = {};
361
-
362
- // 简单解析 YAML front matter
363
- for (const line of frontMatter.split('\n')) {
364
- const colonIndex = line.indexOf(':');
365
- if (colonIndex > 0) {
366
- const key = line.substring(0, colonIndex).trim();
367
- let value = line.substring(colonIndex + 1).trim();
368
- // 移除可能的引号
369
- if ((value.startsWith('"') && value.endsWith('"')) ||
370
- (value.startsWith("'") && value.endsWith("'"))) {
371
- value = value.slice(1, -1);
372
- }
373
- config[key] = value;
374
- }
375
- }
376
- // 从 description 字段提取能力
377
- if (config.description) {
378
- const desc = config.description;
379
- // 按逗号/顿号分隔
380
- const parts = desc.split(/[,,、]/).map(s => s.trim());
381
- // 取第一部分(通常是最核心的能力描述)
382
- const firstPart = parts[0];
383
- // 如果第一部分太长(说明是句子),取前50个字符
384
- if (firstPart.length > 50) {
385
- return firstPart.substring(0, 50).trim() + '...';
386
- }
387
- // 如果有多个部分,取前3个
388
- if (parts.length > 1) {
389
- return parts.slice(0, 3).join('、');
390
- }
391
- return firstPart;
392
- }
393
-
394
- return null;
395
- }
396
-
397
- _buildSystemPrompt() {
398
- // 如果没变脏,返回缓存
399
- if (!this._systemPromptDirty && this._systemPromptCache !== null) {
400
- return this._systemPromptCache;
401
- }
402
-
403
- // 使用 builder 构建系统提示词
404
- this._systemPromptCache = this._systemPromptBuilder.build();
405
- this._systemPromptDirty = false;
406
- return this._systemPromptCache;
407
- }
408
-
409
- /**
410
- * 使 system prompt 缓存失效
411
- * @private
412
- */
413
- _invalidateSystemPromptCache() {
414
- this._systemPromptDirty = true;
415
- // 同时使 builder 中所有部分失效
416
- this._systemPromptBuilder.invalidateAll();
417
- }
418
-
419
- /**
420
- * 注册自定义系统提示词部分(供插件使用)
421
- * @param {string} name - 部分名称
422
- * @param {number} priority - 优先级
423
- * @param {Function} provider - 返回提示词内容的函数
424
- */
425
- registerPromptPart(name, priority, provider) {
426
- this._systemPromptBuilder.register(name, priority, provider);
427
- this._invalidateSystemPromptCache();
428
- return this;
429
- }
430
-
431
- /**
432
- * 注销系统提示词部分
433
- * @param {string} name - 部分名称
434
- */
435
- unregisterPromptPart(name) {
436
- this._systemPromptBuilder.unregister(name);
437
- this._invalidateSystemPromptCache();
438
- return this;
439
- }
440
-
441
- /**
442
- * 使特定系统提示词部分失效
443
- * @param {string} name - 部分名称
444
- */
445
- invalidatePromptPart(name) {
446
- this._systemPromptBuilder.invalidate(name);
447
- this._systemPromptDirty = true;
448
- return this;
449
- }
450
-
451
- /**
452
- * 获取工具调用核心规则
453
- * @private
454
- */
455
- _getToolCoreRules() {
456
- return `【工具调用核心规则】
457
- 1. **子Agent优先**:任务匹配子Agent专业领域时,**必须优先使用** 使用 subagent_call 工具并指定 agentName 委托给对应子Agent处理,而不是直接调用工具。只有当没有匹配的子Agent时,才直接调用工具。
458
- 2. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
459
- 3. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
460
- 4. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
461
- 5. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
462
- 6. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
463
-
464
-
465
- 【响应规范】
466
- - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
467
- - 如果工具返回错误,说明错误原因并给出解决建议
468
- - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
469
-
470
- 【禁止事项】
471
- - 不调用工具就直接回答
472
- - 编造不存在的数据、文件、订单、用户等信息
473
- - 回复含糊不清,让用户无法确定答案是否正确`;
474
- }
475
-
476
- /**
477
- * 刷新上下文
478
- */
479
- _refreshContext() {
480
- this.systemPrompt = this._buildSystemPrompt();
481
- if (this._chatHandler) {
482
- this._chatHandler.setSystemPrompt(this.systemPrompt);
483
- }
484
- }
485
-
486
- /**
487
- * 初始化聊天处理器
488
- * @private
489
- */
490
- _initChatHandler() {
491
- let aiClient = null;
492
- const aiPlugin = this.framework.pluginManager.get('ai');
493
- if (aiPlugin) {
494
- aiClient = aiPlugin.getAIClient();
495
- }
496
-
497
- this._chatHandler = new AgentChatHandler(this, {
498
- model: this.model,
499
- provider: this.provider,
500
- apiKey: this.apiKey,
501
- baseURL: this.baseURL,
502
- providerOptions: this.providerOptions,
503
- // 上下文压缩配置
504
- maxContextTokens: this.config.maxContextTokens,
505
- compressionThreshold: this.config.compressionThreshold,
506
- keepRecentMessages: this.config.keepRecentMessages,
507
- enableSmartCompress: this.config.enableSmartCompress,
508
- });
509
-
510
- if (aiClient) {
511
- this._chatHandler.setAIClient(aiClient);
512
- }
513
-
514
- // 转发事件
515
- this._chatHandler.on('message', (msg) => this.emit('message', msg));
516
- this._chatHandler.on('chunk', (chunk) => this.emit('chunk', chunk));
517
- this._chatHandler.on('tool-call', (tool) => this.emit('tool-call', tool));
518
- this._chatHandler.on('tool-result', (result) => this.emit('tool-result', result));
519
- this._chatHandler.on('error', (err) => this.emit('error', err));
520
-
521
- this._syncTools();
522
- }
523
-
524
- /**
525
- * 设置系统提示
526
- */
527
- setSystemPrompt(prompt) {
528
- this._originalPrompt = prompt;
529
- this.systemPrompt = this._buildSystemPrompt();
530
- if (this._chatHandler) {
531
- this._chatHandler.setSystemPrompt(this.systemPrompt);
532
- }
533
- return this;
534
- }
535
-
536
- /**
537
- * 注册工具到 Agent
538
- */
539
- registerTool(tool) {
540
- this._tools.set(tool.name, tool);
541
- this._invalidateSystemPromptCache();
542
- if (this._chatHandler) {
543
- this._chatHandler.registerTool(tool);
544
- }
545
- this._refreshContext();
546
- return this;
547
- }
548
-
549
- /**
550
- * 获取已注册工具
551
- */
552
- getTools() {
553
- return Array.from(this._tools.values());
554
- }
555
-
556
- /**
557
- * 同步框架中的工具到 Agent
558
- * @private
559
- */
560
- _syncTools() {
561
- if (this.framework.toolRegistry.size() > 0) {
562
- for (const tool of this.framework.getTools()) {
563
- if (!this._tools.has(tool.name)) {
564
- this.registerTool(tool);
565
- }
566
- }
567
- }
568
- }
569
-
570
- /**
571
- * 注册子Agent
572
- * @param {string} name - 子Agent名称
573
- * @param {Agent} agent - 子Agent实例
574
- * @param {string} role - 角色描述
575
- * @param {string} goal - 目标描述
576
- */
577
- registerSubAgent(name, agent, role, goal) {
578
- this._subAgents.set(name, { agent, role, goal });
579
- this._invalidateSystemPromptCache();
580
- this._refreshContext();
581
- return this;
582
- }
583
-
584
- /**
585
- * 注销子Agent
586
- */
587
- unregisterSubAgent(name) {
588
- this._subAgents.delete(name);
589
- this._invalidateSystemPromptCache();
590
- this._refreshContext();
591
- return this;
592
- }
593
-
594
- /**
595
- * 获取所有子Agent
596
- */
597
- getSubAgents() {
598
- return this._subAgents;
599
- }
600
-
601
- /**
602
- * 获取待处理的调度通知并清除(下次不再重复显示)
603
- */
604
- _getAndClearSchedulerNotifications() {
605
- try {
606
- const scheduler = this.framework.pluginManager.get('scheduler');
607
- if (scheduler && scheduler.instance && scheduler.instance.getPendingNotifications) {
608
- const results = scheduler.instance.getPendingNotifications();
609
- if (results.length > 0) {
610
- const notifications = results.slice(-5).reverse(); // 最多5条,最新的在前
611
- // 清除已发送的通知
612
- if (scheduler.instance.clearDeliveredNotifications) {
613
- scheduler.instance.clearDeliveredNotifications(notifications.length);
614
- }
615
- return notifications;
616
- }
617
- }
618
- } catch (err) {
619
- // 忽略错误,避免影响主流程
620
- }
621
- return [];
622
- }
623
-
624
- /**
625
- * 获取待处理的思考结果并清除
626
- */
627
- _getAndClearThinkNotifications() {
628
- try {
629
- const think = this.framework.pluginManager.get('think');
630
- if (think && think.instance && think.instance.getPendingThoughts) {
631
- const thoughts = think.instance.getPendingThoughts();
632
- if (thoughts.length > 0) {
633
- return thoughts.slice(-5).reverse(); // 最多5条,最新的在前
634
- }
635
- }
636
- } catch (err) {
637
- // 忽略错误,避免影响主流程
638
- }
639
- return [];
640
- }
641
-
642
- /**
643
- * 获取所有待处理的系统通知(调度 + 思考)
644
- */
645
- _getAllPendingNotifications() {
646
- const notifications = [];
647
-
648
- // 调度通知
649
- const schedulerNotifs = this._getAndClearSchedulerNotifications();
650
- for (const n of schedulerNotifs) {
651
- notifications.push(
652
- `【定时任务通知】\n任务: ${n.taskName || n.taskId}\n执行时间: ${n.executedAt}\n结果: ${n.result || n.action || '执行完成'}`
653
- );
654
- }
655
-
656
- // 思考通知
657
- const thinkNotifs = this._getAndClearThinkNotifications();
658
- for (const t of thinkNotifs) {
659
- notifications.push(
660
- `【主动思考】\n模式: ${t.mode}\n主题: ${t.topic}\n结果: ${t.result || '思考完成'}`
661
- );
662
- }
663
-
664
- return notifications;
665
- }
666
-
667
- /**
668
- * 发送消息
669
- */
670
- async chat(message, options = {}) {
671
- if (this._status === 'busy') {
672
- throw new Error('Agent is busy');
673
- }
674
-
675
- if (this._status === 'error') {
676
- this._status = 'idle';
677
- }
678
-
679
- this._status = 'busy';
680
- this.emit('status', { status: 'busy' });
681
-
682
- try {
683
- // 检查是否有待处理的系统通知(调度 + 思考)
684
- const notifications = this._getAllPendingNotifications();
685
- let enhancedMessage = message;
686
- if (notifications.length > 0) {
687
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
688
- }
689
-
690
- this._syncTools();
691
-
692
- const result = await this._chatHandler.chat(enhancedMessage, options);
693
- this._status = 'idle';
694
- this.emit('status', { status: 'idle' });
695
-
696
- // 处理队列中的下一条消息
697
- setImmediate(() => this._processQueue());
698
-
699
- return result;
700
- } catch (err) {
701
- this._status = 'error';
702
- this.emit('status', { status: 'error', error: err.message });
703
-
704
- // 发生错误时也要处理队列
705
- setImmediate(() => this._processQueue());
706
-
707
- throw err;
708
- }
709
- }
710
-
711
- /**
712
- * 推送消息(自动继承当前 sessionId 上下文,自动排队)
713
- * 工具中调用此方法,自动带上当前执行上下文的 sessionId
714
- * 如果 agent 忙碌,消息会进入队列等待
715
- * @param {string|Object} message - 消息
716
- * @param {Object} options - 选项 { maxSteps }
717
- * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
718
- */
719
- async pushMessage(message, options = {}) {
720
- // 自动从执行上下文获取 sessionId
721
- const ctx = this.framework.getExecutionContext();
722
- if (ctx?.sessionId && !options.sessionId) {
723
- options.sessionId = ctx.sessionId;
724
- }
725
-
726
- // 如果忙碌,进入队列等待
727
- if (this._status === 'busy') {
728
- const queuedItem = { message, options, resolve: null, reject: null };
729
- const promise = new Promise((resolve, reject) => {
730
- queuedItem.resolve = resolve;
731
- queuedItem.reject = reject;
732
- });
733
- this._messageQueue.push(queuedItem);
734
- // Agent busy, message queued
735
- return promise;
736
- }
737
-
738
- // 空闲则直接处理
739
- return this.chat(message, options);
740
- }
741
-
742
- /**
743
- * 处理消息队列
744
- * @private
745
- */
746
- async _processQueue() {
747
- if (this._isProcessingQueue || this._messageQueue.length === 0) {
748
- return;
749
- }
750
-
751
- this._isProcessingQueue = true;
752
-
753
- // 强制设置为 idle,确保 this.chat() 能执行
754
- this._status = 'idle';
755
-
756
- while (this._messageQueue.length > 0) {
757
- const item = this._messageQueue.shift();
758
- try {
759
- const result = await this.chat(item.message, item.options);
760
- item.resolve(result);
761
- } catch (err) {
762
- item.reject(err);
763
- }
764
- }
765
-
766
- this._isProcessingQueue = false;
767
- }
768
-
769
- /**
770
- * 发送消息(流式)
771
- */
772
- async *chatStream(message, options = {}) {
773
- if (this._status === 'busy') {
774
- throw new Error('Agent is busy');
775
- }
776
-
777
- // 允许从 error 状态重试
778
- if (this._status === 'error') {
779
- this._status = 'idle';
780
- }
781
-
782
- this._status = 'busy';
783
- this.emit('status', { status: 'busy' });
784
-
785
- try {
786
- // 检查是否有待处理的系统通知(调度 + 思考)
787
- const notifications = this._getAllPendingNotifications();
788
- let enhancedMessage = message;
789
- if (notifications.length > 0) {
790
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
791
- }
792
-
793
- this._syncTools();
794
-
795
- yield* this._chatHandler.chatStream(enhancedMessage, options);
796
- this._status = 'idle';
797
- this.emit('status', { status: 'idle' });
798
-
799
- // 处理队列中的下一条消息
800
- setImmediate(() => this._processQueue());
801
- } catch (err) {
802
- this._status = 'error';
803
- this.emit('status', { status: 'error', error: err.message });
804
-
805
- // 发生错误时也要处理队列
806
- setImmediate(() => this._processQueue());
807
-
808
- throw err;
809
- }
810
- }
811
-
812
- /**
813
- * 设置元数据
814
- */
815
- setMetadata(keyOrObj, value) {
816
- if (typeof keyOrObj === 'string') {
817
- this._metadata.set(keyOrObj, value);
818
- } else if (keyOrObj && typeof keyOrObj === 'object') {
819
- for (const [key, val] of Object.entries(keyOrObj)) {
820
- this._metadata.set(key, val);
821
- }
822
- }
823
- this._invalidateSystemPromptCache();
824
- this._refreshContext();
825
- return this;
826
- }
827
-
828
- /**
829
- * 获取元数据
830
- */
831
- getMetadata(key) {
832
- return this._metadata.get(key);
833
- }
834
-
835
- /**
836
- * 删除元数据
837
- */
838
- deleteMetadata(key) {
839
- this._metadata.delete(key);
840
- this._refreshContext();
841
- return this;
842
- }
843
-
844
- /**
845
- * 清空元数据
846
- */
847
- clearMetadata() {
848
- this._metadata.clear();
849
- this._refreshContext();
850
- return this;
851
- }
852
-
853
- /**
854
- * 清空对话历史
855
- */
856
- clearHistory() {
857
- if (this._chatHandler) {
858
- this._chatHandler.clearHistory();
859
- }
860
- return this;
861
- }
862
-
863
- /**
864
- * 获取状态
865
- */
866
- getStatus() {
867
- return this._status;
868
- }
869
-
870
- /**
871
- * 重置状态(从卡住状态恢复)
872
- */
873
- resetStatus() {
874
- this._status = 'idle';
875
- this.emit('status', { status: 'idle' });
876
- return this;
877
- }
878
-
879
- /**
880
- * 销毁 Agent
881
- */
882
- destroy() {
883
- if (this._chatHandler) {
884
- this._chatHandler.destroy();
885
- }
886
- this._tools.clear();
887
- this.removeAllListeners();
888
- this.emit('destroyed');
889
- }
890
- }
891
-
892
- module.exports = { Agent };
1
+ /**
2
+ * Agent 类
3
+ * 负责对话和推理
4
+ */
5
+
6
+ const { EventEmitter } = require('../utils/event-emitter');
7
+ const { AgentChatHandler } = require('./agent-chat');
8
+ const { SystemPromptBuilder } = require('./system-prompt-builder');
9
+ const os = require('os');
10
+
11
+ class Agent extends EventEmitter {
12
+ /**
13
+ * @param {Framework} framework - 框架实例
14
+ * @param {Object} config - 配置
15
+ * @param {string} [config.name] - Agent 名称
16
+ * @param {string} [config.systemPrompt] - 系统提示
17
+ * @param {string} [config.sharedPrompt] - 共享提示模板,支持 {{VAR}} 占位符
18
+ * @param {Object} [config.metadata] - 元数据,注入到 sharedPrompt
19
+ * @param {boolean} [config.enableToolRouting=true] - 是否启用工具路由
20
+ */
21
+ constructor(framework, config = {}) {
22
+ super();
23
+
24
+ this.framework = framework;
25
+ this.config = config;
26
+
27
+ this.name = config.name || 'Agent';
28
+ this.model = config.model || 'deepseek-chat';
29
+ this.apiKey = config.apiKey;
30
+ this.baseURL = config.baseURL;
31
+ this.provider = config.provider || 'deepseek';
32
+ this.providerOptions = config.providerOptions || {};
33
+ this.providerOptions.maxOutputTokens = 8192;
34
+ this.providerOptions.temperature = 0.3; // 降低 temperature 减少生成错误 JSON 的概率
35
+ // 原始 system prompt
36
+ this._originalPrompt =
37
+ config.systemPrompt ||
38
+ '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。';
39
+
40
+ // 共享提示模板
41
+ this._sharedPrompt = config.sharedPrompt || '';
42
+
43
+ // 元数据
44
+ const metadata = config.metadata || {};
45
+ this._metadata = new Map(Object.entries(metadata));
46
+
47
+ this._chatHandler = null;
48
+ this._tools = new Map();
49
+ this._status = 'idle';
50
+
51
+ // 子Agent管理
52
+ this._subAgents = new Map();
53
+
54
+ // 消息队列(用于 pushMessage)
55
+ this._messageQueue = [];
56
+ this._isProcessingQueue = false;
57
+
58
+ // System prompt 构建器
59
+ this._systemPromptBuilder = new SystemPromptBuilder();
60
+ this._registerDefaultPromptParts();
61
+
62
+ // 处理后的 system prompt (带上下文)
63
+ this.systemPrompt = this._buildSystemPrompt();
64
+
65
+ // 初始化聊天处理器
66
+ this._initChatHandler();
67
+ }
68
+
69
+ /**
70
+ * 注册默认的系统提示词部分
71
+ * @private
72
+ */
73
+ _registerDefaultPromptParts() {
74
+ // 1. 原始 system prompt (优先级 100)
75
+ this._systemPromptBuilder.register('original-prompt', 100, () => this._originalPrompt);
76
+
77
+ // 2. 共享提示模板 (优先级 200)
78
+ this._systemPromptBuilder.register('shared-prompt', 200, () => {
79
+ if (this._sharedPrompt) {
80
+ return this._replacePlaceholders(this._sharedPrompt);
81
+ }
82
+ return null;
83
+ });
84
+
85
+ // 3. 元数据 (优先级 300)
86
+ this._systemPromptBuilder.register('metadata', 300, () => {
87
+ if (this._metadata.size === 0) {
88
+ return null;
89
+ }
90
+ const metaParts = ['【元数据】'];
91
+ for (const [key, value] of this._metadata) {
92
+ if (typeof value === 'object') {
93
+ metaParts.push(`- ${key}: ${JSON.stringify(value)}`);
94
+ } else {
95
+ metaParts.push(`- ${key}: ${value}`);
96
+ }
97
+ }
98
+ return metaParts.join('\n');
99
+ });
100
+
101
+ // 4. 工具列表 (优先级 400)
102
+ this._systemPromptBuilder.register('tools', 400, () => this._buildToolsDescription());
103
+
104
+ // 5. 技能列表 (优先级 500)
105
+ this._systemPromptBuilder.register('skills', 500, () => this._buildSkillsDescription());
106
+
107
+ // 6. 子Agent列表 (优先级 600)
108
+ this._systemPromptBuilder.register('subagents', 600, () => this._buildSubAgentsDescription());
109
+
110
+ // 7. 系统能力 (优先级 700)
111
+ this._systemPromptBuilder.register('capabilities', 700, () => this._buildCapabilitiesDescription());
112
+
113
+ // 8. 工具调用核心规则 (优先级 1000)
114
+ this._systemPromptBuilder.register('tool-core-rules', 1000, () => this._getToolCoreRules());
115
+ }
116
+
117
+ /**
118
+ * 获取元数据值
119
+ */
120
+ _getMetadataValue(key) {
121
+ // 优先从 metadata 获取
122
+ if (this._metadata.has(key)) {
123
+ return this._metadata.get(key);
124
+ }
125
+
126
+ // 内置变量
127
+ switch (key) {
128
+ case 'WORK_DIR':
129
+ case 'CWD':
130
+ return process.cwd();
131
+ case 'HOME_DIR':
132
+ return os.homedir();
133
+ case 'HOST_NAME':
134
+ return os.hostname();
135
+ case 'PLATFORM':
136
+ return process.platform;
137
+ case 'TIME':
138
+ return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
139
+ case 'DATE':
140
+ return new Date().toISOString().split('T')[0];
141
+ default:
142
+ return `{{${key}}}`;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * 替换 sharedPrompt 中的占位符
148
+ */
149
+ _replacePlaceholders(template) {
150
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
151
+ return this._getMetadataValue(key);
152
+ });
153
+ }
154
+
155
+ /**
156
+ * 构建工具描述
157
+ */
158
+ _buildToolsDescription() {
159
+ if (this._tools.size === 0) {
160
+ return '';
161
+ }
162
+
163
+ // 需要排除的子Agent相关工具(它们通过专门的子Agent部分提供)
164
+ // const excludedTools = new Set(['subagent_call', 'subagent_list', 'subagent_reload']);
165
+
166
+ let desc = '【可用工具】\n';
167
+ for (const [name, tool] of this._tools) {
168
+ // 跳过没有描述的工具(对LLM无帮助)
169
+ if (!tool.description) continue;
170
+ // // 跳过子Agent相关工具(通过专门的子Agent部分提供)
171
+ // if (excludedTools.has(name)) continue;
172
+ // // 跳过子Agent委托工具(通过专门的子Agent部分提供)
173
+ // if (this._subAgents.has(name)) continue;
174
+ desc += `- ${name}: ${tool.description}\n`;
175
+ }
176
+ return desc.trim();
177
+ }
178
+
179
+ /**
180
+ * 构建技能描述
181
+ */
182
+ _buildSkillsDescription() {
183
+ const skillManager = this.framework.pluginManager.get('skill-manager');
184
+ if (!skillManager) {
185
+ return '';
186
+ }
187
+
188
+ const skills = skillManager.getAllSkills();
189
+ if (!skills || skills.length === 0) {
190
+ return '';
191
+ }
192
+
193
+ let desc = '【可用技能】\n';
194
+ for (const skill of skills) {
195
+ const name = skill.metadata?.name || skill.name || 'unknown';
196
+ const descText = skill.metadata?.description || '';
197
+ desc += `- ${name}: ${descText}\n`;
198
+ }
199
+ desc +=
200
+ '\n重要:当需要开发插件、执行专业任务时,必须先使用 loadSkill 工具加载对应技能,获取专业指导。';
201
+ return desc.trim();
202
+ }
203
+
204
+ /**
205
+ * 构建系统能力描述
206
+ */
207
+ _buildCapabilitiesDescription() {
208
+ const plugins = this.framework.pluginManager.getAll();
209
+ if (!plugins || plugins.length === 0) {
210
+ return '';
211
+ }
212
+
213
+ // 过滤出有描述的关键插件(排除内部插件)
214
+ const keyPlugins = plugins.filter((p) => {
215
+ const name = p.name;
216
+ // 排除默认配置插件和内部插件
217
+ return name !== 'defaults' && name !== 'agent';
218
+ });
219
+
220
+ if (keyPlugins.length === 0) {
221
+ return '';
222
+ }
223
+
224
+ let desc = '【系统能力】\n';
225
+ for (const plugin of keyPlugins) {
226
+ const name = plugin.instance?.name || plugin.name || 'unknown';
227
+ const description = plugin.instance?.description || '无描述';
228
+ desc += `- ${name}: ${description}\n`;
229
+ }
230
+
231
+ return desc.trim();
232
+ }
233
+
234
+ /**
235
+ * 构建子Agent描述
236
+ * 动态从配置文件读取每个子Agent的专业领域
237
+ */
238
+ _buildSubAgentsDescription() {
239
+ const subAgentManager = this.framework.pluginManager.get('subagent-manager');
240
+ if (!subAgentManager) {
241
+ return '';
242
+ }
243
+ const allSubAgents = subAgentManager.getAllSubAgents();
244
+ if (!allSubAgents || allSubAgents.length === 0) {
245
+ return '';
246
+ }
247
+
248
+ let desc = '【子 Agent 匹配表 - 优先使用】\n';
249
+
250
+ // 动态从配置文件读取每个子Agent的核心能力
251
+ for (const plugin of allSubAgents) {
252
+ const name = plugin.name;
253
+ const role = plugin.role;
254
+ const goal = plugin.description || '';
255
+
256
+ // 优先使用 SubAgentConfigManager 获取详细信息
257
+ const config = this.framework._subAgentConfigManager?.get(name);
258
+ if (config) {
259
+ const agentDesc = config.getDescription();
260
+ const skills = config.getSkills();
261
+ let info = agentDesc || role || goal || '子代理';
262
+ if (skills && skills.length > 0) {
263
+ info += ` (技能: ${skills.join(', ')})`;
264
+ }
265
+ desc += ` - ${name}: ${info}\n`;
266
+ } else {
267
+ // 回退到旧逻辑
268
+ desc += ` - ${name}: ${role || goal || '子代理'}\n`;
269
+ }
270
+ }
271
+
272
+ // 通用规则
273
+ desc += '\n【子Agent匹配规则 - 必须遵守】\n';
274
+ desc += ' - 根据上述【子 Agent 匹配表】,将任务委托给最匹配的子Agent处理\n';
275
+ desc += ' - 使用 subagent_call 工具并指定 agentName 来委托任务\n';
276
+ desc += ' - 只有当没有匹配的子Agent时,才直接调用工具\n';
277
+
278
+ return desc.trim();
279
+ }
280
+
281
+ /**
282
+ * 从配置文件动态读取子Agent的核心能力
283
+ * 支持 .json 和 .md 格式
284
+ * @private
285
+ */
286
+ _getSubAgentCapabilities(name) {
287
+ try {
288
+ const fs = require('fs');
289
+ const path = require('path');
290
+ const agentsDir = path.join(process.cwd(), '.agent', 'agents');
291
+
292
+ // 尝试多种文件格式
293
+ const possiblePaths = [
294
+ path.join(agentsDir, `${name}.md`),
295
+ path.join(agentsDir, `${name}.json`),
296
+ ];
297
+
298
+ let filePath = null;
299
+ for (const p of possiblePaths) {
300
+ if (fs.existsSync(p)) {
301
+ filePath = p;
302
+ break;
303
+ }
304
+ }
305
+
306
+ if (!filePath) {
307
+ return null;
308
+ }
309
+
310
+ const content = fs.readFileSync(filePath, 'utf-8');
311
+
312
+ // .json 格式
313
+ if (filePath.endsWith('.json')) {
314
+ const config = JSON.parse(content);
315
+ return this._extractCapabilitiesFromConfig(config);
316
+ }
317
+
318
+ // .md 格式(YAML front matter + markdown)
319
+ if (filePath.endsWith('.md')) {
320
+ return this._extractCapabilitiesFromMd(content);
321
+ }
322
+
323
+ return null;
324
+ } catch (e) {
325
+ return null;
326
+ }
327
+ }
328
+
329
+ /**
330
+ * 从 JSON 配置中提取核心能力
331
+ */
332
+ _extractCapabilitiesFromConfig(config) {
333
+ if (config.instructions) {
334
+ const match = config.instructions.match(/【核心能力】([\s\S]*?)(?=【|$)/);
335
+ if (match) {
336
+ const capabilities = match[1]
337
+ .split('\n')
338
+ .map((line) => line.replace(/^[·\-*]\s*/, '').trim())
339
+ .filter((line) => line && !line.startsWith('你是一个'))
340
+ .slice(0, 4)
341
+ .join('、');
342
+ return capabilities || config.description;
343
+ }
344
+ return config.description;
345
+ }
346
+ return config.description || null;
347
+ }
348
+
349
+ /**
350
+ * 从 .md 文件(YAML front matter)中提取核心能力
351
+ */
352
+ _extractCapabilitiesFromMd(mdContent) {
353
+ // 解析 YAML front matter
354
+ const frontMatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---/);
355
+ if (!frontMatterMatch) {
356
+ return null;
357
+ }
358
+
359
+ const frontMatter = frontMatterMatch[1];
360
+ const config = {};
361
+
362
+ // 简单解析 YAML front matter
363
+ for (const line of frontMatter.split('\n')) {
364
+ const colonIndex = line.indexOf(':');
365
+ if (colonIndex > 0) {
366
+ const key = line.substring(0, colonIndex).trim();
367
+ let value = line.substring(colonIndex + 1).trim();
368
+ // 移除可能的引号
369
+ if ((value.startsWith('"') && value.endsWith('"')) ||
370
+ (value.startsWith("'") && value.endsWith("'"))) {
371
+ value = value.slice(1, -1);
372
+ }
373
+ config[key] = value;
374
+ }
375
+ }
376
+ // 从 description 字段提取能力
377
+ if (config.description) {
378
+ const desc = config.description;
379
+ // 按逗号/顿号分隔
380
+ const parts = desc.split(/[,,、]/).map(s => s.trim());
381
+ // 取第一部分(通常是最核心的能力描述)
382
+ const firstPart = parts[0];
383
+ // 如果第一部分太长(说明是句子),取前50个字符
384
+ if (firstPart.length > 50) {
385
+ return firstPart.substring(0, 50).trim() + '...';
386
+ }
387
+ // 如果有多个部分,取前3个
388
+ if (parts.length > 1) {
389
+ return parts.slice(0, 3).join('、');
390
+ }
391
+ return firstPart;
392
+ }
393
+
394
+ return null;
395
+ }
396
+
397
+ _buildSystemPrompt() {
398
+ // 如果没变脏,返回缓存
399
+ if (!this._systemPromptDirty && this._systemPromptCache !== null) {
400
+ return this._systemPromptCache;
401
+ }
402
+
403
+ // 使用 builder 构建系统提示词
404
+ this._systemPromptCache = this._systemPromptBuilder.build();
405
+ this._systemPromptDirty = false;
406
+ return this._systemPromptCache;
407
+ }
408
+
409
+ /**
410
+ * 使 system prompt 缓存失效
411
+ * @private
412
+ */
413
+ _invalidateSystemPromptCache() {
414
+ this._systemPromptDirty = true;
415
+ // 同时使 builder 中所有部分失效
416
+ this._systemPromptBuilder.invalidateAll();
417
+ }
418
+
419
+ /**
420
+ * 注册自定义系统提示词部分(供插件使用)
421
+ * @param {string} name - 部分名称
422
+ * @param {number} priority - 优先级
423
+ * @param {Function} provider - 返回提示词内容的函数
424
+ */
425
+ registerPromptPart(name, priority, provider) {
426
+ this._systemPromptBuilder.register(name, priority, provider);
427
+ this._invalidateSystemPromptCache();
428
+ return this;
429
+ }
430
+
431
+ /**
432
+ * 注销系统提示词部分
433
+ * @param {string} name - 部分名称
434
+ */
435
+ unregisterPromptPart(name) {
436
+ this._systemPromptBuilder.unregister(name);
437
+ this._invalidateSystemPromptCache();
438
+ return this;
439
+ }
440
+
441
+ /**
442
+ * 使特定系统提示词部分失效
443
+ * @param {string} name - 部分名称
444
+ */
445
+ invalidatePromptPart(name) {
446
+ this._systemPromptBuilder.invalidate(name);
447
+ this._systemPromptDirty = true;
448
+ return this;
449
+ }
450
+
451
+ /**
452
+ * 获取工具调用核心规则
453
+ * @private
454
+ */
455
+ _getToolCoreRules() {
456
+ return `【工具调用核心规则】
457
+ 1. **子Agent优先**:任务匹配子Agent专业领域时,**必须优先使用** 使用 subagent_call 工具并指定 agentName 委托给对应子Agent处理,而不是直接调用工具。只有当没有匹配的子Agent时,才直接调用工具。
458
+ 2. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
459
+ 3. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
460
+ 4. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
461
+ 5. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
462
+ 6. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
463
+
464
+
465
+ 【响应规范】
466
+ - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
467
+ - 如果工具返回错误,说明错误原因并给出解决建议
468
+ - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
469
+
470
+ 【禁止事项】
471
+ - 不调用工具就直接回答
472
+ - 编造不存在的数据、文件、订单、用户等信息
473
+ - 回复含糊不清,让用户无法确定答案是否正确`;
474
+ }
475
+
476
+ /**
477
+ * 刷新上下文
478
+ */
479
+ _refreshContext() {
480
+ this.systemPrompt = this._buildSystemPrompt();
481
+ if (this._chatHandler) {
482
+ this._chatHandler.setSystemPrompt(this.systemPrompt);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * 初始化聊天处理器
488
+ * @private
489
+ */
490
+ _initChatHandler() {
491
+ let aiClient = null;
492
+ const aiPlugin = this.framework.pluginManager.get('ai');
493
+ if (aiPlugin) {
494
+ aiClient = aiPlugin.getAIClient();
495
+ }
496
+
497
+ this._chatHandler = new AgentChatHandler(this, {
498
+ model: this.model,
499
+ provider: this.provider,
500
+ apiKey: this.apiKey,
501
+ baseURL: this.baseURL,
502
+ providerOptions: this.providerOptions,
503
+ // 上下文压缩配置
504
+ maxContextTokens: this.config.maxContextTokens,
505
+ compressionThreshold: this.config.compressionThreshold,
506
+ keepRecentMessages: this.config.keepRecentMessages,
507
+ enableSmartCompress: this.config.enableSmartCompress,
508
+ });
509
+
510
+ if (aiClient) {
511
+ this._chatHandler.setAIClient(aiClient);
512
+ }
513
+
514
+ // 转发事件
515
+ this._chatHandler.on('message', (msg) => this.emit('message', msg));
516
+ this._chatHandler.on('chunk', (chunk) => this.emit('chunk', chunk));
517
+ this._chatHandler.on('tool-call', (tool) => this.emit('tool-call', tool));
518
+ this._chatHandler.on('tool-result', (result) => this.emit('tool-result', result));
519
+ this._chatHandler.on('error', (err) => this.emit('error', err));
520
+
521
+ this._syncTools();
522
+ }
523
+
524
+ /**
525
+ * 设置系统提示
526
+ */
527
+ setSystemPrompt(prompt) {
528
+ this._originalPrompt = prompt;
529
+ this.systemPrompt = this._buildSystemPrompt();
530
+ if (this._chatHandler) {
531
+ this._chatHandler.setSystemPrompt(this.systemPrompt);
532
+ }
533
+ return this;
534
+ }
535
+
536
+ /**
537
+ * 注册工具到 Agent
538
+ */
539
+ registerTool(tool) {
540
+ this._tools.set(tool.name, tool);
541
+ this._invalidateSystemPromptCache();
542
+ if (this._chatHandler) {
543
+ this._chatHandler.registerTool(tool);
544
+ }
545
+ this._refreshContext();
546
+ return this;
547
+ }
548
+
549
+ /**
550
+ * 获取已注册工具
551
+ */
552
+ getTools() {
553
+ return Array.from(this._tools.values());
554
+ }
555
+
556
+ /**
557
+ * 同步框架中的工具到 Agent
558
+ * @private
559
+ */
560
+ _syncTools() {
561
+ if (this.framework.toolRegistry.size() > 0) {
562
+ for (const tool of this.framework.getTools()) {
563
+ if (!this._tools.has(tool.name)) {
564
+ this.registerTool(tool);
565
+ }
566
+ }
567
+ }
568
+ }
569
+
570
+ /**
571
+ * 注册子Agent
572
+ * @param {string} name - 子Agent名称
573
+ * @param {Agent} agent - 子Agent实例
574
+ * @param {string} role - 角色描述
575
+ * @param {string} goal - 目标描述
576
+ */
577
+ registerSubAgent(name, agent, role, goal) {
578
+ this._subAgents.set(name, { agent, role, goal });
579
+ this._invalidateSystemPromptCache();
580
+ this._refreshContext();
581
+ return this;
582
+ }
583
+
584
+ /**
585
+ * 注销子Agent
586
+ */
587
+ unregisterSubAgent(name) {
588
+ this._subAgents.delete(name);
589
+ this._invalidateSystemPromptCache();
590
+ this._refreshContext();
591
+ return this;
592
+ }
593
+
594
+ /**
595
+ * 获取所有子Agent
596
+ */
597
+ getSubAgents() {
598
+ return this._subAgents;
599
+ }
600
+
601
+ /**
602
+ * 获取待处理的调度通知并清除(下次不再重复显示)
603
+ */
604
+ _getAndClearSchedulerNotifications() {
605
+ try {
606
+ const scheduler = this.framework.pluginManager.get('scheduler');
607
+ if (scheduler && scheduler.instance && scheduler.instance.getPendingNotifications) {
608
+ const results = scheduler.instance.getPendingNotifications();
609
+ if (results.length > 0) {
610
+ const notifications = results.slice(-5).reverse(); // 最多5条,最新的在前
611
+ // 清除已发送的通知
612
+ if (scheduler.instance.clearDeliveredNotifications) {
613
+ scheduler.instance.clearDeliveredNotifications(notifications.length);
614
+ }
615
+ return notifications;
616
+ }
617
+ }
618
+ } catch (err) {
619
+ // 忽略错误,避免影响主流程
620
+ }
621
+ return [];
622
+ }
623
+
624
+ /**
625
+ * 获取待处理的思考结果并清除
626
+ */
627
+ _getAndClearThinkNotifications() {
628
+ try {
629
+ const think = this.framework.pluginManager.get('think');
630
+ if (think && think.instance && think.instance.getPendingThoughts) {
631
+ const thoughts = think.instance.getPendingThoughts();
632
+ if (thoughts.length > 0) {
633
+ return thoughts.slice(-5).reverse(); // 最多5条,最新的在前
634
+ }
635
+ }
636
+ } catch (err) {
637
+ // 忽略错误,避免影响主流程
638
+ }
639
+ return [];
640
+ }
641
+
642
+ /**
643
+ * 获取所有待处理的系统通知(调度 + 思考)
644
+ */
645
+ _getAllPendingNotifications() {
646
+ const notifications = [];
647
+
648
+ // 调度通知
649
+ const schedulerNotifs = this._getAndClearSchedulerNotifications();
650
+ for (const n of schedulerNotifs) {
651
+ notifications.push(
652
+ `【定时任务通知】\n任务: ${n.taskName || n.taskId}\n执行时间: ${n.executedAt}\n结果: ${n.result || n.action || '执行完成'}`
653
+ );
654
+ }
655
+
656
+ // 思考通知
657
+ const thinkNotifs = this._getAndClearThinkNotifications();
658
+ for (const t of thinkNotifs) {
659
+ notifications.push(
660
+ `【主动思考】\n模式: ${t.mode}\n主题: ${t.topic}\n结果: ${t.result || '思考完成'}`
661
+ );
662
+ }
663
+
664
+ return notifications;
665
+ }
666
+
667
+ /**
668
+ * 发送消息
669
+ */
670
+ async chat(message, options = {}) {
671
+ if (this._status === 'busy') {
672
+ throw new Error('Agent is busy');
673
+ }
674
+
675
+ if (this._status === 'error') {
676
+ this._status = 'idle';
677
+ }
678
+
679
+ this._status = 'busy';
680
+ this.emit('status', { status: 'busy' });
681
+
682
+ try {
683
+ // 检查是否有待处理的系统通知(调度 + 思考)
684
+ const notifications = this._getAllPendingNotifications();
685
+ let enhancedMessage = message;
686
+ if (notifications.length > 0) {
687
+ enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
688
+ }
689
+
690
+ this._syncTools();
691
+
692
+ const result = await this._chatHandler.chat(enhancedMessage, options);
693
+ this._status = 'idle';
694
+ this.emit('status', { status: 'idle' });
695
+
696
+ // 处理队列中的下一条消息
697
+ setImmediate(() => this._processQueue());
698
+
699
+ return result;
700
+ } catch (err) {
701
+ this._status = 'error';
702
+ this.emit('status', { status: 'error', error: err.message });
703
+
704
+ // 发生错误时也要处理队列
705
+ setImmediate(() => this._processQueue());
706
+
707
+ throw err;
708
+ }
709
+ }
710
+
711
+ /**
712
+ * 推送消息(自动继承当前 sessionId 上下文,自动排队)
713
+ * 工具中调用此方法,自动带上当前执行上下文的 sessionId
714
+ * 如果 agent 忙碌,消息会进入队列等待
715
+ * @param {string|Object} message - 消息
716
+ * @param {Object} options - 选项 { maxSteps }
717
+ * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
718
+ */
719
+ async pushMessage(message, options = {}) {
720
+ // 自动从执行上下文获取 sessionId
721
+ const ctx = this.framework.getExecutionContext();
722
+ if (ctx?.sessionId && !options.sessionId) {
723
+ options.sessionId = ctx.sessionId;
724
+ }
725
+
726
+ // 如果忙碌,进入队列等待
727
+ if (this._status === 'busy') {
728
+ const queuedItem = { message, options, resolve: null, reject: null };
729
+ const promise = new Promise((resolve, reject) => {
730
+ queuedItem.resolve = resolve;
731
+ queuedItem.reject = reject;
732
+ });
733
+ this._messageQueue.push(queuedItem);
734
+ // Agent busy, message queued
735
+ return promise;
736
+ }
737
+
738
+ // 空闲则直接处理
739
+ return this.chat(message, options);
740
+ }
741
+
742
+ /**
743
+ * 处理消息队列
744
+ * @private
745
+ */
746
+ async _processQueue() {
747
+ if (this._isProcessingQueue || this._messageQueue.length === 0) {
748
+ return;
749
+ }
750
+
751
+ this._isProcessingQueue = true;
752
+
753
+ // 强制设置为 idle,确保 this.chat() 能执行
754
+ this._status = 'idle';
755
+
756
+ while (this._messageQueue.length > 0) {
757
+ const item = this._messageQueue.shift();
758
+ try {
759
+ const result = await this.chat(item.message, item.options);
760
+ item.resolve(result);
761
+ } catch (err) {
762
+ item.reject(err);
763
+ }
764
+ }
765
+
766
+ this._isProcessingQueue = false;
767
+ }
768
+
769
+ /**
770
+ * 发送消息(流式)
771
+ */
772
+ async *chatStream(message, options = {}) {
773
+ if (this._status === 'busy') {
774
+ throw new Error('Agent is busy');
775
+ }
776
+
777
+ // 允许从 error 状态重试
778
+ if (this._status === 'error') {
779
+ this._status = 'idle';
780
+ }
781
+
782
+ this._status = 'busy';
783
+ this.emit('status', { status: 'busy' });
784
+
785
+ try {
786
+ // 检查是否有待处理的系统通知(调度 + 思考)
787
+ const notifications = this._getAllPendingNotifications();
788
+ let enhancedMessage = message;
789
+ if (notifications.length > 0) {
790
+ enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
791
+ }
792
+
793
+ this._syncTools();
794
+
795
+ yield* this._chatHandler.chatStream(enhancedMessage, options);
796
+ this._status = 'idle';
797
+ this.emit('status', { status: 'idle' });
798
+
799
+ // 处理队列中的下一条消息
800
+ setImmediate(() => this._processQueue());
801
+ } catch (err) {
802
+ this._status = 'error';
803
+ this.emit('status', { status: 'error', error: err.message });
804
+
805
+ // 发生错误时也要处理队列
806
+ setImmediate(() => this._processQueue());
807
+
808
+ throw err;
809
+ }
810
+ }
811
+
812
+ /**
813
+ * 设置元数据
814
+ */
815
+ setMetadata(keyOrObj, value) {
816
+ if (typeof keyOrObj === 'string') {
817
+ this._metadata.set(keyOrObj, value);
818
+ } else if (keyOrObj && typeof keyOrObj === 'object') {
819
+ for (const [key, val] of Object.entries(keyOrObj)) {
820
+ this._metadata.set(key, val);
821
+ }
822
+ }
823
+ this._invalidateSystemPromptCache();
824
+ this._refreshContext();
825
+ return this;
826
+ }
827
+
828
+ /**
829
+ * 获取元数据
830
+ */
831
+ getMetadata(key) {
832
+ return this._metadata.get(key);
833
+ }
834
+
835
+ /**
836
+ * 删除元数据
837
+ */
838
+ deleteMetadata(key) {
839
+ this._metadata.delete(key);
840
+ this._refreshContext();
841
+ return this;
842
+ }
843
+
844
+ /**
845
+ * 清空元数据
846
+ */
847
+ clearMetadata() {
848
+ this._metadata.clear();
849
+ this._refreshContext();
850
+ return this;
851
+ }
852
+
853
+ /**
854
+ * 清空对话历史
855
+ */
856
+ clearHistory() {
857
+ if (this._chatHandler) {
858
+ this._chatHandler.clearHistory();
859
+ }
860
+ return this;
861
+ }
862
+
863
+ /**
864
+ * 获取状态
865
+ */
866
+ getStatus() {
867
+ return this._status;
868
+ }
869
+
870
+ /**
871
+ * 重置状态(从卡住状态恢复)
872
+ */
873
+ resetStatus() {
874
+ this._status = 'idle';
875
+ this.emit('status', { status: 'idle' });
876
+ return this;
877
+ }
878
+
879
+ /**
880
+ * 销毁 Agent
881
+ */
882
+ destroy() {
883
+ if (this._chatHandler) {
884
+ this._chatHandler.destroy();
885
+ }
886
+ this._tools.clear();
887
+ this.removeAllListeners();
888
+ this.emit('destroyed');
889
+ }
890
+ }
891
+
892
+ module.exports = { Agent };