foliko 1.1.13 → 1.1.15
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/plugins-state.json +1 -1
- package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
- package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
- package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
- package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
- package/.agent/mcp_config.json +7 -0
- package/.agent/memory/feedback/mnxe0cxc-14l6q5.md +17 -0
- package/.agent/memory/feedback/mnxe11pa-nxf577.md +9 -0
- package/.agent/memory/feedback/mnxe1an2-84faff.md +9 -0
- package/.agent/memory/feedback/mnxgcfj0-qg3wjc.md +9 -0
- package/.agent/memory/feedback/mnxgcn3y-40mqss.md +9 -0
- package/.agent/memory/feedback/mnxgcxq9-jm7ydl.md +9 -0
- package/.agent/memory/feedback/mnxgdyfj-pzjvkb.md +9 -0
- package/.agent/memory/feedback/mnxge3z1-7vyit1.md +9 -0
- package/.agent/memory/feedback/mnxhrg28-41hhjr.md +9 -0
- package/.agent/memory/feedback/mnxhrx0e-yth94k.md +9 -0
- package/.agent/memory/feedback/mnxhs3jd-rvx8aq.md +9 -0
- package/.agent/memory/feedback/mnxhs7p7-g5rtn9.md +9 -0
- package/.agent/memory/feedback/mnxhslx5-oqwuhr.md +9 -0
- package/.agent/memory/feedback/mnxhsvd6-nuyvvc.md +9 -0
- package/.agent/memory/project/mnxegq6z-5fc64w.md +22 -0
- package/.agent/memory/project/mnxh2w4r-le9hur.md +17 -0
- package/.agent/memory/project/mnxhq2yv-9qa8ay.md +31 -0
- package/.agent/memory/project/mnxhql11-iaun2o.md +34 -0
- package/.agent/memory/project/mnxhr78p-jpg7eq.md +23 -0
- package/.agent/memory/reference/mnxe0oa9-p6wzk6.md +27 -0
- package/.agent/memory/reference/mnxehcll-kcrmpf.md +29 -0
- package/.agent/memory/reference/mnxei0ts-jw091y.md +18 -0
- package/.agent/memory/reference/mnxfnrr4-rski36.md +40 -0
- package/.agent/memory/reference/mnxfo6n5-af9zls.md +18 -0
- package/.agent/memory/reference/mnxh2ady-u6cmvk.md +61 -0
- package/.agent/memory/reference/mnxhqdqh-ucsbsk.md +31 -0
- package/.agent/memory/reference/mnxiixyp-rz2gvw.md +34 -0
- package/.agent/memory/user/mnxhqxk3-vjjhlf.md +23 -0
- package/.agent/sessions/cli_default.json +11 -639
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +25 -0
- package/.claude/settings.local.json +23 -1
- package/cli/src/commands/chat.js +9 -15
- package/cli/src/ui/chat-ui.js +40 -71
- package/package.json +4 -2
- package/plugins/default-plugins.js +5 -5
- package/plugins/file-system-plugin.js +1 -1
- package/plugins/memory-plugin.js +12 -12
- package/plugins/plugin-manager-plugin.js +1 -0
- package/plugins/subagent-plugin.js +55 -1
- package/plugins/telegram-plugin.js +9 -6
- package/plugins/weixin-plugin.js +75 -78
- package/src/core/agent-chat.js +468 -1612
- package/src/core/agent.js +53 -134
- package/src/core/chat-session.js +423 -0
- package/src/core/context-compressor.js +473 -0
- package/src/core/context-manager.js +0 -48
- package/src/core/framework.js +95 -68
- package/src/core/index.js +11 -0
- package/src/core/notification-manager.js +125 -0
- package/src/core/subagent.js +295 -0
- package/src/core/token-counter.js +190 -0
- package/src/core/tool-executor.js +270 -0
- package/src/executors/mcp-executor.js +14 -1
- package/src/utils/download.js +596 -0
- package/system.md +312 -2373
- package/.agent/agents/code-assistant.json +0 -17
- package/.agent/agents/email-assistant.json +0 -14
- package/.agent/agents/file-assistant.json +0 -18
- package/.agent/agents/orchestrator-demo.md +0 -53
- package/.agent/agents/orchestrator.json +0 -7
- package/.agent/agents/poster-expert.md +0 -228
- package/.agent/agents/system-assistant.json +0 -15
- package/.agent/agents/web-assistant.json +0 -12
- package/.agent/memory/feedback/mnv3nu27-3o15pf.md +0 -9
- package/.agent/memory/feedback/mnv3o078-b959yj.md +0 -9
- package/.agent/memory/feedback/mnv3o6ej-u0fif5.md +0 -9
- package/.agent/memory/feedback/mnv3obgl-bkkjoj.md +0 -9
- package/.agent/memory/feedback/mnv4a3js-dv6onx.md +0 -9
- package/.agent/memory/feedback/mnv4aacm-sxxowp.md +0 -9
- package/.agent/memory/feedback/mnv4ahto-w40ffm.md +0 -9
- package/.agent/memory/feedback/mnv4anvp-3cs06y.md +0 -9
- package/.agent/memory/feedback/mnvzgvtd-0o2900.md +0 -9
- package/.agent/memory/feedback/mnvzhajn-swbx61.md +0 -15
- package/.agent/memory/feedback/mnvzhgsp-p5vog3.md +0 -9
- package/.agent/memory/feedback/mnvzho0c-fgql7q.md +0 -14
- package/.agent/memory/feedback/mnvzhtzq-ufr5at.md +0 -9
- package/.agent/memory/feedback/mnvzhyb3-9byq2z.md +0 -9
- package/.agent/memory/feedback/mnvzi7hp-hyeafp.md +0 -9
- package/.agent/memory/feedback/mnvzibph-z7rwp5.md +0 -9
- package/.agent/memory/feedback/mnvzilys-7h176w.md +0 -14
- package/.agent/memory/feedback/mnvziuh5-zjshci.md +0 -9
- package/.agent/memory/feedback/mnw07wde-6zqsc8.md +0 -9
- package/.agent/memory/feedback/mnw084bp-j0ba2a.md +0 -9
- package/.agent/memory/user/mnv3n62r-y0h79j.md +0 -21
- package/.agent/memory/user/mnv3n9yf-ead4g8.md +0 -13
- package/.agent/memory/user/mnv3ne3j-82tq1k.md +0 -19
- package/.agent/memory/user/mnv3nhgm-g2s2us.md +0 -11
- package/.agent/memory/user/mnv3nl9u-ejd998.md +0 -16
- package/.agent/memory/user/mnv3nofp-ya5szl.md +0 -10
- package/.agent/memory/user/mnv49qne-bhk0ki.md +0 -9
- package/.agent/memory/user/mnv49w3y-rzr8ju.md +0 -13
- package/.agent/sessions/test.json +0 -16
- package/plugins/python-plugin-loader.js.bak +0 -856
- package/src/core/agent-context.js +0 -188
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sessionId": "weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat",
|
|
3
|
+
"messages": [
|
|
4
|
+
{
|
|
5
|
+
"role": "user",
|
|
6
|
+
"content": "\n [用户发送了图片消息]\n\n 文件列表:\n\n [\n \"D:\\\\Code\\\\foliko\\\\.agent\\\\data\\\\weixin\\\\images\\\\file_1776189097450.jpg\"\n] \n\n \n *重要:* 不要试图读取文件内容!\n "
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"role": "assistant",
|
|
10
|
+
"content": [
|
|
11
|
+
{
|
|
12
|
+
"type": "text",
|
|
13
|
+
"text": "<think>\n用户发送了一张图片,路径是 \"D:\\\\Code\\\\foliko\\\\.agent\\\\data\\\\weixin\\\\images\\\\file_1776189097450.jpg\"。我需要帮助用户查看这张图片的内容。\n\n我可以直接使用 read_file 工具来读取图片文件,但用户说不要试图读取文件内容。不过,用户可能是想让我帮忙识别图片内容或进行其他处理。\n\n让我先看看这张图片是什么类型的文件,然后尝试理解用户的需求。由于这是一个图片文件,我可以考虑使用 Python 来处理它,或者直接向用户询问他们想对这张图片做什么。\n\n实际上,从工具列表来看,我没有专门处理图片的工具。我应该告诉用户我收到了图片,并询问他们想对这张图片做什么。\n\n等等,用户说的是\"不要试图读取文件内容\",这可能是因为:\n1. 图片是私密内容,不想让我知道\n2. 只是想让我识别图片内容\n3. 担心读取大文件会有问题\n\n无论如何,我应该询问用户他们希望我对这张图片做什么操作。\n</think>\n\n我收到了你发送的图片文件。请问你想对这张图片做什么处理?比如:\n\n- **识别图片内容**(描述图片中的内容)\n- **提取图片文字**(OCR)\n- **查看图片信息**(尺寸、格式、大小等)\n- **其他处理**\n\n请告诉我你的需求,我会帮你处理。"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"variables": {},
|
|
19
|
+
"metadata": {
|
|
20
|
+
"createdAt": 1776188690731,
|
|
21
|
+
"lastActive": 1776188690731,
|
|
22
|
+
"messageCount": 0,
|
|
23
|
+
"compressionCount": 0
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -180,7 +180,29 @@
|
|
|
180
180
|
"Bash(cd \"D:/Code/foliko\" && node -e \"require\\('./plugins/extension-executor-plugin'\\); console.log\\('OK'\\)\")",
|
|
181
181
|
"Bash(cd D:/Code/foliko && timeout 8s node cli/bin/foliko.js chat 2>&1 || true)",
|
|
182
182
|
"Bash(cd /d/Code/foliko-plugins/poster-plugin && node -e \"\nconst LayoutManager = require\\('./src/layout-manager'\\);\nconsole.log\\('LayoutManager loaded successfully'\\);\nconsole.log\\('Methods:', Object.getOwnPropertyNames\\(LayoutManager.prototype\\).join\\(', '\\)\\);\n\")",
|
|
183
|
-
"Bash(node test-ctx-push.js 2>&1 | head -50)"
|
|
183
|
+
"Bash(node test-ctx-push.js 2>&1 | head -50)",
|
|
184
|
+
"Bash(cd D:/code/vb-agent && node -e \"const { Framework } = require\\('./src/core/framework'\\); const f = new Framework\\({ debug: true }\\); console.log\\('Framework loaded OK'\\); console.log\\('ContextManager stats:', f._contextManager.getStats\\(\\)\\);\")",
|
|
185
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nconst { Framework } = require\\('./src/core/framework'\\);\nconst { NotificationManager } = require\\('./src/core/notification-manager'\\);\nconst f = new Framework\\({ debug: true }\\);\nconst agent = f.createAgent\\({ name: 'test' }\\);\nconsole.log\\('Agent created OK'\\);\nconsole.log\\('Has notificationManager:', !!agent._notificationManager\\);\nconsole.log\\('NotificationManager type:', agent._notificationManager.constructor.name\\);\n\")",
|
|
186
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nconst { Framework } = require\\('./src/core/framework'\\);\nconst { NotificationManager } = require\\('./src/core/notification-manager'\\);\nconst { TokenCounter } = require\\('./src/core/token-counter'\\);\n\nconst f = new Framework\\({ debug: true }\\);\nconst agent = f.createAgent\\({ name: 'test' }\\);\n\nconsole.log\\('=== 验证结果 ==='\\);\nconsole.log\\('Framework: OK'\\);\nconsole.log\\('NotificationManager: OK \\(has enhanceMessage:', typeof agent._notificationManager.enhanceMessage === 'function', '\\)'\\);\nconsole.log\\('TokenCounter: OK \\(has countMessages:', typeof TokenCounter.prototype.countMessages === 'function', '\\)'\\);\n\n// 检查 AgentContext 是否被删除\ntry {\n require\\('./src/core/agent-context'\\);\n console.log\\('AgentContext: FAILED \\(should not exist\\)'\\);\n} catch \\(e\\) {\n console.log\\('AgentContext: OK \\(deleted\\)'\\);\n}\n\n// 检查 ContextManager 是否正常工作\nconsole.log\\('ContextManager stats:', f._contextManager.getStats\\(\\)\\);\n\")",
|
|
187
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nconst { Framework } = require\\('./src/core/framework'\\);\nconst f = new Framework\\({ debug: true }\\);\n\n// 创建 Agent\nconst agent = f.createAgent\\({ \n name: 'TestAgent',\n systemPrompt: '你是一个测试助手'\n}\\);\n\nconsole.log\\('Agent created:', agent.name\\);\nconsole.log\\('Agent has _chatHandler:', !!agent._chatHandler\\);\nconsole.log\\('AgentChatHandler type:', agent._chatHandler?.constructor?.name\\);\n\n// 测试 chat 方法是否存在\nconsole.log\\('Agent.chat is function:', typeof agent.chat === 'function'\\);\nconsole.log\\('Agent._chatHandler.chat is function:', typeof agent._chatHandler?.chat === 'function'\\);\n\n// 测试 Agent._buildSystemPrompt\nconsole.log\\('Agent._buildSystemPrompt is function:', typeof agent._buildSystemPrompt === 'function'\\);\nconsole.log\\('System prompt length:', agent.systemPrompt?.length || 0\\);\n\")",
|
|
188
|
+
"Bash(cd D:/code/vb-agent && node -e \"const { generateText, streamText } = require\\('ai'\\); console.log\\(typeof streamText\\)\" 2>&1)",
|
|
189
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nconst { createAI, createModel } = require\\('./src/core/provider'\\);\nconst { streamText } = require\\('ai'\\);\n\nconst aiProvider = createAI\\({\n provider: 'minimax',\n model: 'MiniMax-text-01',\n apiKey: process.env.MINIMAX_API_KEY || 'test',\n baseURL: 'https://api.minimaxi.com/v1',\n}\\);\nconst model = createModel\\('MiniMax-text-01', aiProvider\\);\n\nconst result = streamText\\({\n model,\n system: 'You are helpful',\n messages: [{ role: 'user', content: 'hi' }],\n}\\);\n\nconsole.log\\('baseStream type:', typeof result.baseStream\\);\nconsole.log\\('baseStream:', result.baseStream\\);\n\n// 尝试直接遍历\n\\(async \\(\\) => {\n try {\n for await \\(const chunk of result\\) {\n console.log\\('chunk:', chunk\\);\n }\n } catch \\(e\\) {\n console.error\\('error:', e.message\\);\n }\n}\\)\\(\\);\n\" 2>&1)",
|
|
190
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nrequire\\('dotenv'\\).config\\(\\);\nconsole.log\\('MINIMAX_API_KEY:', process.env.MINIMAX_API_KEY ? 'set \\(' + process.env.MINIMAX_API_KEY.substring\\(0, 10\\) + '...\\)' : 'NOT SET'\\);\nconsole.log\\('DEEPSEEK_API_KEY:', process.env.DEEPSEEK_API_KEY ? 'set \\(' + process.env.DEEPSEEK_API_KEY.substring\\(0, 10\\) + '...\\)' : 'NOT SET'\\);\n\" 2>&1)",
|
|
191
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nrequire\\('dotenv'\\).config\\(\\);\nconst { Framework } = require\\('./src/core/framework'\\);\n\n\\(async \\(\\) => {\n const framework = new Framework\\({ debug: false }\\);\n await framework.bootstrap\\({\n agentDir: 'D:/code/vb-agent/.agent',\n aiConfig: {\n provider: 'minimax',\n model: 'MiniMax-M2.7',\n baseURL: 'https://api.minimaxi.com/v1',\n apiKey: process.env.FOLIKO_API_KEY,\n },\n }\\);\n \n const agent = framework._mainAgent;\n console.log\\('Agent provider:', agent.provider\\);\n console.log\\('Agent apiKey:', agent.apiKey ? agent.apiKey.substring\\(0, 15\\) : 'undefined'\\);\n console.log\\('Agent baseURL:', agent.baseURL\\);\n process.exit\\(0\\);\n}\\)\\(\\);\n\" 2>&1)",
|
|
192
|
+
"Bash(cd D:/code/vb-agent && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('tool'\\) || k.toLowerCase\\(\\).includes\\('loop'\\)\\)\\)\" 2>&1)",
|
|
193
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nrequire\\('dotenv'\\).config\\(\\);\nconst { Framework } = require\\('./src/core/framework'\\);\n\n\\(async \\(\\) => {\n const framework = new Framework\\({ debug: false }\\);\n await framework.bootstrap\\({\n agentDir: 'D:/code/vb-agent/.agent',\n aiConfig: {\n provider: 'minimax',\n model: 'MiniMax-M2.7',\n baseURL: 'https://api.minimaxi.com/v1',\n apiKey: process.env.FOLIKO_API_KEY,\n },\n }\\);\n \n const agent = framework._mainAgent;\n console.log\\('Testing chat...'\\);\n \n try {\n const result = await agent.chat\\('say hi in 3 words', {}\\);\n console.log\\('Result:', result.message?.substring\\(0, 50\\)\\);\n } catch \\(e\\) {\n console.error\\('Error:', e.message\\);\n }\n process.exit\\(0\\);\n}\\)\\(\\);\n\" 2>&1)",
|
|
194
|
+
"Bash(cd D:/code/vb-agent && node -e \"\nrequire\\('dotenv'\\).config\\(\\);\nconst { Framework } = require\\('./src/core/framework'\\);\n\n\\(async \\(\\) => {\n const framework = new Framework\\({ debug: false }\\);\n await framework.bootstrap\\({\n agentDir: 'D:/code/vb-agent/.agent',\n aiConfig: {\n provider: 'minimax',\n model: 'MiniMax-M2.7',\n baseURL: 'https://api.minimaxi.com/v1',\n apiKey: process.env.FOLIKO_API_KEY,\n },\n }\\);\n \n const agent = framework._mainAgent;\n let full = '';\n try {\n for await \\(const chunk of agent.chatStream\\('say hi', {}\\)\\) {\n if \\(chunk.type === 'text'\\) {\n full += chunk.text;\n process.stdout.write\\(chunk.text\\);\n }\n }\n console.log\\('\\\\\\\\nFull:', full.length\\);\n } catch \\(e\\) {\n console.error\\('Error:', e.message\\);\n }\n process.exit\\(0\\);\n}\\)\\(\\);\n\" 2>&1)",
|
|
195
|
+
"Bash(node -e \"require\\('./src/core/chat-session.js'\\); require\\('./src/core/agent-chat.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
196
|
+
"Bash(node -e \"require\\('./src/core/chat-session.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
197
|
+
"Bash(node -e \"require\\('./cli/src/ui/chat-ui.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
198
|
+
"Bash(node -e \"\nconst { ToolLoopAgent, isLoopFinished, generateText, streamText } = require\\('ai'\\);\nconsole.log\\('ToolLoopAgent imported:', typeof ToolLoopAgent\\);\nconsole.log\\('isLoopFinished:', typeof isLoopFinished\\);\nconsole.log\\('ToolLoopAgent methods:', Object.getOwnPropertyNames\\(ToolLoopAgent.prototype\\)\\);\n\" 2>&1)",
|
|
199
|
+
"Bash(node -e \"\nconst { isLoopFinished } = require\\('ai'\\);\nconsole.log\\('isLoopFinished:', isLoopFinished.toString\\(\\).slice\\(0, 500\\)\\);\n\" 2>&1)",
|
|
200
|
+
"Bash(node -e \"require\\('./plugins/weixin-plugin.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
201
|
+
"Bash(node -e \"require\\('./src/core/tool-executor.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
202
|
+
"Bash(node -e \"\nconst { createTools } = require\\('ai'\\);\nconsole.log\\('createTools exists:', typeof createTools\\);\n\" 2>&1)",
|
|
203
|
+
"Bash(node -e \"\nconst poster = require\\('/d/code/foliko-plugins/poster-plugin'\\);\nconsole.log\\('poster.tools:', typeof poster.tools\\);\nconsole.log\\('poster.tools keys:', Object.keys\\(poster.tools || {}\\).slice\\(0, 5\\)\\);\n\" 2>&1)",
|
|
204
|
+
"Bash(node -e \"require\\('./src/core/agent-chat.js'\\); console.log\\('OK'\\)\" 2>&1)",
|
|
205
|
+
"Bash(node -e \"const ai = require\\('ai'\\); console.log\\('tool type:', typeof ai.tool\\)\")"
|
|
184
206
|
]
|
|
185
207
|
}
|
|
186
208
|
}
|
package/cli/src/commands/chat.js
CHANGED
|
@@ -112,8 +112,6 @@ async function runContinuousTest(agent, options) {
|
|
|
112
112
|
console.log(`命令数量: ${commands.length}`);
|
|
113
113
|
console.log('');
|
|
114
114
|
|
|
115
|
-
const runWithContext = agent.framework?.runWithContext.bind(agent.framework);
|
|
116
|
-
|
|
117
115
|
for (let i = 0; i < commands.length; i++) {
|
|
118
116
|
const cmd = commands[i];
|
|
119
117
|
console.log(`\n[${i + 1}/${commands.length}] >>> ${cmd}`);
|
|
@@ -121,26 +119,22 @@ async function runContinuousTest(agent, options) {
|
|
|
121
119
|
|
|
122
120
|
try {
|
|
123
121
|
let fullResponse = '';
|
|
124
|
-
await
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
console.error(`\n[错误] ${chunk.error}`);
|
|
133
|
-
}
|
|
122
|
+
for await (const chunk of agent.chatStream(cmd, { sessionId })) {
|
|
123
|
+
if (chunk.type === 'text') {
|
|
124
|
+
fullResponse += chunk.text;
|
|
125
|
+
process.stdout.write(chunk.text);
|
|
126
|
+
} else if (chunk.type === 'tool-call') {
|
|
127
|
+
console.log(`\n[工具调用] ${chunk.toolName} ${JSON.stringify(chunk.input)}`);
|
|
128
|
+
} else if (chunk.type === 'error') {
|
|
129
|
+
console.error(`\n[错误] ${chunk.error}`);
|
|
134
130
|
}
|
|
135
|
-
}
|
|
131
|
+
}
|
|
136
132
|
console.log('\n' + '-'.repeat(50));
|
|
137
133
|
console.log(`[完成] 回复长度: ${fullResponse.length}`);
|
|
138
134
|
} catch (err) {
|
|
139
135
|
console.error(`\n[执行错误] ${err.message}`);
|
|
140
|
-
// 继续执行下一条命令
|
|
141
136
|
}
|
|
142
137
|
|
|
143
|
-
// 命令间隔 1 秒
|
|
144
138
|
await new Promise((r) => setTimeout(r, 1000));
|
|
145
139
|
}
|
|
146
140
|
|
package/cli/src/ui/chat-ui.js
CHANGED
|
@@ -125,10 +125,8 @@ class ChatUI {
|
|
|
125
125
|
* 发送消息并显示响应
|
|
126
126
|
*/
|
|
127
127
|
async sendMessage(message) {
|
|
128
|
-
// 用于打断的标志
|
|
129
128
|
let interrupted = false;
|
|
130
129
|
|
|
131
|
-
// 设置打断处理
|
|
132
130
|
const interruptHandler = () => {
|
|
133
131
|
if (!interrupted) {
|
|
134
132
|
interrupted = true;
|
|
@@ -136,78 +134,58 @@ class ChatUI {
|
|
|
136
134
|
}
|
|
137
135
|
};
|
|
138
136
|
|
|
139
|
-
// 监听 Ctrl+C
|
|
140
137
|
process.on('SIGINT', interruptHandler);
|
|
141
138
|
|
|
142
|
-
let fullResponse = '';
|
|
143
|
-
let sessionScope = null;
|
|
144
|
-
|
|
145
139
|
try {
|
|
146
140
|
const renderState = { inThink: false, inCodeBlock: false };
|
|
147
|
-
const runWithContext = this.agent.framework?.runWithContext.bind(this.agent.framework);
|
|
148
141
|
const { sessionId } = this;
|
|
149
142
|
|
|
150
|
-
// 创建当前 session 的事件作用域,自动过滤其他 session 的事件
|
|
151
|
-
sessionScope = this.agent.createSessionScope(sessionId);
|
|
152
|
-
|
|
153
143
|
if (this.stream) {
|
|
154
|
-
// 流式模式
|
|
144
|
+
// 流式模式 - 使用事件方式
|
|
155
145
|
console.log(colored('● ', GREEN));
|
|
156
146
|
|
|
157
147
|
let lineBuffer = '';
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
} else if (chunk.type === 'tool-call') {
|
|
179
|
-
console.log(
|
|
180
|
-
`\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`,
|
|
181
|
-
`args=`,
|
|
182
|
-
JSON.stringify(chunk.input)
|
|
183
|
-
);
|
|
184
|
-
} else if (chunk.type === 'error') {
|
|
185
|
-
console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
sessionScope.on('message:complete', ({ sessionId, content }) => {
|
|
190
|
-
const message = '继续下一步';
|
|
191
|
-
if (!content) {
|
|
192
|
-
console.log(colored(`● ${message}...`, DIM));
|
|
193
|
-
this.agent.sendMessage(message, {
|
|
194
|
-
sessionId: sessionId,
|
|
195
|
-
priority: 1,
|
|
196
|
-
});
|
|
148
|
+
let hasToolCall = false;
|
|
149
|
+
|
|
150
|
+
// 创建 session scope 过滤事件
|
|
151
|
+
const sessionScope = this.agent.createSessionScope(sessionId);
|
|
152
|
+
|
|
153
|
+
// 监听流式数据
|
|
154
|
+
sessionScope.on('stream:chunk', ({ chunk }) => {
|
|
155
|
+
if (interrupted) return;
|
|
156
|
+
|
|
157
|
+
if (chunk.type === 'text') {
|
|
158
|
+
lineBuffer += chunk.text;
|
|
159
|
+
|
|
160
|
+
while (lineBuffer.includes('\n')) {
|
|
161
|
+
if (interrupted) break;
|
|
162
|
+
|
|
163
|
+
const nlIndex = lineBuffer.indexOf('\n');
|
|
164
|
+
const line = lineBuffer.substring(0, nlIndex);
|
|
165
|
+
lineBuffer = lineBuffer.substring(nlIndex + 1);
|
|
166
|
+
if (line.trim()) {
|
|
167
|
+
console.log(renderLine(line, renderState));
|
|
197
168
|
}
|
|
198
|
-
}
|
|
169
|
+
}
|
|
170
|
+
} else if (chunk.type === 'tool-call') {
|
|
171
|
+
if (!hasToolCall) {
|
|
172
|
+
hasToolCall = true;
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
console.log(
|
|
176
|
+
`${colored('[工具调用]', YELLOW)} ${chunk.toolName}`,
|
|
177
|
+
`args=`,
|
|
178
|
+
JSON.stringify(chunk.input)
|
|
179
|
+
);
|
|
180
|
+
} else if (chunk.type === 'error') {
|
|
181
|
+
console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
|
|
199
182
|
}
|
|
200
|
-
|
|
201
|
-
const result = await this.agent.sendMessage(message, {
|
|
202
|
-
sessionId: sessionId,
|
|
203
|
-
priority: 1,
|
|
204
|
-
});
|
|
205
183
|
});
|
|
206
184
|
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
185
|
+
// 调用 sendMessage 触发事件
|
|
186
|
+
const res = await this.agent.sendMessage(message, { sessionId });
|
|
187
|
+
// 清理
|
|
188
|
+
sessionScope.removeAllListeners();
|
|
211
189
|
|
|
212
190
|
if (lineBuffer.trim() && !interrupted) {
|
|
213
191
|
console.log(renderLine(lineBuffer, renderState));
|
|
@@ -216,16 +194,11 @@ class ChatUI {
|
|
|
216
194
|
// 非流式模式
|
|
217
195
|
console.log(colored('○ ', CYAN) + '处理中...\n');
|
|
218
196
|
|
|
219
|
-
const result = await
|
|
220
|
-
return await this.agent.chat(message, { sessionId });
|
|
221
|
-
});
|
|
197
|
+
const result = await this.agent.chat(message, { sessionId });
|
|
222
198
|
|
|
223
199
|
if (interrupted) return;
|
|
224
200
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// 一次性渲染完整响应
|
|
228
|
-
const lines = fullResponse.split('\n');
|
|
201
|
+
const lines = result.message.split('\n');
|
|
229
202
|
for (const line of lines) {
|
|
230
203
|
if (line.trim()) {
|
|
231
204
|
console.log(renderLine(line, renderState));
|
|
@@ -240,10 +213,6 @@ class ChatUI {
|
|
|
240
213
|
console.error(`\n${colored('[错误]', RED)} ${err.message}\n`);
|
|
241
214
|
}
|
|
242
215
|
} finally {
|
|
243
|
-
// 确保清理 session scope 的监听器
|
|
244
|
-
if (sessionScope) {
|
|
245
|
-
sessionScope.removeAllListeners();
|
|
246
|
-
}
|
|
247
216
|
process.removeListener('SIGINT', interruptHandler);
|
|
248
217
|
}
|
|
249
218
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foliko",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.15",
|
|
4
4
|
"description": "简约的插件化 Agent 框架",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -53,13 +53,15 @@
|
|
|
53
53
|
"@ai-sdk/openai": "^3.0.41",
|
|
54
54
|
"@ai-sdk/openai-compatible": "^2.0.35",
|
|
55
55
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
56
|
-
"@chnak/weixin-bot": "^1.2.
|
|
56
|
+
"@chnak/weixin-bot": "^1.2.9",
|
|
57
57
|
"@chnak/zod-to-markdown": "1.0.7",
|
|
58
58
|
"@hono/node-server": "^1.19.11",
|
|
59
59
|
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
60
60
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
61
61
|
"ai": "^6.0.146",
|
|
62
|
+
"crypto": "^1.0.1",
|
|
62
63
|
"dotenv": "^17.3.1",
|
|
64
|
+
"file-type": "^22.0.1",
|
|
63
65
|
"gate-api": "^7.2.57",
|
|
64
66
|
"hono": "^4.12.9",
|
|
65
67
|
"imap-mkl": "^1.0.2",
|
|
@@ -279,13 +279,13 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
279
279
|
|
|
280
280
|
framework._debug&&bootstrapLog.debug(' Loading default plugins...')
|
|
281
281
|
// AI 插件(如果已禁用则跳过)
|
|
282
|
-
|
|
282
|
+
// 根据 provider 获取对应的 API key
|
|
283
|
+
const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
|
|
284
|
+
const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
|
|
285
|
+
if (!shouldLoad('ai') || !(aiConfig.provider || aiConfig.model || aiConfig.apiKey || envApiKey)) {
|
|
283
286
|
// 跳过或已禁用
|
|
284
287
|
} else {
|
|
285
288
|
const AIPlugin = require('./ai-plugin')
|
|
286
|
-
// 根据 provider 获取对应的 API key
|
|
287
|
-
const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
|
|
288
|
-
const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
|
|
289
289
|
const aiPlugin = new AIPlugin({
|
|
290
290
|
provider: aiConfig.provider || 'deepseek',
|
|
291
291
|
model: aiConfig.model || 'deepseek-chat',
|
|
@@ -309,7 +309,7 @@ async function bootstrapDefaults(framework, config = {}) {
|
|
|
309
309
|
systemPrompt: '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。',
|
|
310
310
|
model: aiConfig.model || 'deepseek-chat',
|
|
311
311
|
provider: aiConfig.provider || 'deepseek',
|
|
312
|
-
apiKey: aiConfig.apiKey,
|
|
312
|
+
apiKey: aiPlugin ? aiPlugin.config.apiKey : (aiConfig.apiKey || envApiKey),
|
|
313
313
|
baseURL: aiConfig.baseURL
|
|
314
314
|
})
|
|
315
315
|
framework._agents.push(framework._mainAgent)
|
package/plugins/memory-plugin.js
CHANGED
|
@@ -977,18 +977,18 @@ class MemoryPlugin extends Plugin {
|
|
|
977
977
|
}
|
|
978
978
|
|
|
979
979
|
// 批量处理错误
|
|
980
|
-
if (this._pendingErrors.length > 0) {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
980
|
+
// if (this._pendingErrors.length > 0) {
|
|
981
|
+
// const errors = this._pendingErrors.splice(0, 10) // 每次最多处理 10 条
|
|
982
|
+
// log.debug(`Processing ${errors.length} pending errors`)
|
|
983
|
+
|
|
984
|
+
// for (const errorData of errors) {
|
|
985
|
+
// try {
|
|
986
|
+
// await this._extractErrorLesson(errorData)
|
|
987
|
+
// } catch (err) {
|
|
988
|
+
// log.warn('Failed to extract error lesson:', err.message)
|
|
989
|
+
// }
|
|
990
|
+
// }
|
|
991
|
+
// }
|
|
992
992
|
} finally {
|
|
993
993
|
this._isExtracting = false
|
|
994
994
|
}
|
|
@@ -79,6 +79,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
79
79
|
this.description = '管理远程插件:列表、发布、安装';
|
|
80
80
|
this._repo = config.repo || process.env.FOLIKO_PLUGIN_REPO || DEFAULT_REPO;
|
|
81
81
|
this.system = true;
|
|
82
|
+
this.tools = {}; // ext_call 需要通过 this.tools 访问工具
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
install(framework) {
|
|
@@ -110,7 +110,7 @@ class SubAgentPlugin extends Plugin {
|
|
|
110
110
|
tools:{}, // 自定义工具
|
|
111
111
|
parentTools: all_tools
|
|
112
112
|
})
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
|
|
115
115
|
// 注册从父Agent继承的工具
|
|
116
116
|
// for (const tool of parentTools) {
|
|
@@ -662,6 +662,60 @@ class SubAgentManagerPlugin extends Plugin {
|
|
|
662
662
|
return config
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* 构建子Agent描述
|
|
668
|
+
* 使用数组收集 + join 模式优化字符串拼接
|
|
669
|
+
* 动态从配置文件读取每个子Agent的专业领域
|
|
670
|
+
*/
|
|
671
|
+
_buildDescription() {
|
|
672
|
+
const allSubAgents = this.getAllSubAgents();
|
|
673
|
+
if (!allSubAgents || allSubAgents.length === 0) {
|
|
674
|
+
return '';
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// 使用数组收集 + join 模式优化字符串拼接
|
|
678
|
+
const lines = ['## 子 Agent 匹配表', ''];
|
|
679
|
+
lines.push('');
|
|
680
|
+
lines.push('> **提示**:根据任务类型选择最匹配的子 Agent 处理');
|
|
681
|
+
lines.push('');
|
|
682
|
+
|
|
683
|
+
// 动态从配置文件读取每个子Agent的核心能力
|
|
684
|
+
for (const plugin of allSubAgents) {
|
|
685
|
+
const name = plugin.name;
|
|
686
|
+
const role = plugin.role;
|
|
687
|
+
const goal = plugin.description || '';
|
|
688
|
+
|
|
689
|
+
// 优先使用 SubAgentConfigManager 获取详细信息
|
|
690
|
+
const config = this._framework._subAgentConfigManager?.get(name);
|
|
691
|
+
if (config) {
|
|
692
|
+
const agentDesc = config.getDescription();
|
|
693
|
+
const skills = config.getSkills();
|
|
694
|
+
let info = agentDesc || role || goal || '子代理';
|
|
695
|
+
if (skills && skills.length > 0) {
|
|
696
|
+
info += ` (技能: ${skills.join(', ')})`;
|
|
697
|
+
}
|
|
698
|
+
lines.push(`- **${name}**:${info}`);
|
|
699
|
+
} else {
|
|
700
|
+
// 回退到旧逻辑
|
|
701
|
+
lines.push(`- **${name}**:${role || goal || '子代理'}`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// 通用规则
|
|
706
|
+
lines.push('');
|
|
707
|
+
lines.push('### 子 Agent 调用规则');
|
|
708
|
+
lines.push('');
|
|
709
|
+
lines.push('> **重要**:必须严格遵守以下规则');
|
|
710
|
+
lines.push('');
|
|
711
|
+
lines.push('1. 根据上述「子 Agent 匹配表」,将任务委托给最匹配的子 Agent 处理');
|
|
712
|
+
lines.push('2. 使用 `subagent_call` 工具并指定 `agentName` 来委托任务');
|
|
713
|
+
lines.push('3. 只有当没有匹配的子 Agent 时,才直接调用工具');
|
|
714
|
+
lines.push('4. 子 Agent 是没有记忆的,有需要的时候,有需要的时候,需要传递给上下文给子 Agent');
|
|
715
|
+
|
|
716
|
+
return lines.join('\n');
|
|
717
|
+
}
|
|
718
|
+
|
|
665
719
|
/**
|
|
666
720
|
* 获取所有 subAgent 的基本信息列表
|
|
667
721
|
*/
|
|
@@ -311,24 +311,27 @@ class TelegramPlugin extends Plugin {
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
try {
|
|
314
|
+
// 使用事件方式实时处理流式响应
|
|
315
|
+
const sessionScope = agent.createSessionScope(sessionId)
|
|
314
316
|
let fullResponse = ''
|
|
315
|
-
|
|
317
|
+
|
|
318
|
+
sessionScope.on('stream:chunk', ({ chunk }) => {
|
|
316
319
|
if (chunk.type === 'text' && chunk.text) {
|
|
317
320
|
fullResponse += chunk.text
|
|
318
321
|
if (fullResponse.length % 100 === 0) {
|
|
319
322
|
try {
|
|
320
|
-
|
|
323
|
+
this._bot.editMessageText(`📝 ${escapeMarkdown(fullResponse)}▌`, {
|
|
321
324
|
chat_id: chatId,
|
|
322
325
|
message_id: thinkingMsg.message_id
|
|
323
326
|
})
|
|
324
327
|
} catch (e) { /* ignore */ }
|
|
325
328
|
}
|
|
326
329
|
}
|
|
327
|
-
}
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
await agent.sendMessage(text, { sessionId })
|
|
328
333
|
|
|
329
|
-
|
|
330
|
-
// this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
|
|
331
|
-
// }
|
|
334
|
+
sessionScope.removeAllListeners()
|
|
332
335
|
|
|
333
336
|
const safeResponse = escapeMarkdown(fullResponse) || '抱歉,我没有收到有效的回复。'
|
|
334
337
|
await this._bot.editMessageText(safeResponse, {
|