foliko 1.1.6 → 1.1.7

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 (79) hide show
  1. package/.agent/data/email/processed-emails.json +1 -0
  2. package/.agent/data/plugins-state.json +5 -1
  3. package/.agent/data/web/web-config.json +5 -0
  4. package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +15 -0
  5. package/.agent/memory/feedback/mnt88ja3-al4fuy.md +9 -0
  6. package/.agent/plugins/test-plugin.py +108 -0
  7. package/.agent/sessions/cli_default.json +514 -5298
  8. package/.claude/settings.local.json +2 -1
  9. package/SPEC.md +735 -696
  10. package/output/zen_silence.png +0 -0
  11. package/package.json +2 -2
  12. package/plugins/ambient-agent/EventWatcher.js +33 -37
  13. package/plugins/ambient-agent/ExplorerLoop.js +338 -36
  14. package/plugins/ambient-agent/GoalManager.js +7 -3
  15. package/plugins/ambient-agent/StateStore.js +30 -1
  16. package/plugins/ambient-agent/constants.js +15 -1
  17. package/plugins/ambient-agent/index.js +26 -33
  18. package/plugins/coordinator-plugin.js +3 -3
  19. package/plugins/default-plugins.js +2 -2
  20. package/plugins/email/index.js +150 -36
  21. package/plugins/email/monitor.js +79 -5
  22. package/plugins/email/reply.js +15 -25
  23. package/plugins/extension-executor-plugin.js +160 -31
  24. package/plugins/file-system-plugin.js +57 -24
  25. package/plugins/memory-plugin.js +176 -64
  26. package/plugins/python-plugin-loader.js +79 -9
  27. package/plugins/scheduler-plugin.js +64 -24
  28. package/plugins/think-plugin.js +7 -2
  29. package/plugins/web-plugin.js +263 -4
  30. package/skills/ambient-agent/SKILL.md +342 -314
  31. package/src/core/agent-chat.js +64 -9
  32. package/src/core/agent.js +118 -59
  33. package/src/core/tool-registry.js +5 -5
  34. package/src/executors/mcp-executor.js +188 -26
  35. package/src/utils/id.js +5 -0
  36. package/system.md +3480 -0
  37. package/.agent/data/ambient/goals.json +0 -50
  38. package/.agent/data/ambient/memories.json +0 -7
  39. package/.agent/memory/core.md +0 -1
  40. package/.agent/memory/feedback/mnrsiuoc-e1ru74.md +0 -9
  41. package/.agent/memory/feedback/mnrt2mmz-98az6n.md +0 -9
  42. package/.agent/memory/feedback/mnrtqrhm-kxsicz.md +0 -9
  43. package/.agent/memory/feedback/mnrts8vg-i0ngzp.md +0 -15
  44. package/.agent/memory/feedback/mnrtt7jt-c0trb2.md +0 -9
  45. package/.agent/memory/feedback/mnruc2f0-5s52la.md +0 -16
  46. package/.agent/memory/feedback/mnrumbmx-63sa0v.md +0 -9
  47. package/.agent/memory/project/mnn93ogy-ypjn27.md +0 -9
  48. package/.agent/memory/project/mnn98fqy-5nhc1u.md +0 -25
  49. package/.agent/memory/project/mnrp7p5n-8enm2a.md +0 -31
  50. package/.agent/memory/project/mnrp9ifb-yynks0.md +0 -40
  51. package/.agent/memory/project/mnrpb3b8-f617s4.md +0 -25
  52. package/.agent/memory/project/mnrrmqgg-focprv.md +0 -9
  53. package/.agent/memory/project/mnrtykbh-6atsor.md +0 -9
  54. package/.agent/memory/project/mnru9jiu-kgau16.md +0 -35
  55. package/.agent/memory/reference/mnq3oenw-46haj6.md +0 -63
  56. package/.agent/memory/reference/mnq5qxm2-mjoooh.md +0 -116
  57. package/.agent/memory/reference/mnrnvpwo-rcqv9m.md +0 -52
  58. package/.agent/memory/reference/mnrovxvz-zy9xqm.md +0 -25
  59. package/.agent/memory/reference/mnroxabj-1b3930.md +0 -68
  60. package/.agent/memory/reference/mnrpjtlp-mnb9od.md +0 -35
  61. package/.agent/memory/reference/mnrps1x3-6b8xfm.md +0 -28
  62. package/.agent/memory/reference/mnrpt9ov-15er5w.md +0 -22
  63. package/.agent/memory/reference/mnrq82dn-y9tv9e.md +0 -50
  64. package/.agent/memory/reference/mnrqnr5v-v75drf.md +0 -34
  65. package/.agent/memory/reference/mnrrfzys-urudaf.md +0 -31
  66. package/.agent/memory/reference/mnrrocha-t0027n.md +0 -21
  67. package/.agent/memory/reference/mnrukklc-bxndsb.md +0 -35
  68. package/.agent/memory/user/mnm67t9m-x8rekk.md +0 -9
  69. package/.agent/memory/user/mnn5mmqh-w6aktx.md +0 -11
  70. package/.agent/memory/user/mnnbfhhn-dk1bd1.md +0 -22
  71. package/.agent/memory/user/mnrt39t8-8eosy0.md +0 -9
  72. package/foliko-cloud-rising.png +0 -0
  73. package/foliko-dawn-of-ai.png +0 -0
  74. package/foliko-mindful-observation.png +0 -0
  75. package/foliko-stellar-dreams.png +0 -0
  76. package/foliko-zen-jing.png +0 -0
  77. package/foliko-zen-kong.png +0 -0
  78. package/foliko-zen-wu.png +0 -0
  79. package/zen_karesansui.png +0 -0
