foliko 1.0.71 → 1.0.73

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.
@@ -1,148 +1,149 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(grep -r \"dotenv\" \"D:/Code/vb-agent/\" --include=\"*.json\" 2>/dev/null | head -20)",
5
- "Bash(cd \"D:/Code/vb-agent\" && pnpm add dotenv)",
6
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('reason'\\) || k.toLowerCase\\(\\).includes\\('split'\\) || k.toLowerCase\\(\\).includes\\('think'\\)\\)\\)\")",
7
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(typeof ai.extractReasoningMiddleware, ai.extractReasoningMiddleware.toString\\(\\).substring\\(0, 500\\)\\)\")",
8
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"\nconst ai = require\\('ai'\\);\nconsole.log\\('=== extractReasoningMiddleware ==='\\);\nconsole.log\\(ai.extractReasoningMiddleware.toString\\(\\)\\);\nconsole.log\\('\\\\n=== isReasoningUIPart ==='\\);\nconsole.log\\(typeof ai.isReasoningUIPart\\);\n\")",
9
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('split'\\)\\)\\)\")",
10
- "Bash(cd \"D:/Code/vb-agent\" && pnpm add ink react)",
11
- "Bash(cd \"D:/Code/vb-agent\" && node cli/bin/foliko.js --help)",
12
- "Bash(cd \"D:/Code/vb-agent\" && timeout 2 node cli/bin/foliko.js chat 2>&1 || true)",
13
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const mt = require\\('marked-terminal'\\); console.log\\(typeof mt, Object.keys\\(mt\\)\\)\")",
14
- "Bash(cd \"D:/Code/vb-agent\" && timeout 3 node cli/bin/foliko.js chat 2>&1 || true)",
15
- "Bash(echo \"你好\" | node cli/bin/foliko.js chat 2>&1 | head -50)",
16
- "Bash(printf '思考一下1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1 | head -100)",
17
- "Bash(printf '1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1)",
18
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\(renderLine\\('🎉 这是一个 emoji'\\)\\)\nconsole.log\\(renderLine\\('**粗体** 和 🎉'\\)\\)\n\")",
19
- "Bash(node -e \"\nconst { render } = require\\('./cli/src/utils/markdown'\\)\nconst text = '🎉 今天是个好日子\\\\n## 标题\\\\n- 列表项1\\\\n- 列表项2'\nconsole.log\\(render\\(text\\)\\)\n\")",
20
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\n\n// 模拟emoji被截断的情况\nconst emoji = '🎉'\nconsole.log\\('完整的 emoji:', renderLine\\(emoji\\)\\)\n\n// 模拟截断 - emoji的UTF-8字节是 \\\\xF0\\\\x9F\\\\x8E\\\\x89\nconst partial = '\\\\xF0\\\\x9F' // 不完整的emoji\nconsole.log\\('截断的 emoji:', renderLine\\(partial\\)\\)\n\")",
21
- "Bash(node -e \"\nconst isIncompleteUTF8 = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n if \\(lastChar >= 0x80 && lastChar < 0xC0\\) return true\n return false\n}\n\n// 测试各种emoji\nconst tests = ['🎉', '📁', '⚡', '🛠️', '🔑', '💾', '📝', '⏰', '🔌', '📋']\ntests.forEach\\(e => {\n console.log\\(e, '完整:', !isIncompleteUTF8\\(e\\)\\)\n}\\)\n\n// 测试被截断的emoji \\(只保留第一字节\\)\nconst broken = '🎉'.slice\\(0, 1\\)\nconsole.log\\('截断emoji:', broken, '检测:', isIncompleteUTF8\\(broken\\)\\)\n\")",
22
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\('测试:', renderLine\\('📁 文件操作:读取、创建'\\)\\)\n\")",
23
- "Bash(node -e \"\nconst hasIncompleteSurrogate = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n console.log\\('检查:', str, 'lastChar:', lastChar.toString\\(16\\), '范围:', \\(lastChar >= 0xD800 && lastChar <= 0xDBFF\\)\\)\n return lastChar >= 0xD800 && lastChar <= 0xDBFF\n}\n\nconst chunk1 = '\\\\xD83C'\nconsole.log\\('结果:', hasIncompleteSurrogate\\(chunk1\\)\\)\n\")",
24
- "Bash(cd D:/Code/vb-agent && node test-stream-emoji.js 2>&1)",
25
- "Read(//d/Date/20260321/app/**)",
26
- "Bash(node -e \":*)",
27
- "Bash(node -e \"\nconst { loadAgentConfig } = require\\('./plugins/default-plugins'\\);\nconst config = loadAgentConfig\\('D:/Date/20260321/app/.agent'\\);\nconsole.log\\('skillsDirs:', config.skillsDirs\\);\n\")",
28
- "Bash(cd D:/Code/vb-agent && pnpm install --shamefully-hoist 2>&1 | head -20)",
29
- "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)",
30
- "Bash(cd D:/Code/vb-agent && timeout 8 node test-tg.js 2>&1 || true)",
31
- "Bash(cd D:/Code/vb-agent && timeout 10 node test-tg.js 2>&1 || true)",
32
- "Bash(find /d/Code/vb-agent -name \"*email*\" -type f 2>/dev/null | grep -v node_modules | grep -v .git)",
33
- "Bash(find /d/Code/vb-agent -maxdepth 2 -name \"*.md\" -type f 2>/dev/null | grep -v node_modules)",
34
- "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && echo \"Syntax OK\")",
35
- "Bash(node -c plugins/install-plugin.js && echo \"Syntax OK\")",
36
- "Bash(node -c cli/src/ui/chat-ui.js && echo \"Syntax OK\")",
37
- "Bash(node -c plugins/default-plugins.js && echo \"Syntax OK\")",
38
- "Bash(node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
39
- "Bash(node -c plugins/telegram-plugin.js && node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
40
- "Bash(node -c plugins/telegram-plugin.js && echo \"Syntax OK\")",
41
- "WebSearch",
42
- "Bash(npm ls:*)",
43
- "Bash(cd node_modules/@chnak/weixin-bot && npm run build 2>&1)",
44
- "Bash(cd node_modules/@chnak/weixin-bot && npx tsc 2>&1)",
45
- "Bash(npm install:*)",
46
- "Bash(cd node_modules/@chnak/weixin-bot && npx typescript --version && npx tsc 2>&1)",
47
- "Bash(npx tsc:*)",
48
- "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js 2>&1)",
49
- "Bash(node --check /d/Code/vb-agent/plugins/telegram-plugin.js && node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
50
- "Bash(node --check /d/Code/vb-agent/cli/src/ui/chat-ui.js && echo \"OK\")",
51
- "Bash(npm uninstall:*)",
52
- "Bash(rm -rf /tmp/weixin-bot && git clone https://github.com/chnak/weixin-bot.git /tmp/weixin-bot 2>&1)",
53
- "Bash(mkdir -p node_modules/@chnak/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@chnak/weixin-bot/ && cd node_modules/@chnak/weixin-bot && npm install 2>&1)",
54
- "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
55
- "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', Object.keys\\(m\\)\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\")",
56
- "Bash(npm run:*)",
57
- "Bash(node -e \"const { WeixinBot } = require\\('@chnak/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
58
- "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', typeof m.WeixinBot\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\" 2>&1)",
59
- "Bash(ls -la D:/code/vb-agent/cli/bin/ && cat D:/code/vb-agent/cli/bin/*.js 2>/dev/null | head -50)",
60
- "Bash(npm config:*)",
61
- "Bash(node -c plugins/subagent-plugin.js 2>&1)",
62
- "Bash(node -c plugins/default-plugins.js 2>&1)",
63
- "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
64
- "Bash(node -c src/core/plugin-base.js && node -c src/core/plugin-manager.js 2>&1)",
65
- "Bash(node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
66
- "Bash(node -c src/core/plugin-manager.js 2>&1)",
67
- "Bash(node -c src/core/plugin-manager.js && node -c src/core/plugin-base.js && node -c plugins/default-plugins.js && node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
68
- "Bash(node -e \"require\\('dotenv'\\).config\\(\\); console.log\\('PROVIDER:', process.env.FOLIKO_PROVIDER\\); console.log\\('MODEL:', process.env.FOLIKO_MODEL\\); console.log\\('KEY:', process.env.DEEPSEEK_API_KEY ? 'set' : 'not set'\\)\" 2>&1)",
69
- "Bash(node cli/src/index.js chat 2>&1 | head -30)",
70
- "Bash(node -e 'const { DEFAULT_PROVIDERS } = require\\(\"./src/core/provider\"\\); console.log\\(DEFAULT_PROVIDERS\\);')",
71
- "Bash(node -e \"const dotenv = require\\('dotenv'\\); const result = dotenv.config\\(\\); console.log\\('Result:', result\\); console.log\\('PROVIDER after dotenv:', process.env.FOLIKO_PROVIDER\\);\" 2>&1)",
72
- "Bash(node -c plugins/email.js && node -c plugins/default-plugins.js 2>&1)",
73
- "Bash(node -c plugins/email.js 2>&1)",
74
- "Bash(npm list:*)",
75
- "Bash(node -e \"const {EmailPlugin} = require\\('./plugins/email'\\); const p = new EmailPlugin\\(\\); console.log\\('email plugin loaded ok'\\); console.log\\('enabled:', p.enabled\\); console.log\\('version:', p.version\\);\" 2>&1)",
76
- "Bash(cd D:/Code/vb-agent && node -e \"console.log\\('IMAP_HOST:', process.env.IMAP_HOST\\); console.log\\('IMAP_USER:', process.env.IMAP_USER\\); console.log\\('IMAP_PORT:', process.env.IMAP_PORT\\);\")",
77
- "Bash(node -e \"const sdk = require\\('@larksuiteoapi/node-sdk'\\); console.log\\(Object.keys\\(sdk\\)\\);\")",
78
- "Bash(node -e \"const { WSClient } = require\\('@larksuiteoapi/node-sdk'\\); const sdk = new WSClient\\({}\\); console.log\\(Object.getOwnPropertyNames\\(Object.getPrototypeOf\\(sdk\\)\\)\\);\")",
79
- "Bash(node -c src/core/framework.js 2>&1)",
80
- "Bash(node -c plugins/telegram-plugin.js 2>&1)",
81
- "Bash(node -c src/capabilities/skill-manager.js 2>&1)",
82
- "Bash(node -c plugins/feishu-plugin.js 2>&1)",
83
- "Bash(node debug-skills.js)",
84
- "Bash(node -c src/capabilities/workflow-engine.js 2>&1)",
85
- "Bash(node -c skills/workflow-guide/SKILL.md 2>&1 || head -10 skills/workflow-guide/SKILL.md)",
86
- "Bash(ls plugins/*.js 2>&1)",
87
- "Bash(node -c plugins/web-plugin.js 2>&1)",
88
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./plugins/web-plugin.js'\\)\" 2>&1)",
89
- "Bash(cd D:/code/vb-agent && node -e \"\nconst { WebPlugin } = require\\('./plugins/web-plugin.js'\\);\nconst p = new WebPlugin\\(\\);\nconsole.log\\('Plugin created:', p.name, p.version\\);\n\" 2>&1)",
90
- "Bash(cd D:/code/vb-agent && mkdir -p test-static && echo '<html><body>Hello Static</body></html>' > test-static/index.html)",
91
- "mcp__plugin_context7_context7__resolve-library-id",
92
- "mcp__plugin_context7_context7__query-docs",
93
- "Bash(cd D:/code/vb-agent && rm test-hono.js)",
94
- "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"连接失败\")",
95
- "Bash(cd D:/code/vb-agent && timeout 15 node examples/test-web-plugin.js 2>&1)",
96
- "Bash(cd D:/code/vb-agent && timeout 60 node examples/test-chat.js 2>&1 | head -100)",
97
- "Bash(cd D:/code/vb-agent && timeout 120 node examples/test-chat.js 2>&1 | tail -80)",
98
- "Bash(cd D:/code/vb-agent && timeout 120 node examples/bootstrap.js 2>&1 | tail -100)",
99
- "Bash(cd D:/code/vb-agent && timeout 10 node examples/test-web-plugin.js 2>&1)",
100
- "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
101
- "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"Connection failed\")",
102
- "Bash(curl -s -X POST http://localhost:3000/webhook/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
103
- "Bash(curl -s http://localhost:3000/webui/status)",
104
- "Bash(curl -s http://localhost:3000/test)",
105
- "Bash(curl -s -v -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1 | head -30)",
106
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1)",
107
- "Bash(curl -s http://localhost:3000/webui/ 2>&1)",
108
- "Bash(curl -s -X POST http://localhost:3000/webui/list-routes \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{}' 2>&1 || echo \"Endpoint not found\")",
109
- "Bash(curl -s http://localhost:3000/ 2>&1)",
110
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test with prefix\"}')",
111
- "Bash(netstat -ano | grep :3000 | head -5)",
112
- "Bash(netstat -ano | grep :3000 | grep LISTENING)",
113
- "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\",\"sessionId\":\"web_test\"}')",
114
- "Bash(taskkill /F /IM node.exe 2>/dev/null; sleep 1; echo \"Node processes killed\")",
115
- "Bash(netstat -ano | grep :3000)",
116
- "Bash(taskkill //F //PID 19848)",
117
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1)",
118
- "Bash(curl -s http://localhost:3000/api/hello 2>&1)",
119
- "Bash(curl -v -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1 | head -30)",
120
- "Bash(cd D:/code/vb-agent && timeout 30 node test-compression.js 2>&1)",
121
- "Bash(cd D:/code/vb-agent && node -c src/core/agent-chat.js 2>&1)",
122
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent-chat.js'\\); console.log\\('模块加载成功'\\)\" 2>&1)",
123
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent.js'\\); console.log\\('Agent 加载成功'\\)\" 2>&1)",
124
- "Bash(node -c src/capabilities/skill-manager.js && node -c src/executors/mcp-executor.js && node -c src/capabilities/workflow-engine.js && node -c src/core/plugin-manager.js 2>&1)",
125
- "Bash(node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
126
- "Bash(node -c plugins/default-plugins.js && node -c cli/src/commands/chat.js 2>&1)",
127
- "Bash(node -c plugins/telegram-plugin.js && node -c plugins/feishu-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
128
- "Bash(node -c src/core/agent.js 2>&1)",
129
- "Bash(cd D:/code/vb-agent && node examples/bootstrap.js 2>&1 | head -50)",
130
- "Bash(node -c plugins/proactive-agent-plugin.js 2>&1)",
131
- "Bash(node -c src/index.js && node -c examples/proactive-example.js && node -c examples/proactive-advanced.js && echo \"All syntax OK\")",
132
- "Bash(node -c plugins/proactive-agent-plugin.js && node -c plugins/default-plugins.js && echo \"All OK\")",
133
- "Bash(node examples/basic.js 2>&1 | head -50)",
134
- "Bash(node examples/ambient-example.js 2>&1 | head -80)",
135
- "Bash(ls -la .agent/data/ambient/ 2>/dev/null && cat .agent/data/ambient/*.json 2>/dev/null | head -50)",
136
- "Bash(node examples/basic.js 2>&1 | head -30)",
137
- "Bash(node examples/bootstrap.js 2>&1 | head -40)",
138
- "Bash(node test-debug.js 2>&1)",
139
- "Bash(ls -la D:/Code/vb-agent/*.md 2>/dev/null || dir D:\\\\Code\\\\vb-agent\\\\*.md /b 2>nul)",
140
- "Bash(node -c src/capabilities/workflow-engine.js && node -c plugins/ambient-agent-plugin.js)",
141
- "Bash(node -c plugins/ambient-agent-plugin.js)",
142
- "Bash(node -c plugins/email.js)",
143
- "Bash(node -e \"require\\('./plugins/ambient-agent-plugin.js'\\)\" 2>&1)",
144
- "Bash(node -e \"\nconst { Framework } = require\\('./src/core/framework'\\);\nconst framework = new Framework\\(\\);\nframework.loadPlugin\\('./plugins/ambient-agent-plugin.js'\\).catch\\(console.error\\);\nsetTimeout\\(\\(\\) => {\n const tools = framework.getTools\\(\\);\n console.log\\('Registered tools:', tools.map\\(t => t.name\\)\\);\n}, 2000\\);\n\" 2>&1)",
145
- "Bash(node -c plugins/scheduler-plugin.js 2>&1)"
146
- ]
147
- }
148
- }
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -r \"dotenv\" \"D:/Code/vb-agent/\" --include=\"*.json\" 2>/dev/null | head -20)",
5
+ "Bash(cd \"D:/Code/vb-agent\" && pnpm add dotenv)",
6
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('reason'\\) || k.toLowerCase\\(\\).includes\\('split'\\) || k.toLowerCase\\(\\).includes\\('think'\\)\\)\\)\")",
7
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(typeof ai.extractReasoningMiddleware, ai.extractReasoningMiddleware.toString\\(\\).substring\\(0, 500\\)\\)\")",
8
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"\nconst ai = require\\('ai'\\);\nconsole.log\\('=== extractReasoningMiddleware ==='\\);\nconsole.log\\(ai.extractReasoningMiddleware.toString\\(\\)\\);\nconsole.log\\('\\\\n=== isReasoningUIPart ==='\\);\nconsole.log\\(typeof ai.isReasoningUIPart\\);\n\")",
9
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('split'\\)\\)\\)\")",
10
+ "Bash(cd \"D:/Code/vb-agent\" && pnpm add ink react)",
11
+ "Bash(cd \"D:/Code/vb-agent\" && node cli/bin/foliko.js --help)",
12
+ "Bash(cd \"D:/Code/vb-agent\" && timeout 2 node cli/bin/foliko.js chat 2>&1 || true)",
13
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const mt = require\\('marked-terminal'\\); console.log\\(typeof mt, Object.keys\\(mt\\)\\)\")",
14
+ "Bash(cd \"D:/Code/vb-agent\" && timeout 3 node cli/bin/foliko.js chat 2>&1 || true)",
15
+ "Bash(echo \"你好\" | node cli/bin/foliko.js chat 2>&1 | head -50)",
16
+ "Bash(printf '思考一下1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1 | head -100)",
17
+ "Bash(printf '1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1)",
18
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\(renderLine\\('🎉 这是一个 emoji'\\)\\)\nconsole.log\\(renderLine\\('**粗体** 和 🎉'\\)\\)\n\")",
19
+ "Bash(node -e \"\nconst { render } = require\\('./cli/src/utils/markdown'\\)\nconst text = '🎉 今天是个好日子\\\\n## 标题\\\\n- 列表项1\\\\n- 列表项2'\nconsole.log\\(render\\(text\\)\\)\n\")",
20
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\n\n// 模拟emoji被截断的情况\nconst emoji = '🎉'\nconsole.log\\('完整的 emoji:', renderLine\\(emoji\\)\\)\n\n// 模拟截断 - emoji的UTF-8字节是 \\\\xF0\\\\x9F\\\\x8E\\\\x89\nconst partial = '\\\\xF0\\\\x9F' // 不完整的emoji\nconsole.log\\('截断的 emoji:', renderLine\\(partial\\)\\)\n\")",
21
+ "Bash(node -e \"\nconst isIncompleteUTF8 = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n if \\(lastChar >= 0x80 && lastChar < 0xC0\\) return true\n return false\n}\n\n// 测试各种emoji\nconst tests = ['🎉', '📁', '⚡', '🛠️', '🔑', '💾', '📝', '⏰', '🔌', '📋']\ntests.forEach\\(e => {\n console.log\\(e, '完整:', !isIncompleteUTF8\\(e\\)\\)\n}\\)\n\n// 测试被截断的emoji \\(只保留第一字节\\)\nconst broken = '🎉'.slice\\(0, 1\\)\nconsole.log\\('截断emoji:', broken, '检测:', isIncompleteUTF8\\(broken\\)\\)\n\")",
22
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\('测试:', renderLine\\('📁 文件操作:读取、创建'\\)\\)\n\")",
23
+ "Bash(node -e \"\nconst hasIncompleteSurrogate = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n console.log\\('检查:', str, 'lastChar:', lastChar.toString\\(16\\), '范围:', \\(lastChar >= 0xD800 && lastChar <= 0xDBFF\\)\\)\n return lastChar >= 0xD800 && lastChar <= 0xDBFF\n}\n\nconst chunk1 = '\\\\xD83C'\nconsole.log\\('结果:', hasIncompleteSurrogate\\(chunk1\\)\\)\n\")",
24
+ "Bash(cd D:/Code/vb-agent && node test-stream-emoji.js 2>&1)",
25
+ "Read(//d/Date/20260321/app/**)",
26
+ "Bash(node -e \":*)",
27
+ "Bash(node -e \"\nconst { loadAgentConfig } = require\\('./plugins/default-plugins'\\);\nconst config = loadAgentConfig\\('D:/Date/20260321/app/.agent'\\);\nconsole.log\\('skillsDirs:', config.skillsDirs\\);\n\")",
28
+ "Bash(cd D:/Code/vb-agent && pnpm install --shamefully-hoist 2>&1 | head -20)",
29
+ "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)",
30
+ "Bash(cd D:/Code/vb-agent && timeout 8 node test-tg.js 2>&1 || true)",
31
+ "Bash(cd D:/Code/vb-agent && timeout 10 node test-tg.js 2>&1 || true)",
32
+ "Bash(find /d/Code/vb-agent -name \"*email*\" -type f 2>/dev/null | grep -v node_modules | grep -v .git)",
33
+ "Bash(find /d/Code/vb-agent -maxdepth 2 -name \"*.md\" -type f 2>/dev/null | grep -v node_modules)",
34
+ "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && echo \"Syntax OK\")",
35
+ "Bash(node -c plugins/install-plugin.js && echo \"Syntax OK\")",
36
+ "Bash(node -c cli/src/ui/chat-ui.js && echo \"Syntax OK\")",
37
+ "Bash(node -c plugins/default-plugins.js && echo \"Syntax OK\")",
38
+ "Bash(node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
39
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
40
+ "Bash(node -c plugins/telegram-plugin.js && echo \"Syntax OK\")",
41
+ "WebSearch",
42
+ "Bash(npm ls:*)",
43
+ "Bash(cd node_modules/@chnak/weixin-bot && npm run build 2>&1)",
44
+ "Bash(cd node_modules/@chnak/weixin-bot && npx tsc 2>&1)",
45
+ "Bash(npm install:*)",
46
+ "Bash(cd node_modules/@chnak/weixin-bot && npx typescript --version && npx tsc 2>&1)",
47
+ "Bash(npx tsc:*)",
48
+ "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js 2>&1)",
49
+ "Bash(node --check /d/Code/vb-agent/plugins/telegram-plugin.js && node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
50
+ "Bash(node --check /d/Code/vb-agent/cli/src/ui/chat-ui.js && echo \"OK\")",
51
+ "Bash(npm uninstall:*)",
52
+ "Bash(rm -rf /tmp/weixin-bot && git clone https://github.com/chnak/weixin-bot.git /tmp/weixin-bot 2>&1)",
53
+ "Bash(mkdir -p node_modules/@chnak/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@chnak/weixin-bot/ && cd node_modules/@chnak/weixin-bot && npm install 2>&1)",
54
+ "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
55
+ "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', Object.keys\\(m\\)\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\")",
56
+ "Bash(npm run:*)",
57
+ "Bash(node -e \"const { WeixinBot } = require\\('@chnak/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
58
+ "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', typeof m.WeixinBot\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\" 2>&1)",
59
+ "Bash(ls -la D:/code/vb-agent/cli/bin/ && cat D:/code/vb-agent/cli/bin/*.js 2>/dev/null | head -50)",
60
+ "Bash(npm config:*)",
61
+ "Bash(node -c plugins/subagent-plugin.js 2>&1)",
62
+ "Bash(node -c plugins/default-plugins.js 2>&1)",
63
+ "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
64
+ "Bash(node -c src/core/plugin-base.js && node -c src/core/plugin-manager.js 2>&1)",
65
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
66
+ "Bash(node -c src/core/plugin-manager.js 2>&1)",
67
+ "Bash(node -c src/core/plugin-manager.js && node -c src/core/plugin-base.js && node -c plugins/default-plugins.js && node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
68
+ "Bash(node -e \"require\\('dotenv'\\).config\\(\\); console.log\\('PROVIDER:', process.env.FOLIKO_PROVIDER\\); console.log\\('MODEL:', process.env.FOLIKO_MODEL\\); console.log\\('KEY:', process.env.DEEPSEEK_API_KEY ? 'set' : 'not set'\\)\" 2>&1)",
69
+ "Bash(node cli/src/index.js chat 2>&1 | head -30)",
70
+ "Bash(node -e 'const { DEFAULT_PROVIDERS } = require\\(\"./src/core/provider\"\\); console.log\\(DEFAULT_PROVIDERS\\);')",
71
+ "Bash(node -e \"const dotenv = require\\('dotenv'\\); const result = dotenv.config\\(\\); console.log\\('Result:', result\\); console.log\\('PROVIDER after dotenv:', process.env.FOLIKO_PROVIDER\\);\" 2>&1)",
72
+ "Bash(node -c plugins/email.js && node -c plugins/default-plugins.js 2>&1)",
73
+ "Bash(node -c plugins/email.js 2>&1)",
74
+ "Bash(npm list:*)",
75
+ "Bash(node -e \"const {EmailPlugin} = require\\('./plugins/email'\\); const p = new EmailPlugin\\(\\); console.log\\('email plugin loaded ok'\\); console.log\\('enabled:', p.enabled\\); console.log\\('version:', p.version\\);\" 2>&1)",
76
+ "Bash(cd D:/Code/vb-agent && node -e \"console.log\\('IMAP_HOST:', process.env.IMAP_HOST\\); console.log\\('IMAP_USER:', process.env.IMAP_USER\\); console.log\\('IMAP_PORT:', process.env.IMAP_PORT\\);\")",
77
+ "Bash(node -e \"const sdk = require\\('@larksuiteoapi/node-sdk'\\); console.log\\(Object.keys\\(sdk\\)\\);\")",
78
+ "Bash(node -e \"const { WSClient } = require\\('@larksuiteoapi/node-sdk'\\); const sdk = new WSClient\\({}\\); console.log\\(Object.getOwnPropertyNames\\(Object.getPrototypeOf\\(sdk\\)\\)\\);\")",
79
+ "Bash(node -c src/core/framework.js 2>&1)",
80
+ "Bash(node -c plugins/telegram-plugin.js 2>&1)",
81
+ "Bash(node -c src/capabilities/skill-manager.js 2>&1)",
82
+ "Bash(node -c plugins/feishu-plugin.js 2>&1)",
83
+ "Bash(node debug-skills.js)",
84
+ "Bash(node -c src/capabilities/workflow-engine.js 2>&1)",
85
+ "Bash(node -c skills/workflow-guide/SKILL.md 2>&1 || head -10 skills/workflow-guide/SKILL.md)",
86
+ "Bash(ls plugins/*.js 2>&1)",
87
+ "Bash(node -c plugins/web-plugin.js 2>&1)",
88
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./plugins/web-plugin.js'\\)\" 2>&1)",
89
+ "Bash(cd D:/code/vb-agent && node -e \"\nconst { WebPlugin } = require\\('./plugins/web-plugin.js'\\);\nconst p = new WebPlugin\\(\\);\nconsole.log\\('Plugin created:', p.name, p.version\\);\n\" 2>&1)",
90
+ "Bash(cd D:/code/vb-agent && mkdir -p test-static && echo '<html><body>Hello Static</body></html>' > test-static/index.html)",
91
+ "mcp__plugin_context7_context7__resolve-library-id",
92
+ "mcp__plugin_context7_context7__query-docs",
93
+ "Bash(cd D:/code/vb-agent && rm test-hono.js)",
94
+ "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"连接失败\")",
95
+ "Bash(cd D:/code/vb-agent && timeout 15 node examples/test-web-plugin.js 2>&1)",
96
+ "Bash(cd D:/code/vb-agent && timeout 60 node examples/test-chat.js 2>&1 | head -100)",
97
+ "Bash(cd D:/code/vb-agent && timeout 120 node examples/test-chat.js 2>&1 | tail -80)",
98
+ "Bash(cd D:/code/vb-agent && timeout 120 node examples/bootstrap.js 2>&1 | tail -100)",
99
+ "Bash(cd D:/code/vb-agent && timeout 10 node examples/test-web-plugin.js 2>&1)",
100
+ "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
101
+ "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"Connection failed\")",
102
+ "Bash(curl -s -X POST http://localhost:3000/webhook/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
103
+ "Bash(curl -s http://localhost:3000/webui/status)",
104
+ "Bash(curl -s http://localhost:3000/test)",
105
+ "Bash(curl -s -v -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1 | head -30)",
106
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1)",
107
+ "Bash(curl -s http://localhost:3000/webui/ 2>&1)",
108
+ "Bash(curl -s -X POST http://localhost:3000/webui/list-routes \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{}' 2>&1 || echo \"Endpoint not found\")",
109
+ "Bash(curl -s http://localhost:3000/ 2>&1)",
110
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test with prefix\"}')",
111
+ "Bash(netstat -ano | grep :3000 | head -5)",
112
+ "Bash(netstat -ano | grep :3000 | grep LISTENING)",
113
+ "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\",\"sessionId\":\"web_test\"}')",
114
+ "Bash(taskkill /F /IM node.exe 2>/dev/null; sleep 1; echo \"Node processes killed\")",
115
+ "Bash(netstat -ano | grep :3000)",
116
+ "Bash(taskkill //F //PID 19848)",
117
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1)",
118
+ "Bash(curl -s http://localhost:3000/api/hello 2>&1)",
119
+ "Bash(curl -v -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1 | head -30)",
120
+ "Bash(cd D:/code/vb-agent && timeout 30 node test-compression.js 2>&1)",
121
+ "Bash(cd D:/code/vb-agent && node -c src/core/agent-chat.js 2>&1)",
122
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent-chat.js'\\); console.log\\('模块加载成功'\\)\" 2>&1)",
123
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent.js'\\); console.log\\('Agent 加载成功'\\)\" 2>&1)",
124
+ "Bash(node -c src/capabilities/skill-manager.js && node -c src/executors/mcp-executor.js && node -c src/capabilities/workflow-engine.js && node -c src/core/plugin-manager.js 2>&1)",
125
+ "Bash(node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
126
+ "Bash(node -c plugins/default-plugins.js && node -c cli/src/commands/chat.js 2>&1)",
127
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/feishu-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
128
+ "Bash(node -c src/core/agent.js 2>&1)",
129
+ "Bash(cd D:/code/vb-agent && node examples/bootstrap.js 2>&1 | head -50)",
130
+ "Bash(node -c plugins/proactive-agent-plugin.js 2>&1)",
131
+ "Bash(node -c src/index.js && node -c examples/proactive-example.js && node -c examples/proactive-advanced.js && echo \"All syntax OK\")",
132
+ "Bash(node -c plugins/proactive-agent-plugin.js && node -c plugins/default-plugins.js && echo \"All OK\")",
133
+ "Bash(node examples/basic.js 2>&1 | head -50)",
134
+ "Bash(node examples/ambient-example.js 2>&1 | head -80)",
135
+ "Bash(ls -la .agent/data/ambient/ 2>/dev/null && cat .agent/data/ambient/*.json 2>/dev/null | head -50)",
136
+ "Bash(node examples/basic.js 2>&1 | head -30)",
137
+ "Bash(node examples/bootstrap.js 2>&1 | head -40)",
138
+ "Bash(node test-debug.js 2>&1)",
139
+ "Bash(ls -la D:/Code/vb-agent/*.md 2>/dev/null || dir D:\\\\Code\\\\vb-agent\\\\*.md /b 2>nul)",
140
+ "Bash(node -c src/capabilities/workflow-engine.js && node -c plugins/ambient-agent-plugin.js)",
141
+ "Bash(node -c plugins/ambient-agent-plugin.js)",
142
+ "Bash(node -c plugins/email.js)",
143
+ "Bash(node -e \"require\\('./plugins/ambient-agent-plugin.js'\\)\" 2>&1)",
144
+ "Bash(node -e \"\nconst { Framework } = require\\('./src/core/framework'\\);\nconst framework = new Framework\\(\\);\nframework.loadPlugin\\('./plugins/ambient-agent-plugin.js'\\).catch\\(console.error\\);\nsetTimeout\\(\\(\\) => {\n const tools = framework.getTools\\(\\);\n console.log\\('Registered tools:', tools.map\\(t => t.name\\)\\);\n}, 2000\\);\n\" 2>&1)",
145
+ "Bash(node -c plugins/scheduler-plugin.js 2>&1)",
146
+ "WebFetch(domain:ai-sdk.dev)"
147
+ ]
148
+ }
149
+ }
@@ -0,0 +1,636 @@
1
+ # AI SDK v6 优化报告 - Foliko 项目
2
+
3
+ > 本报告基于 [AI SDK v6 文档](https://ai-sdk.dev/docs/getting-started) 和 [Cookbook](https://ai-sdk.dev/cookbook) 分析,为 Foliko 项目提供具体的优化建议。
4
+
5
+ ## 一、项目当前 AI SDK 使用分析
6
+
7
+ ### 1.1 已集成的 AI SDK 组件
8
+
9
+ | 组件 | 版本 | 用途 |
10
+ |------|------|------|
11
+ | `ai` | 6.0.116 | 核心 SDK |
12
+ | `@ai-sdk/openai` | 3.0.41 | OpenAI Provider |
13
+ | `@ai-sdk/anthropic` | 3.0.58 | Anthropic Provider |
14
+ | `@ai-sdk/openai-compatible` | 2.0.35 | 兼容 Provider |
15
+ | `@ai-sdk/mcp` | 1.0.25 | MCP 集成 |
16
+ | `zod` | 3.24.0 | Schema 验证 |
17
+ | `tiktoken` | 1.0.22 | Token 计数 |
18
+
19
+ ### 1.2 当前使用的 AI SDK 功能
20
+
21
+ ```javascript
22
+ // ✅ 已使用
23
+ - ToolLoopAgent (工具调用循环)
24
+ - generateText (上下文总结)
25
+ - streamText 架构
26
+ - 基础 Provider 配置
27
+ - Zod schema (工具参数)
28
+ ```
29
+
30
+ ### 1.3 相关文件位置
31
+
32
+ | 功能 | 文件位置 | 用途 |
33
+ |------|---------|------|
34
+ | `ToolLoopAgent` | `src/core/agent-chat.js` | 工具调用循环 |
35
+ | `generateText` | `src/core/agent-chat.js` | 上下文总结、工具结果压缩 |
36
+ | `@ai-sdk/mcp` | `src/executors/mcp-executor.js` | MCP 服务器集成 |
37
+ | `Zod` | 全局 | 工具参数 schema |
38
+ | `tiktoken` | `src/core/agent-chat.js` | Token 计数、上下文压缩 |
39
+
40
+ ---
41
+
42
+ ## 二、优化建议
43
+
44
+ ### 🔴 【高优先级】
45
+
46
+ #### 2.1 结构化输出 - `generateObject` / `streamObject`
47
+
48
+ **现状**:项目使用 `generateText` 进行总结,但未使用结构化输出
49
+
50
+ **优化位置**:`src/core/agent-chat.js`
51
+
52
+ **建议新增**:
53
+
54
+ ```javascript
55
+ // 2.1.1 意图识别
56
+ async _classifyIntent(message) {
57
+ const { generateObject } = require('ai')
58
+
59
+ const { object } = await generateObject({
60
+ model: this._aiClient,
61
+ schema: z.object({
62
+ intent: z.enum([
63
+ 'create', 'read', 'update', 'delete',
64
+ 'query', 'execute', 'explain', 'unknown'
65
+ ]),
66
+ confidence: z.number().min(0).max(1),
67
+ entities: z.array(z.object({
68
+ name: z.string(),
69
+ type: z.string(),
70
+ value: z.any()
71
+ })).optional(),
72
+ suggestedTools: z.array(z.string()).optional()
73
+ }),
74
+ prompt: `分析用户消息的意图:${message}`
75
+ })
76
+
77
+ return object
78
+ }
79
+
80
+ // 2.1.2 结构化任务解析
81
+ async _parseStructuredTask(message) {
82
+ const { generateObject } = require('ai')
83
+
84
+ const { object } = await generateObject({
85
+ model: this._aiClient,
86
+ schema: z.object({
87
+ taskType: z.enum(['simple', 'multi-step', 'parallel', 'conditional']),
88
+ steps: z.array(z.object({
89
+ action: z.string(),
90
+ tool: z.string().optional(),
91
+ parameters: z.record(z.any()).optional(),
92
+ dependsOn: z.array(z.number()).optional()
93
+ })),
94
+ estimatedComplexity: z.number().min(1).max(10)
95
+ }),
96
+ prompt: `将任务分解为结构化步骤:${message}`
97
+ })
98
+
99
+ return object
100
+ }
101
+ ```
102
+
103
+ **收益**:
104
+ - 输出类型安全,减少解析错误
105
+ - 支持智能意图路由
106
+ - 为任务分解提供结构化基础
107
+
108
+ ---
109
+
110
+ #### 2.2 Prompt Caching 集成
111
+
112
+ **现状**:使用 tiktoken 手动计算 token,未利用 AI SDK 原生缓存
113
+
114
+ **优化位置**:`src/core/agent-chat.js`
115
+
116
+ **建议修改**:
117
+
118
+ ```javascript
119
+ // 2.2.1 新增导入
120
+ const { cachePrompt, smoothStream } = require('ai')
121
+
122
+ // 2.2.2 修改 _buildSystemPrompt - 添加缓存标记
123
+ _buildSystemPrompt() {
124
+ const parts = []
125
+ parts.push(this._originalPrompt)
126
+ // ... 其他部分
127
+
128
+ // 使用 cachePrompt 标记可缓存内容
129
+ const cacheableContent = parts.join('\n\n')
130
+ this._cachedSystemPrompt = cachePrompt(cacheableContent, {
131
+ cachePrefix: `system-${this.agent.name}`,
132
+ maxAgeMs: 1000 * 60 * 60 // 1小时
133
+ })
134
+
135
+ return this._cachedSystemPrompt
136
+ }
137
+
138
+ // 2.2.3 在 chat() 中使用缓存
139
+ async chat(message, options = {}) {
140
+ // ...
141
+
142
+ // 使用缓存的 system prompt
143
+ const cachedSystem = this._cachedSystemPrompt || this._systemPrompt
144
+
145
+ const agent = new ToolLoopAgent({
146
+ model: this._aiClient,
147
+ instructions: cachedSystem, // 使用缓存版本
148
+ tools: tools,
149
+ stopWhen: (step) => step.stepCount >= maxSteps
150
+ })
151
+ }
152
+ ```
153
+
154
+ **收益**:
155
+ - 降低 30-50% token 消耗
156
+ - 加快响应速度
157
+ - 减少 API 调用成本
158
+
159
+ ---
160
+
161
+ ### 🟡 【中优先级】
162
+
163
+ #### 2.3 流式响应增强 - `smoothStream` / `streamObject`
164
+
165
+ **现状**:流式使用 `stream` 但未使用平滑输出
166
+
167
+ **优化位置**:`src/core/agent-chat.js`
168
+
169
+ **建议修改**:
170
+
171
+ ```javascript
172
+ // 2.3.1 平滑流式输出
173
+ async *chatStream(message, options = {}) {
174
+ // ...
175
+
176
+ const result = await framework.runWithContext(context, async () => {
177
+ return agent.stream({
178
+ messages,
179
+ ...this.providerOptions,
180
+ ...smoothStream({
181
+ delayInMs: 14 // 14ms 平滑间隔
182
+ })
183
+ })
184
+ })
185
+
186
+ // ...
187
+ }
188
+
189
+ // 2.3.2 结构化流式输出 - 新增方法
190
+ async *streamStructured(message, schema, options = {}) {
191
+ const { streamObject } = require('ai')
192
+
193
+ const { partialObjectStream } = await streamObject({
194
+ model: this._aiClient,
195
+ schema,
196
+ prompt: message,
197
+ ...smoothStream({ delayInMs: 14 })
198
+ })
199
+
200
+ for await (const partialObject of partialObjectStream) {
201
+ yield { type: 'partial', data: partialObject }
202
+ }
203
+ }
204
+ ```
205
+
206
+ **收益**:
207
+ - 更流畅的实时输出体验
208
+ - 支持部分对象流式渲染
209
+
210
+ ---
211
+
212
+ #### 2.4 推理模型支持 - o1/o3/R1
213
+
214
+ **现状**:未针对推理模型配置
215
+
216
+ **优化位置**:`src/core/provider.js` 和 `src/core/agent-chat.js`
217
+
218
+ **建议修改**:
219
+
220
+ ```javascript
221
+ // 2.4.1 provider.js - 新增推理模型配置
222
+ const REASONING_MODELS = {
223
+ 'o1-mini': { type: 'reasoning', supportsTools: false, maxTokens: 25000 },
224
+ 'o1-preview': { type: 'reasoning', supportsTools: false, maxTokens: 25000 },
225
+ 'o3-mini': { type: 'reasoning', supportsTools: false, maxTokens: 100000 },
226
+ 'deepseek-r1': { type: 'reasoning', supportsTools: true, maxTokens: 64000 },
227
+ 'deepseek-r1-distill-qwen-32b': { type: 'reasoning', supportsTools: true, maxTokens: 32000 }
228
+ }
229
+
230
+ // 2.4.2 agent-chat.js - 根据模型类型调整配置
231
+ _getAgentConfig() {
232
+ const modelId = this.model.toLowerCase()
233
+
234
+ // 检测是否是推理模型
235
+ const isReasoningModel = Object.keys(REASONING_MODELS)
236
+ .some(name => modelId.includes(name))
237
+
238
+ if (isReasoningModel) {
239
+ const config = REASONING_MODELS[Object.keys(REASONING_MODELS)
240
+ .find(name => modelId.includes(name))]
241
+
242
+ return {
243
+ // 推理模型通常不需要 system prompt
244
+ includeSystemInMessages: false,
245
+ // 推理模型不支持工具或需要特殊处理
246
+ supportsTools: config.supportsTools,
247
+ // 增大 maxTokens
248
+ maxTokens: config.maxTokens
249
+ }
250
+ }
251
+
252
+ return {
253
+ includeSystemInMessages: true,
254
+ supportsTools: true,
255
+ maxTokens: 8192
256
+ }
257
+ }
258
+ ```
259
+
260
+ **收益**:
261
+ - 支持 o1/o3/DeepSeek R1 等推理模型
262
+ - 自动适配推理模型的特殊配置
263
+ - 优化推理任务的性能
264
+
265
+ ---
266
+
267
+ #### 2.5 中间件系统
268
+
269
+ **现状**:缺乏统一的中间件机制
270
+
271
+ **优化位置**:新增 `src/middleware/ai-middleware.js`
272
+
273
+ **建议新增**:
274
+
275
+ ```javascript
276
+ // src/middleware/ai-middleware.js
277
+ const {
278
+ extractReasoningMiddleware,
279
+ defaultSettingsMiddleware,
280
+ withTelemetry
281
+ } = require('ai')
282
+
283
+ /**
284
+ * 创建 AI 中间件
285
+ */
286
+ function createAIMiddleware(options = {}) {
287
+ const middlewares = []
288
+
289
+ // 1. 推理提取中间件
290
+ if (options.extractReasoning !== false) {
291
+ middlewares.push(extractReasoningMiddleware({
292
+ tagName: 'thinking',
293
+ onChunk: (chunk) => {
294
+ options.onReasoning?.(chunk)
295
+ }
296
+ }))
297
+ }
298
+
299
+ // 2. 默认设置中间件
300
+ middlewares.push(defaultSettingsMiddleware({
301
+ settings: {
302
+ [options.defaultModel]: {
303
+ temperature: options.temperature || 0.7,
304
+ maxTokens: options.maxTokens || 8192
305
+ }
306
+ }
307
+ }))
308
+
309
+ // 3. 遥测中间件
310
+ if (options.telemetry) {
311
+ middlewares.push(withTelemetry({
312
+ serviceName: 'foliko-agent',
313
+ metadata: {
314
+ version: options.version,
315
+ sessionId: options.sessionId
316
+ }
317
+ }))
318
+ }
319
+
320
+ return middlewares
321
+ }
322
+
323
+ /**
324
+ * 创建日志中间件(自定义)
325
+ */
326
+ function createLoggingMiddleware() {
327
+ return {
328
+ async wrapModel(model, { doStream }) {
329
+ return {
330
+ doStream: async (prompt, options) => {
331
+ const startTime = Date.now()
332
+ console.log('[AI] Request started:', {
333
+ promptLength: typeof prompt === 'string' ? prompt.length : 'array'
334
+ })
335
+
336
+ try {
337
+ const result = await doStream()
338
+ const duration = Date.now() - startTime
339
+ console.log('[AI] Request completed:', { duration })
340
+ return result
341
+ } catch (error) {
342
+ console.error('[AI] Request failed:', error.message)
343
+ throw error
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+
351
+ module.exports = {
352
+ createAIMiddleware,
353
+ createLoggingMiddleware
354
+ }
355
+ ```
356
+
357
+ **收益**:
358
+ - 统一的日志、监控、遥测
359
+ - 推理过程可追踪
360
+ - 支持自定义中间件扩展
361
+
362
+ ---
363
+
364
+ #### 2.6 Embeddings 支持
365
+
366
+ **现状**:未实现嵌入功能
367
+
368
+ **优化位置**:新增到 `src/plugins/ai-plugin.js` 或创建新文件
369
+
370
+ **建议新增**:
371
+
372
+ ```javascript
373
+ // src/plugins/embeddings-plugin.js 或在 ai-plugin.js 中新增
374
+ const { embed, embedMany } = require('ai')
375
+
376
+ class AIPlugin extends Plugin {
377
+ // ... 现有代码
378
+
379
+ /**
380
+ * 获取嵌入模型
381
+ */
382
+ getEmbeddingModel() {
383
+ if (this._embeddingModel) return this._embeddingModel
384
+
385
+ const embeddingModelId = this._getEmbeddingModelId()
386
+ this._embeddingModel = this._embeddingProvider.textEmbeddingModel(embeddingModelId)
387
+
388
+ return this._embeddingModel
389
+ }
390
+
391
+ _getEmbeddingModelId() {
392
+ const provider = this.config.provider?.toLowerCase()
393
+ const modelMap = {
394
+ 'openai': 'text-embedding-3-small',
395
+ 'deepseek': 'deepseek-embed',
396
+ 'ollama': 'nomic-embed-text'
397
+ }
398
+ return modelMap[provider] || 'text-embedding-3-small'
399
+ }
400
+
401
+ /**
402
+ * 嵌入单个文本
403
+ */
404
+ async embedText(text) {
405
+ const { embedding } = await embed({
406
+ model: this.getEmbeddingModel(),
407
+ value: text
408
+ })
409
+ return embedding
410
+ }
411
+
412
+ /**
413
+ * 批量嵌入
414
+ */
415
+ async embedTexts(texts) {
416
+ const { embeddings } = await embedMany({
417
+ model: this.getEmbeddingModel(),
418
+ values: texts
419
+ })
420
+ return embeddings
421
+ }
422
+ }
423
+ ```
424
+
425
+ **收益**:
426
+ - 支持 RAG 知识库构建
427
+ - 语义搜索基础
428
+ - 文本相似度计算
429
+
430
+ ---
431
+
432
+ ### 🟢 【低优先级】
433
+
434
+ #### 2.7 错误处理增强
435
+
436
+ **现状**:基础错误捕获
437
+
438
+ **优化位置**:`src/core/agent-chat.js`
439
+
440
+ **建议修改**:
441
+
442
+ ```javascript
443
+ // 2.7.1 新增错误类型导入
444
+ const {
445
+ AI_APICallError,
446
+ AI_RetryableError,
447
+ AI_NoSuchModelError,
448
+ AIInvalidPromptError
449
+ } = require('ai')
450
+
451
+ // 2.7.2 增强错误处理
452
+ async chat(message, options = {}) {
453
+ try {
454
+ // ... 现有代码
455
+ } catch (error) {
456
+ if (error instanceof AI_APICallError) {
457
+ switch (error.statusCode) {
458
+ case 400:
459
+ throw new Error(`无效请求: ${error.message}`)
460
+ case 401:
461
+ throw new Error('API 密钥无效或已过期')
462
+ case 429:
463
+ throw new Error('请求频率超限,请稍后重试')
464
+ case 500:
465
+ case 502:
466
+ case 503:
467
+ throw new Error(`AI 服务暂时不可用: ${error.message}`)
468
+ default:
469
+ throw error
470
+ }
471
+ } else if (error instanceof AI_NoSuchModelError) {
472
+ throw new Error(`模型 ${this.model} 不存在或不可用`)
473
+ } else if (error instanceof AIInvalidPromptError) {
474
+ throw new Error(`提示词无效: ${error.message}`)
475
+ }
476
+ throw error
477
+ }
478
+ }
479
+
480
+ // 2.7.3 重试装饰器
481
+ async withRetry(fn, maxRetries = 3, delayMs = 1000) {
482
+ for (let i = 0; i < maxRetries; i++) {
483
+ try {
484
+ return await fn()
485
+ } catch (error) {
486
+ if (i === maxRetries - 1) throw error
487
+ if (!this._isRetryable(error)) throw error
488
+
489
+ console.log(`[AgentChat] Retry ${i + 1}/${maxRetries} after ${delayMs}ms`)
490
+ await new Promise(r => setTimeout(r, delayMs))
491
+ delayMs *= 2 // 指数退避
492
+ }
493
+ }
494
+ }
495
+
496
+ _isRetryable(error) {
497
+ if (error instanceof AI_APICallError) {
498
+ return [429, 500, 502, 503].includes(error.statusCode)
499
+ }
500
+ return false
501
+ }
502
+ ```
503
+
504
+ **收益**:
505
+ - 更健壮的错误恢复
506
+ - 用户友好的错误提示
507
+ - 自动重试机制
508
+
509
+ ---
510
+
511
+ #### 2.8 MCP Elicitation 支持
512
+
513
+ **现状**:使用 MCP 但未支持用户确认
514
+
515
+ **优化位置**:`src/executors/mcp-executor.js`
516
+
517
+ **建议修改**:
518
+
519
+ ```javascript
520
+ // 2.8.1 新增 MCP Elicitation 支持
521
+ async connect() {
522
+ // ... 现有代码
523
+
524
+ // 启用 Elicitation(用户确认)
525
+ if (this.client && typeof this.client.requestConfirmation === 'function') {
526
+ this._enableElicitation = true
527
+ }
528
+ }
529
+
530
+ // 2.8.2 工具调用时请求确认
531
+ async executeToolWithConfirmation(toolName, args) {
532
+ if (!this._enableElicitation) {
533
+ return this.executeTool(toolName, args)
534
+ }
535
+
536
+ // 发送确认请求给用户
537
+ const confirmed = await this._requestUserConfirmation({
538
+ toolName,
539
+ args,
540
+ description: this._getToolDescription(toolName)
541
+ })
542
+
543
+ if (!confirmed) {
544
+ return { error: 'User rejected tool execution' }
545
+ }
546
+
547
+ return this.executeTool(toolName, args)
548
+ }
549
+ ```
550
+
551
+ **收益**:
552
+ - 用户可控制工具执行
553
+ - 提高安全性
554
+ - 支持敏感操作确认
555
+
556
+ ---
557
+
558
+ ## 三、优化优先级汇总
559
+
560
+ | 优先级 | 优化项 | 收益 | 影响范围 | 工作量 |
561
+ |--------|--------|------|----------|--------|
562
+ | 🔴 高 | `generateObject` 意图识别 | 类型安全、智能路由 | `agent-chat.js` | 1天 |
563
+ | 🔴 高 | Prompt Caching | 降低30% token消耗 | `agent-chat.js` | 0.5天 |
564
+ | 🟡 中 | `smoothStream` 流式增强 | 更流畅体验 | `agent-chat.js` | 0.5天 |
565
+ | 🟡 中 | 推理模型支持 | o1/R1 优化 | `provider.js`, `agent-chat.js` | 1天 |
566
+ | 🟡 中 | 中间件系统 | 统一监控/日志 | 新建 `middleware/` | 2天 |
567
+ | 🟡 中 | Embeddings | RAG 基础 | `ai-plugin.js` | 1天 |
568
+ | 🟢 低 | 错误处理增强 | 更健壮 | `agent-chat.js` | 0.5天 |
569
+ | 🟢 低 | MCP Elicitation | 用户控制 | `mcp-executor.js` | 1天 |
570
+
571
+ ---
572
+
573
+ ## 四、实施路线图
574
+
575
+ ### 第一阶段(立即可做)
576
+
577
+ ```
578
+ ✅ generateObject 意图识别
579
+ └── 在 agent-chat.js 新增 _classifyIntent() 方法
580
+
581
+ ✅ Prompt Caching 集成
582
+ └── 在 _buildSystemPrompt() 中使用 cachePrompt()
583
+ ```
584
+
585
+ ### 第二阶段(1周内)
586
+
587
+ ```
588
+ 📦 smoothStream 流式增强
589
+ └── 在 stream() 中添加 smoothStream 配置
590
+
591
+ 📦 推理模型支持
592
+ └── 在 provider.js 新增 REASONING_MODELS 配置
593
+
594
+ 📦 错误处理增强
595
+ └── 使用 AI SDK 错误类型替换基础 catch
596
+ ```
597
+
598
+ ### 第三阶段(长期)
599
+
600
+ ```
601
+ 📦 中间件系统
602
+ └── 新建 src/middleware/ai-middleware.js
603
+
604
+ 📦 Embeddings 支持
605
+ └── 在 ai-plugin.js 新增 embedText/embedTexts 方法
606
+
607
+ 📦 MCP Elicitation
608
+ └── 在 mcp-executor.js 新增用户确认机制
609
+ ```
610
+
611
+ ---
612
+
613
+ ## 五、需要安装的包
614
+
615
+ ```bash
616
+ # 基础已安装
617
+ npm install ai @ai-sdk/openai @ai-sdk/anthropic
618
+
619
+ # 可能需要添加(根据需求)
620
+ npm install @ai-sdk/google # Gemini 模型支持
621
+ npm install @ai-sdk/deepseek # DeepSeek 模型支持
622
+ npm install @ai-sdk/amazon-bedrock # AWS Bedrock 支持
623
+ ```
624
+
625
+ ---
626
+
627
+ ## 六、参考资料
628
+
629
+ - [AI SDK 官方文档](https://ai-sdk.dev/docs/getting-started)
630
+ - [AI SDK Cookbook](https://ai-sdk.dev/cookbook)
631
+ - [AI SDK API Reference](https://ai-sdk.dev/docs/api-reference)
632
+
633
+ ---
634
+
635
+ *文档生成时间:2025-01-25*
636
+ *基于 AI SDK v6 版本分析*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.0.71",
3
+ "version": "1.0.73",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -44,7 +44,7 @@ class AgentChatHandler extends EventEmitter {
44
44
  this._systemPrompt = config.systemPrompt || 'You are a helpful assistant.'
45
45
  this._messages = []
46
46
  this._tools = new Map()
47
- this._maxSteps = 20
47
+ this._maxSteps = 10
48
48
 
49
49
  // 上下文压缩配置:根据模型自动设置限制
50
50
  const modelKey = Object.keys(MODEL_CONTEXT_LIMITS).find(k =>
@@ -59,7 +59,7 @@ class AgentChatHandler extends EventEmitter {
59
59
  this._compressionCount = 0 // 压缩次数统计
60
60
 
61
61
  // 工具结果压缩配置
62
- this._maxToolResultSize = config.maxToolResultSize || 3000 // 工具结果超过此大小则压缩
62
+ this._maxToolResultSize = config.maxToolResultSize || 4000 // 工具结果超过此大小则压缩(字节)
63
63
 
64
64
  // 初始化编码器
65
65
  this._initEncoder()
@@ -128,6 +128,44 @@ class AgentChatHandler extends EventEmitter {
128
128
  return totalTokens > this._maxContextTokens * this._compressionThreshold
129
129
  }
130
130
 
131
+ /**
132
+ * 计算工具定义的 token 数(估算)
133
+ * @returns {number}
134
+ * @private
135
+ */
136
+ _countToolsTokens() {
137
+ let total = 0
138
+ for (const toolDef of this._tools.values()) {
139
+ // 工具名 + 描述
140
+ total += this._countTokens(toolDef.name || '')
141
+ total += this._countTokens(toolDef.description || '')
142
+
143
+ // 工具参数 schema
144
+ if (toolDef.inputSchema) {
145
+ const schemaStr = typeof toolDef.inputSchema === 'string'
146
+ ? toolDef.inputSchema
147
+ : JSON.stringify(toolDef.inputSchema)
148
+ total += this._countTokens(schemaStr)
149
+ }
150
+ }
151
+ return total
152
+ }
153
+
154
+ /**
155
+ * 检查是否需要压缩(包括工具定义)
156
+ * @returns {boolean}
157
+ * @private
158
+ */
159
+ _shouldCompressWithTools() {
160
+ const messagesTokens = this._countMessagesTokens(this._messages)
161
+ const toolsTokens = this._countToolsTokens()
162
+ const systemPromptTokens = this._countTokens(this._systemPrompt)
163
+ const total = messagesTokens + toolsTokens + systemPromptTokens
164
+
165
+ // 如果总token数超过上下文限制的 85%,就压缩
166
+ return total > this._maxContextTokens * 0.85
167
+ }
168
+
131
169
  /**
132
170
  * 压缩上下文消息(智能摘要模式)
133
171
  * 策略:
@@ -252,37 +290,75 @@ ${conversationText}
252
290
 
253
291
  if (!this._aiClient) {
254
292
  console.warn('[AgentChat] Cannot compress tool result: no AI client')
255
- return result
293
+ return this._fallbackCompress(result)
256
294
  }
257
295
 
258
296
  try {
259
297
  const originalSize = typeof result === 'string' ? result.length : JSON.stringify(result).length
260
298
  const resultStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2)
261
299
 
300
+ // 对于超大型内容(如网页),采用更好的截断策略
301
+ const maxInputSize = 6000 // 保留给 AI 处理的输入大小
302
+ const shouldTruncate = resultStr.length > maxInputSize
303
+ const truncatedContent = resultStr.substring(0, maxInputSize)
304
+ const truncatedNote = shouldTruncate ? `\n\n[内容已截断,原始长度 ${originalSize} 字符]` : ''
305
+
306
+ // 检测内容类型
307
+ const isHTML = resultStr.startsWith('<') || resultStr.includes('<html') || resultStr.includes('<!DOCTYPE')
308
+ const isJSON = !isHTML && (resultStr.startsWith('{') || resultStr.startsWith('['))
309
+ const contentTypeHint = isHTML ? '(HTML 网页内容)' : isJSON ? '(JSON 数据)' : ''
310
+
262
311
  // 构建压缩提示
263
- const compressPrompt = `以下是一个工具执行结果,长度 ${originalSize} 字符。请简洁地总结其核心内容,保留关键数据和信息:
312
+ const compressPrompt = `以下是一个工具执行结果${contentTypeHint},长度 ${originalSize} 字符。请简洁地总结其核心内容:
313
+
314
+ ${truncatedContent}${truncatedNote}
264
315
 
265
- ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截断)' : ''}
316
+ 请提取并保留:
317
+ 1. 主要标题和主题
318
+ 2. 关键信息点(不超过 5 个)
319
+ 3. 重要数据或结论
266
320
 
267
- 请用简洁的语言总结(不超过 500 字):`
321
+ 用简洁的中文总结,不超过 400 字:`
268
322
 
269
323
  // 使用 AI SDK 6.x 的 generateText
270
324
  const { generateText } = require('ai')
271
325
  const { text } = await generateText({
272
326
  model: this._aiClient,
273
327
  prompt: compressPrompt,
274
- ...this.providerOptions
328
+ ...this.providerOptions,
329
+ maxTokens: 500
275
330
  })
276
331
 
277
- const summary = text || '(压缩失败,使用原始结果)'
278
- const compressed = `[工具结果已压缩: 原始大小 ${originalSize} 字符 → ${summary.length} 字符]\n\n${summary}`
332
+ const summary = text || '(总结生成失败)'
333
+ const compressed = `[工具结果已压缩${contentTypeHint}: ${originalSize} → ${summary.length} 字符]\n\n${summary}`
279
334
 
280
335
  console.log(`[AgentChat] Tool result compressed: ${originalSize} → ${summary.length} chars`)
281
336
  return compressed
282
337
  } catch (err) {
283
338
  console.warn('[AgentChat] Tool result compression failed:', err.message)
339
+ return this._fallbackCompress(result)
340
+ }
341
+ }
342
+
343
+ /**
344
+ * 回退压缩方法(当 AI 客户端不可用时)
345
+ * @param {any} result - 工具返回结果
346
+ * @returns {string} 压缩后的结果
347
+ * @private
348
+ */
349
+ _fallbackCompress(result) {
350
+ const originalSize = typeof result === 'string' ? result.length : JSON.stringify(result).length
351
+ const resultStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2)
352
+
353
+ // 简单截断策略:保留前 2000 字符
354
+ const maxSize = 2000
355
+ if (resultStr.length <= maxSize) {
284
356
  return result
285
357
  }
358
+
359
+ const compressed = `[工具结果已压缩(简单截断): ${originalSize} → ${maxSize} 字符]\n\n${resultStr.substring(0, maxSize)}\n\n...[内容已截断,原文 ${originalSize} 字符]`
360
+ console.log(`[AgentChat] Tool result fallback compressed: ${originalSize} → ${maxSize} chars`)
361
+ return compressed
286
362
  }
287
363
 
288
364
  /**
@@ -364,9 +440,18 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
364
440
 
365
441
  this._messages.push(userMessage)
366
442
 
367
- // 检查是否需要压缩上下文
368
- if (this._shouldCompress()) {
443
+ // 检查是否需要压缩上下文(包括工具定义)
444
+ const messagesTokens = this._countMessagesTokens(this._messages)
445
+ const toolsTokens = this._countToolsTokens()
446
+ const systemPromptTokens = this._countTokens(this._systemPrompt)
447
+ const totalTokens = messagesTokens + toolsTokens + systemPromptTokens
448
+ const limit = this._maxContextTokens * 0.7 // 降低到 70%,更早压缩
449
+
450
+ if (totalTokens > limit) {
451
+ console.log(`[AgentChat] Context large (${totalTokens}/${this._maxContextTokens} tokens = msgs:${messagesTokens} + tools:${toolsTokens} + sys:${systemPromptTokens}), compressing...`)
369
452
  await this._compressContext()
453
+ } else {
454
+ console.log(`[AgentChat] Context OK: ${totalTokens}/${this._maxContextTokens} tokens`)
370
455
  }
371
456
 
372
457
  const maxSteps = options.maxSteps || this._maxSteps
@@ -380,8 +465,6 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
380
465
  model: this._aiClient,
381
466
  instructions: this._systemPrompt,
382
467
  tools: tools,
383
- maxOutputTokens: options.maxOutputTokens || 5000,
384
- toolChoice:'auto',
385
468
  stopWhen: (step) => step.stepCount >= maxSteps
386
469
  })
387
470
 
@@ -406,6 +489,12 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
406
489
  })
407
490
  }
408
491
 
492
+ // 生成后检查:如果消息太长,下次需要压缩
493
+ const afterTokens = this._countMessagesTokens(this._messages)
494
+ if (afterTokens > this._maxContextTokens * 0.8) {
495
+ console.log(`[AgentChat] After generation: ${afterTokens} tokens, will compress on next turn`)
496
+ }
497
+
409
498
  return {
410
499
  success: true,
411
500
  message: result.text || '',
@@ -436,12 +525,18 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
436
525
 
437
526
  this._messages.push(userMessage)
438
527
 
439
- // 检查是否需要压缩上下文(同步调用,不阻塞流式输出)
440
- if (this._shouldCompress()) {
441
- // 压缩在后台进行,不等待完成,避免阻塞流式输出
442
- this._compressContext().catch(err => {
443
- console.warn('[AgentChat] Background compression failed:', err.message)
444
- })
528
+ // 检查是否需要压缩上下文(包括工具定义)
529
+ const messagesTokens = this._countMessagesTokens(this._messages)
530
+ const toolsTokens = this._countToolsTokens()
531
+ const systemPromptTokens = this._countTokens(this._systemPrompt)
532
+ const totalTokens = messagesTokens + toolsTokens + systemPromptTokens
533
+ const limit = this._maxContextTokens * 0.7 // 降低到 70%
534
+
535
+ // 对于流式调用,如果上下文太大,先压缩再开始
536
+ if (totalTokens > limit) {
537
+ console.log(`[AgentChat] Context large (${totalTokens}/${this._maxContextTokens} tokens), compressing...`)
538
+ // 流式调用时等待压缩完成
539
+ await this._compressContext()
445
540
  }
446
541
 
447
542
  const maxSteps = options.maxSteps || this._maxSteps
@@ -456,8 +551,6 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
456
551
  model: this._aiClient,
457
552
  instructions: this._systemPrompt,
458
553
  tools: tools,
459
- maxOutputTokens: options.maxOutputTokens || 5000,
460
- toolChoice:'auto',
461
554
  stopWhen: (step) => step.stepCount >= maxSteps
462
555
  })
463
556
 
@@ -533,14 +626,17 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
533
626
  name: toolName,
534
627
  description: toolDef.description || '',
535
628
  execute: async (args) => {
629
+ // 清理参数:移除 undefined、function 等无效值
630
+ const cleanedArgs = this._cleanToolArgs(args)
631
+
536
632
  // 执行工具
537
- this.emit('tool-call', { name: toolName, args })
633
+ this.emit('tool-call', { name: toolName, args: cleanedArgs })
538
634
  try {
539
- const result = await toolDef.execute(args, this.agent.framework)
540
- this.emit('tool-result', { name: toolName, args, result })
635
+ const result = await toolDef.execute(cleanedArgs, this.agent.framework)
636
+ this.emit('tool-result', { name: toolName, args: cleanedArgs, result })
541
637
  return result
542
638
  } catch (err) {
543
- this.emit('tool-error', { name: toolName, args, error: err.message })
639
+ this.emit('tool-error', { name: toolName, args: cleanedArgs, error: err.message })
544
640
  return { error: err.message }
545
641
  }
546
642
  }
@@ -560,6 +656,42 @@ ${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截
560
656
  return tools
561
657
  }
562
658
 
659
+ /**
660
+ * 清理工具参数,移除无效值
661
+ * @param {Object} args - 原始参数
662
+ * @returns {Object} 清理后的参数
663
+ * @private
664
+ */
665
+ _cleanToolArgs(args) {
666
+ if (!args || typeof args !== 'object') {
667
+ return {}
668
+ }
669
+
670
+ const cleaned = {}
671
+ for (const [key, value] of Object.entries(args)) {
672
+ // 跳过 undefined、function、symbol 等无效值
673
+ if (value === undefined || value === null) {
674
+ continue
675
+ }
676
+ if (typeof value === 'function' || typeof value === 'symbol') {
677
+ continue
678
+ }
679
+ // 递归清理嵌套对象
680
+ if (typeof value === 'object' && !Array.isArray(value)) {
681
+ cleaned[key] = this._cleanToolArgs(value)
682
+ } else if (Array.isArray(value)) {
683
+ cleaned[key] = value.map(item =>
684
+ typeof item === 'object' && item !== null
685
+ ? this._cleanToolArgs(item)
686
+ : item
687
+ ).filter(item => item !== undefined && typeof item !== 'function')
688
+ } else {
689
+ cleaned[key] = value
690
+ }
691
+ }
692
+ return cleaned
693
+ }
694
+
563
695
  /**
564
696
  * 清理消息格式
565
697
  * @private
@@ -30,6 +30,10 @@ const DEFAULT_PROVIDERS = {
30
30
  anthropic: {
31
31
  name: 'Anthropic',
32
32
  baseURL: 'https://api.anthropic.com/v1'
33
+ },
34
+ minimax: {
35
+ name: 'MiniMax',
36
+ baseURL: 'https://api.minimaxi.com/v1'
33
37
  }
34
38
  }
35
39