foliko 1.0.77 → 1.0.78
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/default.json +31559 -0
- package/.agent/data/plugins-state.json +10 -1
- package/.claude/settings.local.json +13 -2
- package/.env.example +54 -54
- package/cli/src/commands/chat.js +1 -1
- package/examples/basic.js +1 -1
- package/package.json +5 -3
- package/plugins/ai-plugin.js +1 -1
- package/plugins/ambient-agent/index.js +1 -1
- package/plugins/audit-plugin.js +1 -1
- package/plugins/default-plugins.js +92 -209
- package/plugins/email/index.js +1 -1
- package/plugins/extension-executor-plugin.js +326 -0
- package/plugins/feishu-plugin.js +1 -1
- package/plugins/file-system-plugin.js +57 -6
- package/plugins/gate-trading.js +747 -0
- package/plugins/install-plugin.js +1 -1
- package/plugins/python-executor-plugin.js +1 -1
- package/plugins/python-plugin-loader.js +275 -105
- package/plugins/rules-plugin.js +1 -1
- package/plugins/scheduler-plugin.js +1 -1
- package/plugins/session-plugin.js +132 -7
- package/plugins/shell-executor-plugin.js +1 -1
- package/plugins/storage-plugin.js +24 -1
- package/plugins/subagent-plugin.js +2 -2
- package/plugins/telegram-plugin.js +1 -1
- package/plugins/think-plugin.js +10 -10
- package/plugins/tools-plugin.js +1 -1
- package/plugins/web-plugin.js +49 -18
- package/plugins/weixin-plugin.js +1 -1
- package/skills/foliko-dev/SKILL.md +583 -500
- package/skills/python-plugin-dev/SKILL.md +238 -266
- package/src/core/agent-chat.js +103 -4
- package/src/core/agent.js +85 -19
- package/src/core/plugin-base.js +43 -0
- package/src/executors/mcp-executor.js +126 -22
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
"maxSessions": 100,
|
|
58
58
|
"maxHistoryLength": 150,
|
|
59
59
|
"autoCleanup": true,
|
|
60
|
-
"cleanupInterval": 300000
|
|
60
|
+
"cleanupInterval": 300000,
|
|
61
|
+
"persistToStorage": true
|
|
61
62
|
}
|
|
62
63
|
},
|
|
63
64
|
"audit": {
|
|
@@ -251,5 +252,13 @@
|
|
|
251
252
|
"agentsDir": "D:\\code\\vb-agent\\.agent\\agents",
|
|
252
253
|
"agents": []
|
|
253
254
|
}
|
|
255
|
+
},
|
|
256
|
+
"extension-executor": {
|
|
257
|
+
"enabled": true,
|
|
258
|
+
"config": {}
|
|
259
|
+
},
|
|
260
|
+
"gate-trading": {
|
|
261
|
+
"enabled": true,
|
|
262
|
+
"config": {}
|
|
254
263
|
}
|
|
255
264
|
}
|
|
@@ -152,8 +152,19 @@
|
|
|
152
152
|
"Bash(git checkout:*)",
|
|
153
153
|
"Bash(node --check plugins/default-plugins.js && echo \"OK\")",
|
|
154
154
|
"Bash(node --check plugins/subagent-plugin.js && echo \"OK\")",
|
|
155
|
-
"Bash(
|
|
156
|
-
"Bash(
|
|
155
|
+
"Bash(cd D:/Code/vb-agent && pnpm install 2>&1 | tail -10)",
|
|
156
|
+
"Bash(mkdir -p \"D:/Code/vb-agent/node_modules/@chanak\" && ln -sf \"../../.pnpm/@chnak+zod-to-markdown@1.0.1/node_modules/@chnak/zod-to-markdown\" \"D:/Code/vb-agent/node_modules/@chnak/zod-to-markdown\")",
|
|
157
|
+
"Bash(cd D:/Code/vb-agent && rm -rf node_modules/@chanak && npm install @chnak/zod-to-markdown --legacy-peer-deps 2>&1 | tail -10)",
|
|
158
|
+
"Bash(cd D:/Code/vb-agent && npm start 2>&1 | head -30)",
|
|
159
|
+
"Bash(cd D:/Code/vb-agent && npm start 2>&1 | head -40)",
|
|
160
|
+
"Bash(grep -l \"module.exports\" D:/Code/vb-agent/plugins/*.js 2>/dev/null | head -20)",
|
|
161
|
+
"Bash(grep -E \"^module.exports\" D:/Code/vb-agent/plugins/*.js | head -30)",
|
|
162
|
+
"Bash(grep -E \"^module.exports\" D:/Code/vb-agent/src/executors/*.js 2>/dev/null)",
|
|
163
|
+
"Bash(grep \"module.exports\" D:/Code/vb-agent/plugins/ambient-agent/*.js 2>/dev/null)",
|
|
164
|
+
"Bash(grep -E \"^module.exports\" D:/Code/vb-agent/plugins/*.js | head -20)",
|
|
165
|
+
"Bash(cd D:/Code/vb-agent && npm start 2>&1 | head -25)",
|
|
166
|
+
"Bash(cd D:/Code/vb-agent && timeout 20 npm start 2>&1 | head -35)",
|
|
167
|
+
"Bash(node -c D:/Code/vb-agent/plugins/gate-trading.js 2>&1)"
|
|
157
168
|
]
|
|
158
169
|
}
|
|
159
170
|
}
|
package/.env.example
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
# ========== AI Configuration ==========
|
|
2
2
|
# 最大输出 tokens(影响 AI 回复长度)
|
|
3
|
-
MAX_OUTPUT_TOKENS=8192
|
|
4
|
-
# AI Provider: minimax, deepseek, openai, anthropic 等
|
|
5
|
-
FOLIKO_PROVIDER=minimax
|
|
6
|
-
|
|
7
|
-
# AI Model(如果未设置,使用 provider 默认值)
|
|
8
|
-
# MiniMax: MiniMax-M2.7
|
|
9
|
-
# DeepSeek: deepseek-chat, deepseek-coder 等
|
|
10
|
-
FOLIKO_MODEL=MiniMax-M2.7
|
|
11
|
-
|
|
12
|
-
# API Base URL(如果未设置,使用 provider 默认值)
|
|
13
|
-
# MiniMax: https://api.minimaxi.com/v1
|
|
14
|
-
# DeepSeek: https://api.deepseek.com/v1
|
|
15
|
-
FOLIKO_BASE_URL=https://api.minimaxi.com/v1
|
|
16
|
-
|
|
17
|
-
# API Key(通用,如果未设置则尝试 provider 专用 key)
|
|
18
|
-
FOLIKO_API_KEY=sk-your-api-key
|
|
19
|
-
|
|
20
|
-
# Provider 专用 API Key(可选,如果 FOLIKO_API_KEY 未设置则使用这些)
|
|
21
|
-
DEEPSEEK_API_KEY=sk-your-deepseek-api-key
|
|
22
|
-
MINIMAX_API_KEY=sk-your-minimax-api-key
|
|
23
|
-
|
|
24
|
-
# ========== Email Configuration ==========
|
|
25
|
-
# SMTP Settings (for sending emails)
|
|
26
|
-
SMTP_HOST=smtp.gmail.com
|
|
27
|
-
SMTP_PORT=587
|
|
28
|
-
SMTP_SECURE=false
|
|
29
|
-
SMTP_USER=your-email@gmail.com
|
|
30
|
-
SMTP_PASS=your-app-password
|
|
31
|
-
|
|
32
|
-
# IMAP Settings (for reading emails)
|
|
33
|
-
IMAP_HOST=imap.gmail.com
|
|
34
|
-
IMAP_PORT=993
|
|
35
|
-
IMAP_USER=your-email@gmail.com
|
|
36
|
-
IMAP_PASS=your-app-password
|
|
37
|
-
|
|
38
|
-
# Default sender email address
|
|
39
|
-
FROM_EMAIL=your-email@gmail.com
|
|
40
|
-
|
|
41
|
-
# ========== Telegram Bot (optional) ==========
|
|
42
|
-
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
|
43
|
-
|
|
44
|
-
# ========== Feishu Bot (optional) ==========
|
|
45
|
-
FEISHU_APP_ID=cli_xxxxxxxxxxx
|
|
46
|
-
FEISHU_APP_SECRET=app_secret
|
|
47
|
-
|
|
48
|
-
# ========== Web Server (optional) ==========
|
|
49
|
-
# Web 服务端口,默认 8088
|
|
50
|
-
WEB_PORT=3000
|
|
51
|
-
|
|
52
|
-
# Web 服务主机,默认 127.0.0.1
|
|
53
|
-
WEB_HOST=127.0.0.1
|
|
54
|
-
|
|
55
|
-
# 公网访问的 base URL(用于生成 webhook URL 等),不设置则使用 host:port,最好部署在docker中可以暴露自定义域名
|
|
56
|
-
WEB_BASE_URL=https://your-domain.com
|
|
3
|
+
MAX_OUTPUT_TOKENS=8192
|
|
4
|
+
# AI Provider: minimax, deepseek, openai, anthropic 等
|
|
5
|
+
FOLIKO_PROVIDER=minimax
|
|
6
|
+
|
|
7
|
+
# AI Model(如果未设置,使用 provider 默认值)
|
|
8
|
+
# MiniMax: MiniMax-M2.7
|
|
9
|
+
# DeepSeek: deepseek-chat, deepseek-coder 等
|
|
10
|
+
FOLIKO_MODEL=MiniMax-M2.7
|
|
11
|
+
|
|
12
|
+
# API Base URL(如果未设置,使用 provider 默认值)
|
|
13
|
+
# MiniMax: https://api.minimaxi.com/v1
|
|
14
|
+
# DeepSeek: https://api.deepseek.com/v1
|
|
15
|
+
FOLIKO_BASE_URL=https://api.minimaxi.com/v1
|
|
16
|
+
|
|
17
|
+
# API Key(通用,如果未设置则尝试 provider 专用 key)
|
|
18
|
+
FOLIKO_API_KEY=sk-your-api-key
|
|
19
|
+
|
|
20
|
+
# Provider 专用 API Key(可选,如果 FOLIKO_API_KEY 未设置则使用这些)
|
|
21
|
+
DEEPSEEK_API_KEY=sk-your-deepseek-api-key
|
|
22
|
+
MINIMAX_API_KEY=sk-your-minimax-api-key
|
|
23
|
+
|
|
24
|
+
# ========== Email Configuration ==========
|
|
25
|
+
# SMTP Settings (for sending emails)
|
|
26
|
+
SMTP_HOST=smtp.gmail.com
|
|
27
|
+
SMTP_PORT=587
|
|
28
|
+
SMTP_SECURE=false
|
|
29
|
+
SMTP_USER=your-email@gmail.com
|
|
30
|
+
SMTP_PASS=your-app-password
|
|
31
|
+
|
|
32
|
+
# IMAP Settings (for reading emails)
|
|
33
|
+
IMAP_HOST=imap.gmail.com
|
|
34
|
+
IMAP_PORT=993
|
|
35
|
+
IMAP_USER=your-email@gmail.com
|
|
36
|
+
IMAP_PASS=your-app-password
|
|
37
|
+
|
|
38
|
+
# Default sender email address
|
|
39
|
+
FROM_EMAIL=your-email@gmail.com
|
|
40
|
+
|
|
41
|
+
# ========== Telegram Bot (optional) ==========
|
|
42
|
+
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
|
43
|
+
|
|
44
|
+
# ========== Feishu Bot (optional) ==========
|
|
45
|
+
FEISHU_APP_ID=cli_xxxxxxxxxxx
|
|
46
|
+
FEISHU_APP_SECRET=app_secret
|
|
47
|
+
|
|
48
|
+
# ========== Web Server (optional) ==========
|
|
49
|
+
# Web 服务端口,默认 8088
|
|
50
|
+
WEB_PORT=3000
|
|
51
|
+
|
|
52
|
+
# Web 服务主机,默认 127.0.0.1
|
|
53
|
+
WEB_HOST=127.0.0.1
|
|
54
|
+
|
|
55
|
+
# 公网访问的 base URL(用于生成 webhook URL 等),不设置则使用 host:port,最好部署在docker中可以暴露自定义域名
|
|
56
|
+
WEB_BASE_URL=https://your-domain.com
|
package/cli/src/commands/chat.js
CHANGED
package/examples/basic.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foliko",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.78",
|
|
4
4
|
"description": "简约的插件化 Agent 框架",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -54,24 +54,26 @@
|
|
|
54
54
|
"@ai-sdk/openai-compatible": "^2.0.35",
|
|
55
55
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
56
56
|
"@chnak/weixin-bot": "^1.2.1",
|
|
57
|
+
"@chnak/zod-to-markdown": "^1.0.1",
|
|
57
58
|
"@hono/node-server": "^1.19.11",
|
|
58
59
|
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
59
60
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
60
61
|
"ai": "^6.0.116",
|
|
61
62
|
"dotenv": "^17.3.1",
|
|
63
|
+
"gate-api": "^7.2.57",
|
|
62
64
|
"hono": "^4.12.9",
|
|
63
65
|
"imap-mkl": "^1.0.2",
|
|
64
66
|
"mailparser": "^3.7.2",
|
|
65
67
|
"marked": "^11.2.0",
|
|
66
68
|
"marked-terminal": "6",
|
|
67
69
|
"node-cron": "^4.2.1",
|
|
70
|
+
"node-html-markdown": "^1.3.0",
|
|
68
71
|
"node-telegram-bot-api": "^0.67.0",
|
|
69
72
|
"nodemailer": "^6.10.0",
|
|
70
73
|
"qrcode-terminal": "^0.12.0",
|
|
71
74
|
"remove-markdown": "^0.6.3",
|
|
72
|
-
"tiktoken": "^1.0.22",
|
|
73
75
|
"vm2": "^3.10.5",
|
|
74
|
-
"zod": "^3.
|
|
76
|
+
"zod": "^3.25.76"
|
|
75
77
|
},
|
|
76
78
|
"devDependencies": {
|
|
77
79
|
"husky": "^9.1.7",
|
package/plugins/ai-plugin.js
CHANGED
package/plugins/audit-plugin.js
CHANGED
|
@@ -229,7 +229,7 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
229
229
|
// 核心插件列表(不能禁用,必须加载)
|
|
230
230
|
const CORE_PLUGINS = new Set([
|
|
231
231
|
'install', 'ai', 'storage', 'tools', 'workflow', 'skill-manager',
|
|
232
|
-
'mcp-executor', 'shell-executor', 'python-executor', 'session', 'web',
|
|
232
|
+
'mcp-executor', 'extension-executor', 'shell-executor', 'python-executor', 'session', 'web',
|
|
233
233
|
'audit', 'rules', 'scheduler', 'file-system', 'think', 'ambient',
|
|
234
234
|
'python-plugin-loader', 'telegram', 'weixin', 'subagent-manager'
|
|
235
235
|
])
|
|
@@ -257,7 +257,7 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
257
257
|
|
|
258
258
|
// 0. Install 工具插件(最先加载,让其他插件能用到它的 node_modules)
|
|
259
259
|
if (shouldLoad('install')) {
|
|
260
|
-
const
|
|
260
|
+
const InstallPlugin = require('./install-plugin')
|
|
261
261
|
await framework.loadPlugin(new InstallPlugin({ agentDir: agentConfig.agentDir }))
|
|
262
262
|
framework._debug&&bootstrapLog.debug(' Install Plugin loaded')
|
|
263
263
|
}
|
|
@@ -273,7 +273,7 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
273
273
|
if (!shouldLoad('ai') || !(aiConfig.provider || aiConfig.model || aiConfig.apiKey)) {
|
|
274
274
|
// 跳过或已禁用
|
|
275
275
|
} else {
|
|
276
|
-
const
|
|
276
|
+
const AIPlugin = require('./ai-plugin')
|
|
277
277
|
// 根据 provider 获取对应的 API key
|
|
278
278
|
const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
|
|
279
279
|
const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
|
|
@@ -306,38 +306,14 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
306
306
|
framework._debug&&bootstrapLog.debug(' Main Agent created, has _chatHandler:', !!framework._mainAgent._chatHandler)
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
// 2.
|
|
310
|
-
if (shouldLoad('
|
|
311
|
-
const {
|
|
312
|
-
await framework.loadPlugin(new
|
|
313
|
-
framework._debug&&bootstrapLog.debug('
|
|
309
|
+
// 2. Skill 管理器插件(需要 skillsDirs 配置)
|
|
310
|
+
if (shouldLoad('skill-manager') && skillsDirs.length > 0) {
|
|
311
|
+
const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
|
|
312
|
+
await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
|
|
313
|
+
framework._debug&&bootstrapLog.debug(' Skill Manager loaded')
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
// 3.
|
|
317
|
-
if (shouldLoad('tools')) {
|
|
318
|
-
const { ToolsPlugin } = require('./tools-plugin')
|
|
319
|
-
await framework.loadPlugin(new ToolsPlugin())
|
|
320
|
-
framework._debug&&bootstrapLog.debug(' Tools Plugin loaded')
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// 4. 工作流插件
|
|
324
|
-
if (shouldLoad('workflow')) {
|
|
325
|
-
const { WorkflowPlugin } = require('../src/capabilities/workflow-engine')
|
|
326
|
-
await framework.loadPlugin(new WorkflowPlugin())
|
|
327
|
-
framework._debug&&bootstrapLog.debug(' Workflow Plugin loaded')
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// 5. Skill 管理器插件
|
|
331
|
-
if (shouldLoad('skill-manager')) {
|
|
332
|
-
if (skillsDirs.length > 0) {
|
|
333
|
-
const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
|
|
334
|
-
// 传递所有 skills 目录
|
|
335
|
-
await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
|
|
336
|
-
framework._debug&&bootstrapLog.debug(' Skill Manager loaded')
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// 6. MCP 执行器插件(始终加载,确保 mcp_reload 工具可用)
|
|
316
|
+
// 3. MCP 执行器插件(需要转换 mcpServers 格式)
|
|
341
317
|
if (shouldLoad('mcp-executor')) {
|
|
342
318
|
const mcpServers = Object.entries(agentConfig.mcpServers || {})
|
|
343
319
|
const servers = mcpServers.map(([name, cfg]) => ({
|
|
@@ -354,152 +330,21 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
354
330
|
framework._debug&&bootstrapLog.debug(` MCP Executor loaded${servers.length > 0 ? ` (${servers.length} servers)` : ' (no servers)'}`)
|
|
355
331
|
}
|
|
356
332
|
|
|
357
|
-
//
|
|
358
|
-
if (shouldLoad('shell-executor')) {
|
|
359
|
-
const { ShellExecutorPlugin } = require('./shell-executor-plugin')
|
|
360
|
-
await framework.loadPlugin(new ShellExecutorPlugin())
|
|
361
|
-
framework._debug&&bootstrapLog.debug(' Shell Executor loaded')
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// 8. Python 执行器插件
|
|
365
|
-
if (shouldLoad('python-executor')) {
|
|
366
|
-
const { PythonExecutorPlugin } = require('./python-executor-plugin')
|
|
367
|
-
await framework.loadPlugin(new PythonExecutorPlugin())
|
|
368
|
-
framework._debug&&bootstrapLog.debug(' Python Executor loaded')
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// 8.5 Web Web服务插件
|
|
372
|
-
if (shouldLoad('web')) {
|
|
373
|
-
const { WebPlugin } = require('./web-plugin')
|
|
374
|
-
await framework.loadPlugin(new WebPlugin())
|
|
375
|
-
framework._debug&&bootstrapLog.debug(' Web Plugin loaded')
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// 9. Session 会话管理插件
|
|
379
|
-
if (shouldLoad('session')) {
|
|
380
|
-
const { SessionPlugin } = require('./session-plugin')
|
|
381
|
-
await framework.loadPlugin(new SessionPlugin())
|
|
382
|
-
framework._debug&&bootstrapLog.debug(' Session Plugin loaded')
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// 10. Audit 审计日志插件
|
|
386
|
-
if (shouldLoad('audit')) {
|
|
387
|
-
const { AuditPlugin } = require('./audit-plugin')
|
|
388
|
-
await framework.loadPlugin(new AuditPlugin())
|
|
389
|
-
framework._debug&&bootstrapLog.debug(' Audit Plugin loaded')
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// 10. Rules 规则引擎插件
|
|
393
|
-
if (shouldLoad('rules')) {
|
|
394
|
-
const { RulesPlugin } = require('./rules-plugin')
|
|
395
|
-
await framework.loadPlugin(new RulesPlugin())
|
|
396
|
-
framework._debug&&bootstrapLog.debug(' Rules Plugin loaded')
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// 11. Scheduler 定时任务插件
|
|
400
|
-
if (shouldLoad('scheduler')) {
|
|
401
|
-
const { SchedulerPlugin } = require('./scheduler-plugin')
|
|
402
|
-
await framework.loadPlugin(new SchedulerPlugin())
|
|
403
|
-
framework._debug&&bootstrapLog.debug(' Scheduler Plugin loaded')
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// 11. FileSystem 文件系统插件
|
|
407
|
-
if (shouldLoad('file-system')) {
|
|
408
|
-
const { FileSystemPlugin } = require('./file-system-plugin')
|
|
409
|
-
await framework.loadPlugin(new FileSystemPlugin())
|
|
410
|
-
framework._debug&&bootstrapLog.debug(' FileSystem Plugin loaded')
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// 12. Think 主动思考插件
|
|
414
|
-
if (shouldLoad('think')) {
|
|
415
|
-
const { ThinkPlugin } = require('./think-plugin')
|
|
416
|
-
await framework.loadPlugin(new ThinkPlugin())
|
|
417
|
-
framework._debug&&bootstrapLog.debug(' Think Plugin loaded')
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// 12.1 Ambient Agent 插件
|
|
421
|
-
if (shouldLoad('ambient')) {
|
|
422
|
-
const { AmbientAgentPlugin } = require('./ambient-agent')
|
|
423
|
-
await framework.loadPlugin(new AmbientAgentPlugin())
|
|
424
|
-
framework._debug&&bootstrapLog.debug(' Ambient Agent Plugin loaded')
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// 12.5 Python 插件加载器
|
|
333
|
+
// 4. Python 插件加载器(需要 agentDir)
|
|
428
334
|
if (shouldLoad('python-plugin-loader')) {
|
|
429
|
-
const
|
|
335
|
+
const PythonPluginLoader = require('./python-plugin-loader')
|
|
430
336
|
await framework.loadPlugin(new PythonPluginLoader({ agentDir: agentConfig.agentDir }))
|
|
431
337
|
framework._debug&&bootstrapLog.debug(' Python Plugin Loader loaded')
|
|
432
338
|
}
|
|
433
339
|
|
|
434
|
-
//
|
|
435
|
-
if (shouldLoad('telegram')) {
|
|
436
|
-
const { TelegramPlugin } = require('./telegram-plugin')
|
|
437
|
-
const telegramConfig = {
|
|
438
|
-
botToken: process.env.TELEGRAM_BOT_TOKEN || agentConfig.telegram?.botToken
|
|
439
|
-
}
|
|
440
|
-
await framework.loadPlugin(new TelegramPlugin(telegramConfig))
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// 12.7 WeChat 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
|
|
444
|
-
if (shouldLoad('weixin')) {
|
|
445
|
-
try {
|
|
446
|
-
const { WeixinPlugin } = require('./weixin-plugin')
|
|
447
|
-
const weixinConfig = {
|
|
448
|
-
forceLogin: agentConfig.weixin?.forceLogin || false,
|
|
449
|
-
qrcodeTerminal: agentConfig.weixin?.qrcodeTerminal !== false,
|
|
450
|
-
allowedUsers: agentConfig.weixin?.allowedUsers || []
|
|
451
|
-
}
|
|
452
|
-
await framework.loadPlugin(new WeixinPlugin(weixinConfig))
|
|
453
|
-
} catch (err) {
|
|
454
|
-
bootstrapLog.warn(' WeChat Plugin not available:', err.message)
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// 12.8 Email 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
|
|
459
|
-
if (shouldLoad('email')) {
|
|
460
|
-
try {
|
|
461
|
-
const { Plugin } = require('../src/core/plugin-base')
|
|
462
|
-
const { logger } = require('../src/utils/logger')
|
|
463
|
-
const log = logger.child('AgentConfig')
|
|
464
|
-
const bootstrapLog = logger.child('Bootstrap')
|
|
465
|
-
const { EmailPlugin } = require('./email')
|
|
466
|
-
// 支持两种格式:email.smtp 或 email.config.smtp
|
|
467
|
-
const emailData = agentConfig.email || {}
|
|
468
|
-
const emailCfg = emailData.config || {}
|
|
469
|
-
const emailConfig = {
|
|
470
|
-
smtp: emailCfg.smtp || emailData.smtp || {},
|
|
471
|
-
imap: emailCfg.imap || emailData.imap || {},
|
|
472
|
-
clientId: emailCfg.clientId || emailData.clientId
|
|
473
|
-
}
|
|
474
|
-
await framework.loadPlugin(new EmailPlugin(emailConfig))
|
|
475
|
-
} catch (err) {
|
|
476
|
-
bootstrapLog.warn(' Email Plugin not available:', err.message)
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// 12.9 Feishu 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
|
|
481
|
-
if (shouldLoad('feishu')) {
|
|
482
|
-
try {
|
|
483
|
-
const { FeishuPlugin } = require('./feishu-plugin')
|
|
484
|
-
const feishuConfig = {
|
|
485
|
-
allowedUsers: agentConfig.feishu?.allowedUsers || []
|
|
486
|
-
}
|
|
487
|
-
await framework.loadPlugin(new FeishuPlugin(feishuConfig))
|
|
488
|
-
} catch (err) {
|
|
489
|
-
bootstrapLog.warn(' Feishu Plugin not available:', err.message)
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// 12.10 SubAgent 管理器
|
|
340
|
+
// 5. SubAgent 管理器(需要特殊初始化 SubAgentConfigManager)
|
|
494
341
|
if (shouldLoad('subagent-manager')) {
|
|
495
342
|
try {
|
|
496
|
-
// 先初始化 SubAgentConfigManager 并加载所有配置
|
|
497
343
|
const { SubAgentConfigManager } = require('../src/core/sub-agent-config')
|
|
498
344
|
const subAgentConfigManager = new SubAgentConfigManager(agentConfig.agentsDir)
|
|
499
345
|
subAgentConfigManager.loadAll()
|
|
500
346
|
framework._subAgentConfigManager = subAgentConfigManager
|
|
501
347
|
|
|
502
|
-
// 然后加载 SubAgentManagerPlugin
|
|
503
348
|
const { SubAgentManagerPlugin } = require('./subagent-plugin')
|
|
504
349
|
await framework.loadPlugin(new SubAgentManagerPlugin({ agentsDir: agentConfig.agentsDir }))
|
|
505
350
|
framework._debug&&bootstrapLog.debug(' SubAgent Manager loaded')
|
|
@@ -508,7 +353,7 @@ const bootstrapLog = logger.child('Bootstrap')
|
|
|
508
353
|
}
|
|
509
354
|
}
|
|
510
355
|
|
|
511
|
-
//
|
|
356
|
+
// 6. 自动加载 plugins/ 目录下的所有插件
|
|
512
357
|
await loadCustomPlugins(framework, agentConfig)
|
|
513
358
|
|
|
514
359
|
framework._debug&&bootstrapLog.debug(' All plugins loaded')
|
|
@@ -598,56 +443,94 @@ function scanPluginNames(pluginsDir) {
|
|
|
598
443
|
}
|
|
599
444
|
|
|
600
445
|
async function loadCustomPlugins(framework, agentConfig) {
|
|
601
|
-
|
|
602
|
-
|
|
446
|
+
const { Plugin } = require('../src/core/plugin-base')
|
|
447
|
+
|
|
448
|
+
// 加载两个目录下的自定义插件:
|
|
449
|
+
// 1. .agent/plugins/ - 用户自定义插件(强制启用)
|
|
450
|
+
// 2. plugins/ - 项目内置插件(自动加载)
|
|
451
|
+
const dirs = [
|
|
452
|
+
{ dir: path.resolve(process.cwd(), '.agent', 'plugins'), forceEnabled: true },
|
|
453
|
+
{ dir: path.resolve(process.cwd(), 'plugins'), forceEnabled: false }
|
|
454
|
+
]
|
|
603
455
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
456
|
+
for (const { dir, forceEnabled } of dirs) {
|
|
457
|
+
if (!fs.existsSync(dir)) {
|
|
458
|
+
continue
|
|
459
|
+
}
|
|
607
460
|
|
|
608
|
-
|
|
609
|
-
|
|
461
|
+
// 扫描所有插件名称(支持文件夹和单文件)
|
|
462
|
+
const pluginNames = scanPluginNames(dir)
|
|
610
463
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
464
|
+
for (const pluginName of pluginNames) {
|
|
465
|
+
try {
|
|
466
|
+
const resolved = resolvePluginPath(dir, pluginName)
|
|
467
|
+
if (!resolved) {
|
|
468
|
+
continue
|
|
469
|
+
}
|
|
618
470
|
|
|
619
|
-
|
|
471
|
+
const { path: pluginPath, type } = resolved
|
|
472
|
+
|
|
473
|
+
// 清除缓存
|
|
474
|
+
delete require.cache[require.resolve(pluginPath)]
|
|
475
|
+
const pluginModule = require(pluginPath)
|
|
476
|
+
|
|
477
|
+
let plugin
|
|
478
|
+
if (typeof pluginModule === 'function') {
|
|
479
|
+
plugin = pluginModule
|
|
480
|
+
} else if (pluginModule.default) {
|
|
481
|
+
plugin = pluginModule.default
|
|
482
|
+
} else {
|
|
483
|
+
// 支持具名导出 { PluginClass } 或 { PluginClass, Other }
|
|
484
|
+
// 找到第一个是 Plugin 子类的导出
|
|
485
|
+
const keys = Object.keys(pluginModule)
|
|
486
|
+
let foundPlugin = null
|
|
487
|
+
for (const key of keys) {
|
|
488
|
+
const exp = pluginModule[key]
|
|
489
|
+
if (typeof exp === 'function' && exp.prototype instanceof Plugin) {
|
|
490
|
+
foundPlugin = exp
|
|
491
|
+
break
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
plugin = foundPlugin || pluginModule
|
|
495
|
+
}
|
|
620
496
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
497
|
+
// 获取插件名称(参考 plugin-manager 的逻辑)
|
|
498
|
+
let resolvedPluginName = pluginName
|
|
499
|
+
if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
|
|
500
|
+
// Plugin 子类:实例化获取名称
|
|
501
|
+
const instance = new plugin()
|
|
502
|
+
resolvedPluginName = instance.name || pluginName
|
|
503
|
+
} else if (typeof plugin === 'function') {
|
|
504
|
+
// 工厂函数
|
|
505
|
+
const result = plugin(Plugin)
|
|
506
|
+
resolvedPluginName = result?.name || pluginName
|
|
507
|
+
} else {
|
|
508
|
+
resolvedPluginName = plugin?.name || pluginName
|
|
509
|
+
}
|
|
624
510
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
plugin = pluginModule.default
|
|
631
|
-
} else {
|
|
632
|
-
plugin = pluginModule
|
|
633
|
-
}
|
|
511
|
+
// 如果插件已加载且已启动,跳过
|
|
512
|
+
if (framework.pluginManager.has(resolvedPluginName) &&
|
|
513
|
+
framework.pluginManager.get(resolvedPluginName)?._started) {
|
|
514
|
+
continue
|
|
515
|
+
}
|
|
634
516
|
|
|
635
|
-
|
|
636
|
-
const tempPlugin = typeof plugin === 'function' && plugin.prototype?.name
|
|
637
|
-
? new plugin() : plugin
|
|
638
|
-
const resolvedPluginName = tempPlugin.name || pluginName
|
|
517
|
+
bootstrapLog.debug(` Loading plugin: ${resolvedPluginName} (${type})`)
|
|
639
518
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
framework.pluginManager.get(resolvedPluginName)?._started) {
|
|
643
|
-
continue
|
|
644
|
-
}
|
|
519
|
+
// 从 agentConfig 获取插件配置
|
|
520
|
+
const pluginConfig = agentConfig[resolvedPluginName] || {}
|
|
645
521
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
522
|
+
// 实例化插件并传入配置
|
|
523
|
+
let pluginInstance
|
|
524
|
+
if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
|
|
525
|
+
pluginInstance = new plugin(pluginConfig)
|
|
526
|
+
} else {
|
|
527
|
+
pluginInstance = plugin
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
await framework.pluginManager.load(pluginInstance, { forceEnabled })
|
|
531
|
+
} catch (err) {
|
|
532
|
+
log.error(` Failed to load plugin ${pluginName}:`, err.message)
|
|
533
|
+
}
|
|
651
534
|
}
|
|
652
535
|
}
|
|
653
536
|
}
|
package/plugins/email/index.js
CHANGED