@@ -5,7 +5,7 @@
5
5
 
6
6
  const { EventEmitter } = require('../utils/event-emitter');
7
7
  const { logger } = require('../utils/logger');
8
- const { generateText, stepCountIs } = require('ai');
8
+ const { generateText, stepCountIs, isLoopFinished } = require('ai');
9
9
  const { prepareMessagesForAPI } = require('../utils');
10
10
  const fs = require('fs/promises');
11
11
 
@@ -28,10 +28,11 @@ function extractToolCallId(msg) {
28
28
  // 模型上下文限制表(留 15-20% 余量给 system prompt 和输出)
29
29
  const MODEL_CONTEXT_LIMITS = {
30
30
  // DeepSeek
31
- 'deepseek-chat': 28000,
32
- 'deepseek-coder': 28000,
31
+ 'deepseek-chat': 128000,
32
+ 'deepseek-coder': 128000,
33
+ 'deepseek-reasoner': 128000,
33
34
  // MiniMax
34
- 'MiniMax-M2.7': 120000,
35
+ 'MiniMax-M2.7': 110000,
35
36
  // OpenAI
36
37
  'gpt-4': 100000,
37
38
  'gpt-4o': 100000,
@@ -1328,7 +1329,7 @@ ${truncatedContent}${truncatedNote}
1328
1329
 
1329
1330
  // 触发 agent:message 事件,让 memory 插件可以自动提取记忆
1330
1331
  const userMsg = messages[messages.length - result.response.messages.length - 1];
1331
- this.emit('message', { userMessage: userMsg, assistantResponse: result.text });
1332
+ this.emit('message', { content: result.text, sessionId: sessionId, userMessage: userMsg });
1332
1333
 
1333
1334
  // 生成后检查:如果消息太长,下次需要压缩
1334
1335
  const afterTokens = this._countMessagesTokens(messages);
@@ -1341,6 +1342,39 @@ ${truncatedContent}${truncatedNote}
1341
1342
  message: result.text || '',
1342
1343
  stepCount: result.stepCount || 1,
1343
1344
  };
1345
+ } catch (err) {
1346
+ // 捕获 AI API 瞬时错误(如 Invalid JSON response、服务负载过高等)
1347
+ const errorMsg = err.message || String(err);
1348
+ const causeMsg = err.cause?.message || String(err.cause) || '';
1349
+ const fullMsg = errorMsg + causeMsg;
1350
+
1351
+ const isTransientError =
1352
+ fullMsg.includes('Invalid JSON response') ||
1353
+ fullMsg.includes('负载较高') ||
1354
+ fullMsg.includes('Failed after') ||
1355
+ fullMsg.includes('timeout') ||
1356
+ fullMsg.includes('retry') ||
1357
+ err.name === 'AI_RetryError' ||
1358
+ err.name === 'AI_APICallError';
1359
+
1360
+ logger.warn(
1361
+ `[AgentChat] Error caught in _doChat: msg="${errorMsg}", name=${err.name}, isTransient=${isTransientError}`
1362
+ );
1363
+
1364
+ if (isTransientError) {
1365
+ return {
1366
+ success: false,
1367
+ message: 'AI 服务暂时不可用,请稍后重试。',
1368
+ error: errorMsg,
1369
+ stepCount: 0,
1370
+ };
1371
+ }
1372
+
1373
+ // 未知错误,打印调试信息后继续抛出
1374
+ logger.error(
1375
+ `[AgentChat] Unknown error in _doChat: ${err.message}, name: ${err.name}, cause: ${err.cause?.message || err.cause}`
1376
+ );
1377
+ throw err;
1344
1378
  } finally {
1345
1379
  // 校验并修复消息中的不完整工具调用
1346
1380
  this._validateToolCalls(messages);
@@ -1368,7 +1402,7 @@ ${truncatedContent}${truncatedNote}
1368
1402
  this._systemPrompt = this.agent._buildSystemPrompt();
1369
1403
  // 动态导入 AI SDK
1370
1404
  const { tool, ToolLoopAgent } = await this._importAI();
1371
- //await fs.writeFile('system.md',this._systemPrompt)
1405
+ // await fs.writeFile('system.md', this._systemPrompt);
1372
1406
  const userMessage =
1373
1407
  typeof message === 'string' ? { role: 'user', content: message } : message;
1374
1408
  messages.push(userMessage);
@@ -1480,6 +1514,7 @@ ${truncatedContent}${truncatedNote}
1480
1514
  model: this._aiClient,
1481
1515
  instructions: this._systemPrompt,
1482
1516
  tools: tools,
1517
+ stopWhen: isLoopFinished(),
1483
1518
  prepareStep: prepareStepChainStream,
1484
1519
  });
