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.
- package/.agent/data/email/processed-emails.json +1 -0
- package/.agent/data/plugins-state.json +5 -1
- package/.agent/data/web/web-config.json +5 -0
- package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +15 -0
- package/.agent/memory/feedback/mnt88ja3-al4fuy.md +9 -0
- package/.agent/plugins/test-plugin.py +108 -0
- package/.agent/sessions/cli_default.json +514 -5298
- package/.claude/settings.local.json +2 -1
- package/SPEC.md +735 -696
- package/output/zen_silence.png +0 -0
- package/package.json +2 -2
- package/plugins/ambient-agent/EventWatcher.js +33 -37
- package/plugins/ambient-agent/ExplorerLoop.js +338 -36
- package/plugins/ambient-agent/GoalManager.js +7 -3
- package/plugins/ambient-agent/StateStore.js +30 -1
- package/plugins/ambient-agent/constants.js +15 -1
- package/plugins/ambient-agent/index.js +26 -33
- package/plugins/coordinator-plugin.js +3 -3
- package/plugins/default-plugins.js +2 -2
- package/plugins/email/index.js +150 -36
- package/plugins/email/monitor.js +79 -5
- package/plugins/email/reply.js +15 -25
- package/plugins/extension-executor-plugin.js +160 -31
- package/plugins/file-system-plugin.js +57 -24
- package/plugins/memory-plugin.js +176 -64
- package/plugins/python-plugin-loader.js +79 -9
- package/plugins/scheduler-plugin.js +64 -24
- package/plugins/think-plugin.js +7 -2
- package/plugins/web-plugin.js +263 -4
- package/skills/ambient-agent/SKILL.md +342 -314
- package/src/core/agent-chat.js +64 -9
- package/src/core/agent.js +118 -59
- package/src/core/tool-registry.js +5 -5
- package/src/executors/mcp-executor.js +188 -26
- package/src/utils/id.js +5 -0
- package/system.md +3480 -0
- package/.agent/data/ambient/goals.json +0 -50
- package/.agent/data/ambient/memories.json +0 -7
- package/.agent/memory/core.md +0 -1
- package/.agent/memory/feedback/mnrsiuoc-e1ru74.md +0 -9
- package/.agent/memory/feedback/mnrt2mmz-98az6n.md +0 -9
- package/.agent/memory/feedback/mnrtqrhm-kxsicz.md +0 -9
- package/.agent/memory/feedback/mnrts8vg-i0ngzp.md +0 -15
- package/.agent/memory/feedback/mnrtt7jt-c0trb2.md +0 -9
- package/.agent/memory/feedback/mnruc2f0-5s52la.md +0 -16
- package/.agent/memory/feedback/mnrumbmx-63sa0v.md +0 -9
- package/.agent/memory/project/mnn93ogy-ypjn27.md +0 -9
- package/.agent/memory/project/mnn98fqy-5nhc1u.md +0 -25
- package/.agent/memory/project/mnrp7p5n-8enm2a.md +0 -31
- package/.agent/memory/project/mnrp9ifb-yynks0.md +0 -40
- package/.agent/memory/project/mnrpb3b8-f617s4.md +0 -25
- package/.agent/memory/project/mnrrmqgg-focprv.md +0 -9
- package/.agent/memory/project/mnrtykbh-6atsor.md +0 -9
- package/.agent/memory/project/mnru9jiu-kgau16.md +0 -35
- package/.agent/memory/reference/mnq3oenw-46haj6.md +0 -63
- package/.agent/memory/reference/mnq5qxm2-mjoooh.md +0 -116
- package/.agent/memory/reference/mnrnvpwo-rcqv9m.md +0 -52
- package/.agent/memory/reference/mnrovxvz-zy9xqm.md +0 -25
- package/.agent/memory/reference/mnroxabj-1b3930.md +0 -68
- package/.agent/memory/reference/mnrpjtlp-mnb9od.md +0 -35
- package/.agent/memory/reference/mnrps1x3-6b8xfm.md +0 -28
- package/.agent/memory/reference/mnrpt9ov-15er5w.md +0 -22
- package/.agent/memory/reference/mnrq82dn-y9tv9e.md +0 -50
- package/.agent/memory/reference/mnrqnr5v-v75drf.md +0 -34
- package/.agent/memory/reference/mnrrfzys-urudaf.md +0 -31
- package/.agent/memory/reference/mnrrocha-t0027n.md +0 -21
- package/.agent/memory/reference/mnrukklc-bxndsb.md +0 -35
- package/.agent/memory/user/mnm67t9m-x8rekk.md +0 -9
- package/.agent/memory/user/mnn5mmqh-w6aktx.md +0 -11
- package/.agent/memory/user/mnnbfhhn-dk1bd1.md +0 -22
- package/.agent/memory/user/mnrt39t8-8eosy0.md +0 -9
- package/foliko-cloud-rising.png +0 -0
- package/foliko-dawn-of-ai.png +0 -0
- package/foliko-mindful-observation.png +0 -0
- package/foliko-stellar-dreams.png +0 -0
- package/foliko-zen-jing.png +0 -0
- package/foliko-zen-kong.png +0 -0
- package/foliko-zen-wu.png +0 -0
- package/zen_karesansui.png +0 -0
package/src/core/agent-chat.js
CHANGED
|
@@ -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':
|
|
32
|
-
'deepseek-coder':
|
|
31
|
+
'deepseek-chat': 128000,
|
|
32
|
+
'deepseek-coder': 128000,
|
|
33
|
+
'deepseek-reasoner': 128000,
|
|
33
34
|
// MiniMax
|
|
34
|
-
'MiniMax-M2.7':
|
|
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', {
|
|
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', {
|
|
1568
|
+
this.emit('message', { content: fullText, sessionId: sessionId, userMessage: userMsg });
|
|
1534
1569
|
} catch (err) {
|
|
1535
|
-
|
|
1536
|
-
|
|
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 {
|
|
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
|
-
'
|
|
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}.
|
|
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
|
-
'##
|
|
343
|
+
'## Extensions 扩展工具',
|
|
343
344
|
'',
|
|
344
345
|
'你可以通过 `ext_call` 工具调用以下扩展插件的功能。',
|
|
345
346
|
'',
|
|
346
|
-
'
|
|
347
|
-
'
|
|
348
|
-
'
|
|
349
|
-
'
|
|
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(`####
|
|
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 =
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
'
|
|
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
|
|
418
|
-
const desc =
|
|
419
|
-
const isOptional =
|
|
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
|
-
*
|
|
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
|
-
|
|
445
|
+
_extractFieldType(field) {
|
|
432
446
|
const typeName = field._def?.typeName || field.constructor?.name || '';
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
|
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 = ['
|
|
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(
|
|
545
|
+
lines.push(`- **${name}**:${info}`);
|
|
492
546
|
} else {
|
|
493
547
|
// 回退到旧逻辑
|
|
494
|
-
lines.push(
|
|
548
|
+
lines.push(`- **${name}**:${role || goal || '子代理'}`);
|
|
495
549
|
}
|
|
496
550
|
}
|
|
497
551
|
|
|
498
552
|
// 通用规则
|
|
499
553
|
lines.push('');
|
|
500
|
-
lines.push('
|
|
501
|
-
lines.push('
|
|
502
|
-
lines.push('
|
|
503
|
-
lines.push('
|
|
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')
|
|
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
|
-
|
|
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
|
// 包装错误信息,添加详细上下文
|