1485
1520
 
@@ -1530,10 +1565,30 @@ ${truncatedContent}${truncatedNote}
1530
1565
 
1531
1566
  // 触发 agent:message 事件,让 memory 插件可以自动提取记忆
1532
1567
  const userMsg = messages[messages.length - finishMessages.length - 1];
1533
- this.emit('message', { userMessage: userMsg, assistantResponse: fullText });
1568
+ this.emit('message', { content: fullText, sessionId: sessionId, userMessage: userMsg });
1534
1569
  } catch (err) {
1535
- this.emit('error', { error: err.message });
1536
- yield { type: 'error', error: err.message };
1570
+ // 捕获 AI API 瞬时错误
1571
+ const errorMsg = err.message || String(err);
1572
+ const causeMsg = err.cause?.message || String(err.cause) || '';
1573
+ const fullMsg = errorMsg + causeMsg;
1574
+
1575
+ const isTransientError =
1576
+ fullMsg.includes('Invalid JSON response') ||
1577
+ fullMsg.includes('负载较高') ||
1578
+ fullMsg.includes('Failed after') ||
1579
+ fullMsg.includes('timeout') ||
1580
+ fullMsg.includes('retry') ||
1581
+ err.name === 'AI_RetryError' ||
1582
+ err.name === 'AI_APICallError';
1583
+
1584
+ if (isTransientError) {
1585
+ logger.warn(`[AgentChat] Transient AI error in stream: ${errorMsg}`);
1586
+ yield { type: 'error', error: 'AI 服务暂时不可用,请稍后重试。' };
1587
+ } else {
1588
+ logger.error(`[AgentChat] Stream error: ${err.message}, name: ${err.name}`);
1589
+ this.emit('error', { error: err.message });
1590
+ yield { type: 'error', error: err.message };
1591
+ }
1537
1592
  } finally {
1538
1593
  // 校验并修复消息中的不完整工具调用
1539
1594
  this._validateToolCalls(messages);
package/src/core/agent.js CHANGED
@@ -6,7 +6,8 @@
6
6
  const { EventEmitter } = require('../utils/event-emitter');
7
7
  const { AgentChatHandler } = require('./agent-chat');
8
8
  const { SystemPromptBuilder } = require('./system-prompt-builder');
9
- const { zodSchemaToTable } = require('@chnak/zod-to-markdown');
9
+ const { zodSchemaToMarkdown } = require('@chnak/zod-to-markdown');
10
+ const { zodSchema } = require('ai');
10
11
  const os = require('os');
11
12
 
12
13
  /**
@@ -278,7 +279,7 @@ class Agent extends EventEmitter {
278
279
  }
279
280
 
280
281
  // 使用数组收集 + join 优化字符串拼接
281
- const lines = ['【可用技能】'];
282
+ const lines = ['## 可用技能', ''];
282
283
  for (const skill of skills) {
283
284
  const name = skill.metadata?.name || skill.name || 'unknown';
284
285
  const descText = skill.metadata?.description || '';
@@ -286,7 +287,7 @@ class Agent extends EventEmitter {
286
287
  }
287
288
  lines.push(
288
289
  '',
289
- '重要:当需要开发插件、执行专业任务时,必须先使用 loadSkill 工具加载对应技能,获取专业指导。'
290
+ '> **重要提示**:当需要开发插件、执行专业任务时,必须先使用 `loadSkill` 工具加载对应技能,获取专业指导。'
290
291
  );
291
292
 
292
293
  return lines.join('\n');
@@ -313,11 +314,11 @@ class Agent extends EventEmitter {
313
314
  }
314
315
 
315
316
  // 使用数组收集 + join 优化字符串拼接
316
- const lines = ['【系统能力】'];
317
+ const lines = ['## 系统能力', ''];
317
318
  keyPlugins.forEach((plugin, index) => {
318
319
  const name = plugin.instance?.name || plugin.name || 'unknown';
319
320
  const description = plugin.instance?.description || '无描述';
320
- lines.push(`${index + 1}. ${name}: ${description}`);
321
+ lines.push(`${index + 1}. **${name}**:${description}`);
321
322
  });
322
323
 
323
324
  return lines.join('\n');
@@ -339,14 +340,16 @@ class Agent extends EventEmitter {
339
340
  }
340
341
 
341
342
  const sections = [
342
- '## Extensions 扩展工具】',
343
+ '## Extensions 扩展工具',
343
344
  '',
344
345
  '你可以通过 `ext_call` 工具调用以下扩展插件的功能。',
345
346
  '',
346
- '**重要调用规则:**',
347
- '1. 调用前必须指定 `plugin`(插件名)和 `tool`(工具名)',
348
- '2. 参数通过 `args` 对象传入,参数名和类型见各工具说明',
349
- '3. 必填参数(Required)必须提供,可选参数(Optional)可省略',
347
+ '### 调用规则',
348
+ '',
349
+ '> **重要**:',
350
+ '> 1. 调用前必须指定 `plugin`(插件名)和 `tool`(工具名)',
351
+ '> 2. 参数通过 `args` 对象传入,参数名和类型见各工具说明',
352
+ '> 3. 必填参数(Required)必须提供,可选参数(Optional)可省略',
350
353
  '',
351
354
  '---',
352
355
  '',
@@ -355,21 +358,30 @@ class Agent extends EventEmitter {
355
358
  for (const ext of extensions) {
356
359
  sections.push(`### ${ext.name}`, '');
357
360
  sections.push(ext.description || '无描述', '');
361
+ sections.push(`**版本:** ${ext.version || '1.0.0'}`, '');
358
362
 
359
363
  for (const tool of ext.tools) {
360
- sections.push(`#### ${tool.name}`, '');
364
+ sections.push(`#### \`${tool.name}\``, '');
361
365
  sections.push(tool.description || '无描述', '');
362
366
 
363
367
  // 使用 zodSchemaToMarkdown 解析参数
364
368
  if (tool.inputSchema) {
365
369
  try {
366
- const schemaMarkdown = zodSchemaToTable(tool.inputSchema);
367
- sections.push('**参数:**', ' ');
368
- sections.push(schemaMarkdown || '无', ' ');
370
+ const schemaMarkdown = zodSchemaToMarkdown(tool.inputSchema);
371
+ // 检查是否包含未解析的原始 Zod 类型名(如 ZodMap、ZodSet、ZodAny 等)
372
+ const hasUnparsedTypes = schemaMarkdown && /\|.*\bZod\w+\b.*\|/.test(schemaMarkdown);
373
+ if (hasUnparsedTypes) {
374
+ // 降级处理:zodSchemaToMarkdown 未正确解析,使用 fallback
375
+ sections.push('**参数:**', ' ');
376
+ sections.push(this._fallbackSchemaToText(tool.inputSchema), ' ');
377
+ } else {
378
+ sections.push('**参数:**', ' ');
379
+ sections.push(schemaMarkdown || '无', ' ');
380
+ }
369
381
  } catch (e) {
370
382
  logger.warn('Agent', `转换工具 ${tool.name} 的参数描述失败`, e.message);
371
383
  // 降级处理:手动解析常见 Zod 类型
372
- sections.push('**参数:**', ' ');
384
+ sections.push('**参数:**', ' ');
373
385
  sections.push(this._fallbackSchemaToText(tool.inputSchema), ' ');
374
386
  }
375
387
  }
@@ -383,18 +395,18 @@ class Agent extends EventEmitter {
383
395
  '',
384
396
  '## 调用示例',
385
397
  '',
386
- '**格式:**',
387
- '```',
398
+ '### 格式',
399
+ '```javascript',
388
400
  'ext_call({ plugin: "插件名", tool: "工具名", args: {参数} })',
389
401
  '```',
390
402
  '',
391
- '**示例 - 获取余额:**',
392
- '```',
403
+ '### 示例 - 获取余额',
404
+ '```javascript',
393
405
  'ext_call({ plugin: "gate-trading", tool: "gate_get_account_balance", args: {} })',
394
406
  '```',
395
407
  '',
396
- '**示例 - HTTP 请求:**',
397
- '```',
408
+ '### 示例 - HTTP 请求',
409
+ '```javascript',
398
410
  'ext_call({ plugin: "web", tool: "web_request", args: { method: "GET", path: "/api/data" } })',
399
411
  '```'
400
412
  );
@@ -404,6 +416,7 @@ class Agent extends EventEmitter {
404
416
 
405
417
  /**
406
418
  * 降级处理:当 zodSchemaToMarkdown 解析失败时的备用方案
419
+ * 支持复杂 Zod 类型如 ZodOptional、ZodUnion、ZodArray 等
407
420
  * @param {Object} schema - Zod schema 对象
408
421
  * @returns {string} 参数描述文本
409
422
  */
@@ -414,41 +427,79 @@ class Agent extends EventEmitter {
414
427
 
415
428
  const lines = [];
416
429
  for (const [name, field] of Object.entries(schema.shape)) {
417
- const type = this._inferZodType(field);
418
- const desc = field.description || field._def?.description || '';
419
- const isOptional = type.includes('optional') ? '(可选)' : '(必填)';
420
- lines.push(`- ${name} (${type}) ${isOptional}${desc ? `: ${desc}` : ''}`);
430
+ const typeInfo = this._extractFieldType(field);
431
+ const desc = typeInfo.description || '';
432
+ const isOptional = typeInfo.isOptional ? '(可选)' : '(必填)';
433
+ lines.push(`- ${name} (${typeInfo.type}) ${isOptional}${desc ? `: ${desc}` : ''}`);
421
434
  }
422
435
 
423
436
  return lines.join('\n') || '- (参数描述不可用)';
424
437
  }
425
438
 
426
439
  /**
427
- * 从 Zod schema 推断类型名称
440
+ * 递归提取字段类型信息
441
+ * 处理 ZodOptional、ZodUnion、ZodArray 等复杂类型
428
442
  * @param {Object} field - Zod schema 字段
429
- * @returns {string} 类型名称
443
+ * @returns {{ type: string, isOptional: boolean, description: string }}
430
444
  */
431
- _inferZodType(field) {
445
+ _extractFieldType(field) {
432
446
  const typeName = field._def?.typeName || field.constructor?.name || '';
433
-
434
- const typeMap = {
435
- ZodString: 'string',
436
- ZodNumber: 'number',
437
- ZodBoolean: 'boolean',
438
- ZodArray: 'array',
439
- ZodObject: 'object',
440
- ZodOptional: 'optional',
441
- ZodDefault: 'any',
442
- ZodEnum: 'enum',
443
- ZodUnion: 'union',
444
- ZodRecord: 'record',
445
- };
446
-
447
- return typeMap[typeName] || typeName.replace('Zod', '').toLowerCase() || 'any';
447
+ let description = field.description || field._def?.description || '';
448
+
449
+ switch (typeName) {
450
+ case 'ZodOptional': {
451
+ const inner = field._def.innerType;
452
+ const innerInfo = this._extractFieldType(inner);
453
+ return {
454
+ type: innerInfo.type,
455
+ isOptional: true,
456
+ description: description || innerInfo.description,
457
+ };
458
+ }
459
+ case 'ZodUnion': {
460
+ const types = field._def.options.map((opt) => this._extractFieldType(opt).type);
461
+ return { type: `union(${types.join(' | ')})`, isOptional: false, description };
462
+ }
463
+ case 'ZodArray': {
464
+ const innerInfo = this._extractFieldType(field._def.type);
465
+ return { type: `${innerInfo.type}[]`, isOptional: false, description };
466
+ }
467
+ case 'ZodObject': {
468
+ const props = Object.keys(field._def.shape()).join(', ');
469
+ return { type: `object{${props}}`, isOptional: false, description };
470
+ }
471
+ case 'ZodString':
472
+ return { type: 'string', isOptional: false, description };
473
+ case 'ZodNumber':
474
+ return { type: 'number', isOptional: false, description };
475
+ case 'ZodBoolean':
476
+ return { type: 'boolean', isOptional: false, description };
477
+ case 'ZodEnum':
478
+ return {
479
+ type: field._def.values.map((v) => `"${v}"`).join(' | '),
480
+ isOptional: false,
481
+ description,
482
+ };
483
+ case 'ZodRecord': {
484
+ const keyType = this._extractFieldType(field._def.keyType).type;
485
+ const valueType = this._extractFieldType(field._def.valueType).type;
486
+ return { type: `record<${keyType}, ${valueType}>`, isOptional: false, description };
487
+ }
488
+ case 'ZodIntersection':
489
+ return { type: 'intersection', isOptional: false, description };
490
+ case 'ZodLiteral':
491
+ return { type: JSON.stringify(field._def.value), isOptional: false, description };
492
+ default:
493
+ return {
494
+ type: typeName.replace('Zod', '').toLowerCase() || 'any',
495
+ isOptional: false,
496
+ description,
497
+ };
498
+ }
448
499
  }
449
500
 
450
501
  _buildMcpToolsDescription() {
451
- const mcpExecutor = this.framework.pluginManager.get('mcp-executor');
502
+ const mcpExecutor = this.framework.pluginManager.get('mcp');
452
503
  if (!mcpExecutor) {
453
504
  return '';
454
505
  }
@@ -471,7 +522,10 @@ class Agent extends EventEmitter {
471
522
  }
472
523
 
473
524
  // 使用数组收集 + join 模式优化字符串拼接
474
- const lines = ['【子 Agent 匹配表 - 优先使用】'];
525
+ const lines = ['## Agent 匹配表', ''];
526
+ lines.push('');
527
+ lines.push('> **提示**:根据任务类型选择最匹配的子 Agent 处理');
528
+ lines.push('');
475
529
 
476
530
  // 动态从配置文件读取每个子Agent的核心能力
477
531
  for (const plugin of allSubAgents) {
@@ -488,21 +542,24 @@ class Agent extends EventEmitter {
488
542
  if (skills && skills.length > 0) {
489
543
  info += ` (技能: ${skills.join(', ')})`;
490
544
  }
491
- lines.push(` - ${name}: ${info}`);
545
+ lines.push(`- **${name}**:${info}`);
492
546
  } else {
493
547
  // 回退到旧逻辑
494
- lines.push(` - ${name}: ${role || goal || '子代理'}`);
548
+ lines.push(`- **${name}**:${role || goal || '子代理'}`);
495
549
  }
496
550
  }
497
551
 
498
552
  // 通用规则
499
553
  lines.push('');
500
- lines.push('【子Agent匹配规则 - 必须遵守】');
501
- lines.push(' - 根据上述【子 Agent 匹配表】,将任务委托给最匹配的子Agent处理');
502
- lines.push(' - 使用 subagent_call 工具并指定 agentName 来委托任务');
503
- lines.push(' - 只有当没有匹配的子Agent时,才直接调用工具');
554
+ lines.push('### 子 Agent 调用规则');
555
+ lines.push('');
556
+ lines.push('> **重要**:必须严格遵守以下规则');
557
+ lines.push('');
558
+ lines.push('1. 根据上述「子 Agent 匹配表」,将任务委托给最匹配的子 Agent 处理');
559
+ lines.push('2. 使用 `subagent_call` 工具并指定 `agentName` 来委托任务');
560
+ lines.push('3. 只有当没有匹配的子 Agent 时,才直接调用工具');
504
561
 
505
- return lines.join('\n').trim();
562
+ return lines.join('\n');
506
563
  }
507
564
 
508
565
  /**
@@ -689,24 +746,26 @@ class Agent extends EventEmitter {
689
746
  * @private
690
747
  */
691
748
  _getToolCoreRules() {
692
- return `【工具调用核心规则】
693
- 1. **子Agent优先**:任务匹配子Agent专业领域时,**必须优先使用** 使用 subagent_call 工具并指定 agentName 委托给对应子Agent处理,而不是直接调用工具。只有当没有匹配的子Agent时,才直接调用工具。
749
+ return `## 工具调用核心规则
750
+
751
+ 1. **子 Agent 优先**:任务匹配子 Agent 专业领域时,**必须优先使用** \`subagent_call\` 工具并指定 \`agentName\` 委托给对应子 Agent 处理,而不是直接调用工具。只有当没有匹配的子 Agent 时,才直接调用工具。
694
752
  2. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
695
753
  3. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
696
- 4. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
754
+ 4. **工具优先**:可用工具列表会提供,格式为 \`toolName(toolArgs)\`。不确定用哪个工具时,优先调用可能相关的工具。
697
755
  5. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
698
756
  6. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
699
757
  7. **步骤未完成必须提示继续**:如果任务需要多步骤操作,在返回前必须明确告知用户当前进度和下一步操作。如果回复内容为空或不完整,必须说明"步骤进行中,请继续"。
700
758
 
759
+ ## 响应规范
760
+
761
+ > 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
701
762
 
702
- 【响应规范】
703
- - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
704
763
  - 如果工具返回错误,说明错误原因并给出解决建议
705
764
  - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
706
- - **重要:如果任务需要多步骤操作,在回复末尾必须提示用户"请继续"或"是否继续下一步"**
765
+ - **重要**:如果任务需要多步骤操作,在回复末尾必须提示用户"请继续"或"是否继续下一步"
707
766
 
767
+ ## 禁止事项
708
768
 
709
- 【禁止事项】
710
769
  - 不调用工具就直接回答
711
770
  - 编造不存在的数据、文件、订单、用户等信息
712
771
  - 回复含糊不清,让用户无法确定答案是否正确
@@ -163,7 +163,7 @@ class ToolRegistry extends EventEmitter {
163
163
  const tool = this._tools.get(name);
164
164
  if (!tool) {
165
165
  const error = new Error(`Tool '${name}' not found`);
166
- this.emit('tool:error', { name, args, error });
166
+ this.emit('tool:error', { name, args, error, source: 'tool' });
167
167
  throw error;
168
168
  }
169
169
 
@@ -199,7 +199,7 @@ class ToolRegistry extends EventEmitter {
199
199
  error.toolName = name;
200
200
  error.toolArgs = args;
201
201
  error.errorType = 'VALIDATION_ERROR';
202
- this.emit('tool:error', { name, args, error });
202
+ this.emit('tool:error', { name, args, error, source: 'tool' });
203
203
  throw error;
204
204
  }
205
205
  // 其他错误(可能是非 Zod 错误),包装后抛出
@@ -207,7 +207,7 @@ class ToolRegistry extends EventEmitter {
207
207
  error.toolName = name;
208
208
  error.toolArgs = args;
209
209
  error.errorType = 'PARSE_ERROR';
210
- this.emit('tool:error', { name, args, error });
210
+ this.emit('tool:error', { name, args, error, source: 'tool' });
211
211
  throw error;
212
212
  }
213
213
  }
@@ -240,7 +240,7 @@ class ToolRegistry extends EventEmitter {
240
240
  });
241
241
 
242
242
  try {
243
- this.emit('tool:call', { name, args: validatedArgs });
243
+ this.emit('tool:call', { name, args: validatedArgs, source: 'tool' });
244
244
 
245
245
  // 确定重试配置
246
246
  let retryConfig = tool.retryOptions;
@@ -288,7 +288,7 @@ class ToolRegistry extends EventEmitter {
288
288
  result = await executeTool();
289
289
  }
290
290
 
291
- this.emit('tool:result', { name, args, result });
291
+ this.emit('tool:result', { name, args, result, source: 'tool' });
292
292
  return result;
293
293
  } catch (err) {
294
294
  // 包装错误信息,添加详细上下文