foliko 1.0.49 → 1.0.50

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.
@@ -116,7 +116,8 @@
116
116
  "Bash(taskkill //F //PID 19848)",
117
117
  "Bash(curl -s -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1)",
118
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)"
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)"
120
121
  ]
121
122
  }
122
123
  }
package/examples/basic.js CHANGED
@@ -1,110 +1,110 @@
1
- /**
2
- * 基础示例
3
- * 展示如何使用 Framework 和 Agent
4
- */
5
-
6
- const { Framework } = require('../src')
7
- const { AIPlugin } = require('../plugins/ai-plugin')
8
- const { z } = require('zod')
9
-
10
- async function main() {
11
- // 创建框架实例
12
- const framework = new Framework({ debug: true })
13
-
14
- // 加载 AI 插件
15
- await framework.loadPlugin(new AIPlugin({
16
- provider: 'deepseek',
17
- model: 'deepseek-chat',
18
- apiKey: process.env.DEEPSEEK_API_KEY || 'your-api-key'
19
- }))
20
-
21
- // 注册自定义工具(使用 inputSchema 格式)
22
- framework.registerTool({
23
- name: 'hello',
24
- description: '打招呼工具',
25
- inputSchema: z.object({
26
- name: z.string().optional().describe('姓名')
27
- }),
28
- execute: async (args) => {
29
- return `Hello, ${args.name || 'World'}!`
30
- }
31
- })
32
-
33
- // 注册计算器工具
34
- framework.registerTool({
35
- name: 'calculate',
36
- description: '简单的计算器',
37
- inputSchema: z.object({
38
- expression: z.string().describe('数学表达式,如 2+3*4')
39
- }),
40
- execute: async (args) => {
41
- try {
42
- // 安全计算(仅支持基本运算)
43
- const result = Function(`"use strict"; return (${args.expression})`)()
44
- return { result }
45
- } catch (e) {
46
- return { error: e.message }
47
- }
48
- }
49
- })
50
-
51
- console.log('[Framework] Ready!')
52
- console.log('[Tools]', framework.getTools().map(t => t.name))
53
-
54
- // 创建 Agent
55
- const agent = framework.createAgent({
56
- name: 'MyAgent',
57
- systemPrompt: '你是一个有帮助的助手。当需要计算时,使用 calculate 工具。'
58
- })
59
-
60
- // 监听事件
61
- agent.on('tool-call', (tool) => {
62
- console.log('[Agent] Tool call:', tool.name, tool.args)
63
- })
64
-
65
- agent.on('tool-result', (result) => {
66
- console.log('[Agent] Tool result:', result.name, result.result)
67
- })
68
-
69
- // AI 对话示例
70
- console.log('\n=== AI Chat Example ===')
71
- try {
72
- const response = await agent.chat('你好!')
73
- console.log('[Agent] Response:', response.message)
74
- } catch (err) {
75
- console.error('[Agent] Error:', err.message)
76
- }
77
-
78
- // 使用工具的对话示例
79
- console.log('\n=== AI Chat with Tool Call ===')
80
- try {
81
- const response = await agent.chat('请帮我计算 (15 + 25) * 2 等于多少?')
82
- console.log('[Agent] Response:', response.message)
83
- } catch (err) {
84
- console.error('[Agent] Error:', err.message)
85
- }
86
-
87
- // 流式对话示例
88
- console.log('\n=== Streaming Chat ===')
89
- try {
90
- for await (const chunk of agent.chatStream('请用中文介绍一下你自己')) {
91
- if (chunk.type === 'text') {
92
- process.stdout.write(chunk.text)
93
- }
94
- }
95
- console.log('\n')
96
- } catch (err) {
97
- console.error('[Agent] Stream Error:', err.message)
98
- }
99
-
100
- // 热重载示例
101
- console.log('\n=== Hot Reload ===')
102
- await framework.reloadPlugin('ai')
103
- console.log('AI plugin reloaded!')
104
-
105
- // 清理
106
- await framework.destroy()
107
- console.log('\n[Done]')
108
- }
109
-
110
- main().catch(console.error)
1
+ /**
2
+ * 基础示例
3
+ * 展示如何使用 Framework 和 Agent
4
+ */
5
+
6
+ const { Framework } = require('../src')
7
+ const { AIPlugin } = require('../plugins/ai-plugin')
8
+ const { z } = require('zod')
9
+
10
+ async function main() {
11
+ // 创建框架实例
12
+ const framework = new Framework({ debug: true })
13
+
14
+ // 加载 AI 插件
15
+ await framework.loadPlugin(new AIPlugin({
16
+ provider: 'deepseek',
17
+ model: 'deepseek-chat',
18
+ apiKey: process.env.DEEPSEEK_API_KEY || 'your-api-key'
19
+ }))
20
+
21
+ // 注册自定义工具(使用 inputSchema 格式)
22
+ framework.registerTool({
23
+ name: 'hello',
24
+ description: '打招呼工具',
25
+ inputSchema: z.object({
26
+ name: z.string().optional().describe('姓名')
27
+ }),
28
+ execute: async (args) => {
29
+ return `Hello, ${args.name || 'World'}!`
30
+ }
31
+ })
32
+
33
+ // 注册计算器工具
34
+ framework.registerTool({
35
+ name: 'calculate',
36
+ description: '简单的计算器',
37
+ inputSchema: z.object({
38
+ expression: z.string().describe('数学表达式,如 2+3*4')
39
+ }),
40
+ execute: async (args) => {
41
+ try {
42
+ // 安全计算(仅支持基本运算)
43
+ const result = Function(`"use strict"; return (${args.expression})`)()
44
+ return { result }
45
+ } catch (e) {
46
+ return { error: e.message }
47
+ }
48
+ }
49
+ })
50
+
51
+ console.log('[Framework] Ready!')
52
+ console.log('[Tools]', framework.getTools().map(t => t.name))
53
+
54
+ // 创建 Agent
55
+ const agent = framework.createAgent({
56
+ name: 'MyAgent',
57
+ systemPrompt: '你是一个有帮助的助手。当需要计算时,使用 calculate 工具。'
58
+ })
59
+
60
+ // 监听事件
61
+ agent.on('tool-call', (tool) => {
62
+ console.log('[Agent] Tool call:', tool.name, tool.args)
63
+ })
64
+
65
+ agent.on('tool-result', (result) => {
66
+ console.log('[Agent] Tool result:', result.name, result.result)
67
+ })
68
+
69
+ // AI 对话示例
70
+ console.log('\n=== AI Chat Example ===')
71
+ try {
72
+ const response = await agent.chat('你好!')
73
+ console.log('[Agent] Response:', response.message)
74
+ } catch (err) {
75
+ console.error('[Agent] Error:', err.message)
76
+ }
77
+
78
+ // 使用工具的对话示例
79
+ console.log('\n=== AI Chat with Tool Call ===')
80
+ try {
81
+ const response = await agent.chat('请帮我计算 (15 + 25) * 2 等于多少?')
82
+ console.log('[Agent] Response:', response.message)
83
+ } catch (err) {
84
+ console.error('[Agent] Error:', err.message)
85
+ }
86
+
87
+ // 流式对话示例
88
+ console.log('\n=== Streaming Chat ===')
89
+ try {
90
+ for await (const chunk of agent.chatStream('请用中文介绍一下你自己')) {
91
+ if (chunk.type === 'text') {
92
+ process.stdout.write(chunk.text)
93
+ }
94
+ }
95
+ console.log('\n')
96
+ } catch (err) {
97
+ console.error('[Agent] Stream Error:', err.message)
98
+ }
99
+
100
+ // 热重载示例
101
+ console.log('\n=== Hot Reload ===')
102
+ await framework.reloadPlugin('ai')
103
+ console.log('AI plugin reloaded!')
104
+
105
+ // 清理
106
+ await framework.destroy()
107
+ console.log('\n[Done]')
108
+ }
109
+
110
+ main().catch(console.error)
@@ -1,53 +1,53 @@
1
- /**
2
- * MCP 执行器示例
3
- * 展示如何连接 MCP 服务器
4
- */
5
-
6
- const { Framework } = require('../src')
7
- const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
8
-
9
- async function main() {
10
- console.log('=== MCP Executor Example ===\n')
11
-
12
- // 创建框架
13
- const framework = new Framework({ debug: true })
14
-
15
- // 创建 MCP 执行器插件
16
- const mcpPlugin = new MCPExecutorPlugin({
17
- servers: [
18
- // 示例:添加一个 MCP 服务器
19
- // {
20
- // name: 'example',
21
- // command: 'uvx',
22
- // args: ['example-mcp-server'],
23
- // env: {}
24
- // }
25
- ]
26
- })
27
-
28
- // 加载插件
29
- await framework.loadPlugin(mcpPlugin)
30
-
31
- // 列出服务器
32
- console.log('\n--- MCP Servers ---')
33
- const servers = mcpPlugin.getServers()
34
- console.log('Servers:', servers)
35
-
36
- // 列出所有 MCP 工具
37
- console.log('\n--- MCP Tools ---')
38
- const tools = framework.getTools().filter(t => t.name.startsWith('mcp_'))
39
- console.log('MCP tools:', tools.map(t => t.name))
40
-
41
- // 如果有配置的服务器,可以这样调用:
42
- // const result = await framework.executeTool('mcp_call', {
43
- // server: 'example',
44
- // tool: 'tool_name',
45
- // args: { /* tool arguments */ }
46
- // })
47
-
48
- // 清理
49
- await framework.destroy()
50
- console.log('\n[Done]')
51
- }
52
-
53
- main().catch(console.error)
1
+ /**
2
+ * MCP 执行器示例
3
+ * 展示如何连接 MCP 服务器
4
+ */
5
+
6
+ const { Framework } = require('../src')
7
+ const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
8
+
9
+ async function main() {
10
+ console.log('=== MCP Executor Example ===\n')
11
+
12
+ // 创建框架
13
+ const framework = new Framework({ debug: true })
14
+
15
+ // 创建 MCP 执行器插件
16
+ const mcpPlugin = new MCPExecutorPlugin({
17
+ servers: [
18
+ // 示例:添加一个 MCP 服务器
19
+ // {
20
+ // name: 'example',
21
+ // command: 'uvx',
22
+ // args: ['example-mcp-server'],
23
+ // env: {}
24
+ // }
25
+ ]
26
+ })
27
+
28
+ // 加载插件
29
+ await framework.loadPlugin(mcpPlugin)
30
+
31
+ // 列出服务器
32
+ console.log('\n--- MCP Servers ---')
33
+ const servers = mcpPlugin.getServers()
34
+ console.log('Servers:', servers)
35
+
36
+ // 列出所有 MCP 工具
37
+ console.log('\n--- MCP Tools ---')
38
+ const tools = framework.getTools().filter(t => t.name.startsWith('mcp_'))
39
+ console.log('MCP tools:', tools.map(t => t.name))
40
+
41
+ // 如果有配置的服务器,可以这样调用:
42
+ // const result = await framework.executeTool('mcp_call', {
43
+ // server: 'example',
44
+ // tool: 'tool_name',
45
+ // args: { /* tool arguments */ }
46
+ // })
47
+
48
+ // 清理
49
+ await framework.destroy()
50
+ console.log('\n[Done]')
51
+ }
52
+
53
+ main().catch(console.error)
@@ -1,49 +1,49 @@
1
- /**
2
- * Skill 管理器示例
3
- * 展示如何加载和使用 Skill
4
- */
5
-
6
- const { Framework } = require('../src')
7
- const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
8
-
9
- async function main() {
10
- console.log('=== Skill Manager Example ===\n')
11
-
12
- // 创建框架
13
- const framework = new Framework({ debug: true })
14
-
15
- // 创建 skills 目录(如果没有)
16
- const fs = require('fs')
17
- const skillsDir = './skills'
18
- if (!fs.existsSync(skillsDir)) {
19
- fs.mkdirSync(skillsDir, { recursive: true })
20
- }
21
-
22
- // 加载 Skill 管理器插件
23
- const skillPlugin = new SkillManagerPlugin({
24
- skillsDir: skillsDir
25
- })
26
-
27
- await framework.loadPlugin(skillPlugin)
28
-
29
- // 列出所有加载的 skills
30
- console.log('\n--- Loaded Skills ---')
31
- const skills = skillPlugin.getAllSkills()
32
- console.log(`Found ${skills.length} skills:`)
33
- for (const skill of skills) {
34
- console.log(` - ${skill.name}: ${skill.metadata.description}`)
35
- }
36
-
37
- // 获取单个 skill
38
- if (skillPlugin.hasSkill('hello-skill')) {
39
- console.log('\n--- Hello Skill ---')
40
- const helloSkill = skillPlugin.getSkill('hello-skill')
41
- console.log('Content preview:', helloSkill.content.substring(0, 100) + '...')
42
- }
43
-
44
- // 清理
45
- await framework.destroy()
46
- console.log('\n[Done]')
47
- }
48
-
49
- main().catch(console.error)
1
+ /**
2
+ * Skill 管理器示例
3
+ * 展示如何加载和使用 Skill
4
+ */
5
+
6
+ const { Framework } = require('../src')
7
+ const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
8
+
9
+ async function main() {
10
+ console.log('=== Skill Manager Example ===\n')
11
+
12
+ // 创建框架
13
+ const framework = new Framework({ debug: true })
14
+
15
+ // 创建 skills 目录(如果没有)
16
+ const fs = require('fs')
17
+ const skillsDir = './skills'
18
+ if (!fs.existsSync(skillsDir)) {
19
+ fs.mkdirSync(skillsDir, { recursive: true })
20
+ }
21
+
22
+ // 加载 Skill 管理器插件
23
+ const skillPlugin = new SkillManagerPlugin({
24
+ skillsDir: skillsDir
25
+ })
26
+
27
+ await framework.loadPlugin(skillPlugin)
28
+
29
+ // 列出所有加载的 skills
30
+ console.log('\n--- Loaded Skills ---')
31
+ const skills = skillPlugin.getAllSkills()
32
+ console.log(`Found ${skills.length} skills:`)
33
+ for (const skill of skills) {
34
+ console.log(` - ${skill.name}: ${skill.metadata.description}`)
35
+ }
36
+
37
+ // 获取单个 skill
38
+ if (skillPlugin.hasSkill('hello-skill')) {
39
+ console.log('\n--- Hello Skill ---')
40
+ const helloSkill = skillPlugin.getSkill('hello-skill')
41
+ console.log('Content preview:', helloSkill.content.substring(0, 100) + '...')
42
+ }
43
+
44
+ // 清理
45
+ await framework.destroy()
46
+ console.log('\n[Done]')
47
+ }
48
+
49
+ main().catch(console.error)
@@ -1,79 +1,79 @@
1
- /**
2
- * MCP 插件测试脚本
3
- */
4
-
5
- const { Framework } = require('../src')
6
- const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
7
-
8
- async function test() {
9
- console.log('=== MCP Plugin Test ===\n')
10
-
11
- console.log('1. Creating framework...')
12
- const framework = new Framework({ debug: true })
13
-
14
- console.log('2. Creating MCP plugin with fetch server...')
15
- const mcpPlugin = new MCPExecutorPlugin({
16
- servers: [
17
- {
18
- name: 'fetch',
19
- command: 'uvx',
20
- args: ['mcp-server-fetch']
21
- }
22
- ]
23
- })
24
-
25
- console.log('3. Loading MCP plugin...')
26
- await framework.loadPlugin(mcpPlugin)
27
-
28
- console.log('4. Starting framework...')
29
- await framework.pluginManager.startAll()
30
-
31
- // 等待 MCP 服务器连接
32
- console.log('\n5. Waiting for MCP connection...')
33
- await new Promise(resolve => setTimeout(resolve, 2000))
34
-
35
- console.log('\n6. Listing MCP servers...')
36
- const servers = mcpPlugin.getServers()
37
- console.log('Servers:', JSON.stringify(servers, null, 2))
38
-
39
- console.log('\n7. Listing MCP tools...')
40
- const mcpTools = framework.getTools().filter(t => t.name.startsWith('mcp_'))
41
- console.log('MCP Tools:', mcpTools.map(t => t.name))
42
-
43
- if (mcpTools.length > 0) {
44
- console.log('\n8. Testing mcp_list_servers...')
45
- const listResult = await framework.executeTool('mcp_list_servers', {})
46
- console.log('List Servers Result:', JSON.stringify(listResult, null, 2))
47
-
48
- console.log('\n9. Testing mcp_tool_schema...')
49
- const schemaResult = await framework.executeTool('mcp_tool_schema', {
50
- server: 'fetch',
51
- tool: 'fetch'
52
- })
53
- console.log('Tool Schema:', JSON.stringify(schemaResult, null, 2))
54
-
55
- console.log('\n10. Testing mcp_call (fetch a webpage)...')
56
- const callResult = await framework.executeTool('mcp_call', {
57
- server: 'fetch',
58
- tool: 'fetch',
59
- args_json: JSON.stringify({ url: 'https://httpbin.org/get' })
60
- })
61
- console.log('Fetch Result (truncated):', JSON.stringify(callResult, null, 2).substring(0, 500) + '...')
62
- }
63
-
64
- console.log('\n11. Destroying framework...')
65
- await framework.destroy()
66
-
67
- console.log('\n=== Test Complete ===')
68
- }
69
-
70
- test()
71
- .then(() => {
72
- console.log('\n✓ Test completed successfully')
73
- process.exit(0)
74
- })
75
- .catch(err => {
76
- console.error('\n✗ Test failed:', err.message)
77
- console.error(err.stack)
78
- process.exit(1)
79
- })
1
+ /**
2
+ * MCP 插件测试脚本
3
+ */
4
+
5
+ const { Framework } = require('../src')
6
+ const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
7
+
8
+ async function test() {
9
+ console.log('=== MCP Plugin Test ===\n')
10
+
11
+ console.log('1. Creating framework...')
12
+ const framework = new Framework({ debug: true })
13
+
14
+ console.log('2. Creating MCP plugin with fetch server...')
15
+ const mcpPlugin = new MCPExecutorPlugin({
16
+ servers: [
17
+ {
18
+ name: 'fetch',
19
+ command: 'uvx',
20
+ args: ['mcp-server-fetch']
21
+ }
22
+ ]
23
+ })
24
+
25
+ console.log('3. Loading MCP plugin...')
26
+ await framework.loadPlugin(mcpPlugin)
27
+
28
+ console.log('4. Starting framework...')
29
+ await framework.pluginManager.startAll()
30
+
31
+ // 等待 MCP 服务器连接
32
+ console.log('\n5. Waiting for MCP connection...')
33
+ await new Promise(resolve => setTimeout(resolve, 2000))
34
+
35
+ console.log('\n6. Listing MCP servers...')
36
+ const servers = mcpPlugin.getServers()
37
+ console.log('Servers:', JSON.stringify(servers, null, 2))
38
+
39
+ console.log('\n7. Listing MCP tools...')
40
+ const mcpTools = framework.getTools().filter(t => t.name.startsWith('mcp_'))
41
+ console.log('MCP Tools:', mcpTools.map(t => t.name))
42
+
43
+ if (mcpTools.length > 0) {
44
+ console.log('\n8. Testing mcp_list_servers...')
45
+ const listResult = await framework.executeTool('mcp_list_servers', {})
46
+ console.log('List Servers Result:', JSON.stringify(listResult, null, 2))
47
+
48
+ console.log('\n9. Testing mcp_tool_schema...')
49
+ const schemaResult = await framework.executeTool('mcp_tool_schema', {
50
+ server: 'fetch',
51
+ tool: 'fetch'
52
+ })
53
+ console.log('Tool Schema:', JSON.stringify(schemaResult, null, 2))
54
+
55
+ console.log('\n10. Testing mcp_call (fetch a webpage)...')
56
+ const callResult = await framework.executeTool('mcp_call', {
57
+ server: 'fetch',
58
+ tool: 'fetch',
59
+ args_json: JSON.stringify({ url: 'https://httpbin.org/get' })
60
+ })
61
+ console.log('Fetch Result (truncated):', JSON.stringify(callResult, null, 2).substring(0, 500) + '...')
62
+ }
63
+
64
+ console.log('\n11. Destroying framework...')
65
+ await framework.destroy()
66
+
67
+ console.log('\n=== Test Complete ===')
68
+ }
69
+
70
+ test()
71
+ .then(() => {
72
+ console.log('\n✓ Test completed successfully')
73
+ process.exit(0)
74
+ })
75
+ .catch(err => {
76
+ console.error('\n✗ Test failed:', err.message)
77
+ console.error(err.stack)
78
+ process.exit(1)
79
+ })
@@ -1,61 +1,61 @@
1
- /**
2
- * MCP mcp_reload 功能测试
3
- */
4
-
5
- const { Framework } = require('../src')
6
- const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
7
- const fs = require('fs')
8
- const path = require('path')
9
-
10
- async function test() {
11
- console.log('=== Testing mcp_reload ===\n')
12
-
13
- // 创建框架
14
- const framework = new Framework({ debug: true })
15
-
16
- // 创建 MCP 插件
17
- const mcpPlugin = new MCPExecutorPlugin({
18
- servers: [
19
- { name: 'fetch', command: 'uvx', args: ['mcp-server-fetch'] }
20
- ]
21
- })
22
-
23
- // 加载并启动
24
- await framework.loadPlugin(mcpPlugin)
25
- await framework.pluginManager.startAll()
26
-
27
- // 等待连接
28
- await new Promise(r => setTimeout(r, 2000))
29
-
30
- console.log('\n1. 初始服务器列表:')
31
- const initialServers = mcpPlugin.getServers()
32
- console.log(JSON.stringify(initialServers, null, 2))
33
-
34
- // 测试 mcp_reload
35
- console.log('\n2. 调用 mcp_reload...')
36
- const result = await framework.executeTool('mcp_reload', {})
37
- console.log('mcp_reload 结果:')
38
- console.log(JSON.stringify(result, null, 2))
39
-
40
- // 检查配置
41
- console.log('\n3. 当前配置文件:')
42
- const configPath = path.resolve('.agent/mcp_config.json')
43
- if (fs.existsSync(configPath)) {
44
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
45
- console.log(JSON.stringify(config, null, 2))
46
- } else {
47
- console.log('配置文件不存在: ' + configPath)
48
- }
49
-
50
- // 清理
51
- await framework.destroy()
52
-
53
- console.log('\n=== 测试完成 ===')
54
- }
55
-
56
- test()
57
- .then(() => process.exit(0))
58
- .catch(err => {
59
- console.error('测试失败:', err)
60
- process.exit(1)
61
- })
1
+ /**
2
+ * MCP mcp_reload 功能测试
3
+ */
4
+
5
+ const { Framework } = require('../src')
6
+ const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
7
+ const fs = require('fs')
8
+ const path = require('path')
9
+
10
+ async function test() {
11
+ console.log('=== Testing mcp_reload ===\n')
12
+
13
+ // 创建框架
14
+ const framework = new Framework({ debug: true })
15
+
16
+ // 创建 MCP 插件
17
+ const mcpPlugin = new MCPExecutorPlugin({
18
+ servers: [
19
+ { name: 'fetch', command: 'uvx', args: ['mcp-server-fetch'] }
20
+ ]
21
+ })
22
+
23
+ // 加载并启动
24
+ await framework.loadPlugin(mcpPlugin)
25
+ await framework.pluginManager.startAll()
26
+
27
+ // 等待连接
28
+ await new Promise(r => setTimeout(r, 2000))
29
+
30
+ console.log('\n1. 初始服务器列表:')
31
+ const initialServers = mcpPlugin.getServers()
32
+ console.log(JSON.stringify(initialServers, null, 2))
33
+
34
+ // 测试 mcp_reload
35
+ console.log('\n2. 调用 mcp_reload...')
36
+ const result = await framework.executeTool('mcp_reload', {})
37
+ console.log('mcp_reload 结果:')
38
+ console.log(JSON.stringify(result, null, 2))
39
+
40
+ // 检查配置
41
+ console.log('\n3. 当前配置文件:')
42
+ const configPath = path.resolve('.agent/mcp_config.json')
43
+ if (fs.existsSync(configPath)) {
44
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
45
+ console.log(JSON.stringify(config, null, 2))
46
+ } else {
47
+ console.log('配置文件不存在: ' + configPath)
48
+ }
49
+
50
+ // 清理
51
+ await framework.destroy()
52
+
53
+ console.log('\n=== 测试完成 ===')
54
+ }
55
+
56
+ test()
57
+ .then(() => process.exit(0))
58
+ .catch(err => {
59
+ console.error('测试失败:', err)
60
+ process.exit(1)
61
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.0.49",
3
+ "version": "1.0.50",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -40,6 +40,7 @@
40
40
  "node-telegram-bot-api": "^0.67.0",
41
41
  "nodemailer": "^6.10.0",
42
42
  "qrcode-terminal": "^0.12.0",
43
+ "tiktoken": "^1.0.22",
43
44
  "zod": "^3.24.0"
44
45
  }
45
46
  }
@@ -32,7 +32,7 @@ class SessionPlugin extends Plugin {
32
32
  this.config = {
33
33
  sessionTTL: config.sessionTTL || 30 * 60 * 1000, // 30分钟
34
34
  maxSessions: config.maxSessions || 100,
35
- maxHistoryLength: config.maxHistoryLength || 50,
35
+ maxHistoryLength: config.maxHistoryLength || 150, // 放宽到 150,Agent 已有智能压缩
36
36
  autoCleanup: config.autoCleanup !== false,
37
37
  cleanupInterval: config.cleanupInterval || 5 * 60 * 1000 // 5分钟
38
38
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  const { EventEmitter } = require('../utils/event-emitter')
7
+ const tiktoken = require('tiktoken')
7
8
 
8
9
  class AgentChatHandler extends EventEmitter {
9
10
  /**
@@ -27,8 +28,172 @@ class AgentChatHandler extends EventEmitter {
27
28
  this._tools = new Map()
28
29
  this._maxSteps = 20
29
30
 
30
- // AI 客户端
31
- this._aiClient = null
31
+ // 上下文压缩配置
32
+ this._maxContextTokens = config.maxContextTokens || 100000
33
+ this._compressionThreshold = config.compressionThreshold || 0.75
34
+ this._keepRecentMessages = config.keepRecentMessages || 30
35
+ this._enableSmartCompress = config.enableSmartCompress !== false // 默认开启智能摘要
36
+ this._encoder = null
37
+ this._compressionCount = 0 // 压缩次数统计
38
+
39
+ // 初始化编码器
40
+ this._initEncoder()
41
+ }
42
+
43
+ /**
44
+ * 初始化 tiktoken 编码器
45
+ * @private
46
+ */
47
+ _initEncoder() {
48
+ try {
49
+ // cl100k_base 是 GPT-4/ChatGPT 使用的编码
50
+ this._encoder = tiktoken.get_encoding('cl100k_base')
51
+ } catch (err) {
52
+ console.warn('[AgentChat] Failed to initialize tiktoken encoder:', err.message)
53
+ }
54
+ }
55
+
56
+ /**
57
+ * 计算文本的 token 数
58
+ * @param {string} text
59
+ * @returns {number}
60
+ * @private
61
+ */
62
+ _countTokens(text) {
63
+ if (!this._encoder || !text) return 0
64
+ try {
65
+ return this._encoder.encode(text).length
66
+ } catch (err) {
67
+ // 粗略估算:约 4 字符 = 1 token
68
+ return Math.ceil(text.length / 4)
69
+ }
70
+ }
71
+
72
+ /**
73
+ * 计算消息列表的总 token 数
74
+ * @param {Array} messages
75
+ * @returns {number}
76
+ * @private
77
+ */
78
+ _countMessagesTokens(messages) {
79
+ let total = 0
80
+ for (const msg of messages) {
81
+ total += 4 // role 标记
82
+ if (typeof msg.content === 'string') {
83
+ total += this._countTokens(msg.content)
84
+ } else if (Array.isArray(msg.content)) {
85
+ for (const part of msg.content) {
86
+ if (part.text) {
87
+ total += this._countTokens(part.text)
88
+ }
89
+ }
90
+ }
91
+ }
92
+ total += 4 // 结尾标记
93
+ return total
94
+ }
95
+
96
+ /**
97
+ * 检查是否需要压缩上下文
98
+ * @returns {boolean}
99
+ * @private
100
+ */
101
+ _shouldCompress() {
102
+ const totalTokens = this._countMessagesTokens(this._messages)
103
+ return totalTokens > this._maxContextTokens * this._compressionThreshold
104
+ }
105
+
106
+ /**
107
+ * 压缩上下文消息(智能摘要模式)
108
+ * 策略:
109
+ * 1. 如果启用了智能摘要且有 AI 客户端,对早期消息进行 AI 总结
110
+ * 2. 否则使用简单裁剪 + 标记
111
+ * @private
112
+ */
113
+ async _compressContext() {
114
+ if (this._messages.length <= this._keepRecentMessages) {
115
+ return
116
+ }
117
+
118
+ const systemMessages = this._messages.filter(m => m.role === 'system')
119
+ const otherMessages = this._messages.filter(m => m.role !== 'system')
120
+
121
+ // 保留最近的 N 条非系统消息
122
+ const recentMessages = otherMessages.slice(-this._keepRecentMessages)
123
+ const messagesToSummarize = otherMessages.slice(0, -this._keepRecentMessages)
124
+
125
+ const compressedCount = messagesToSummarize.length
126
+ let summaryContent = ''
127
+
128
+ // 尝试使用 AI 总结
129
+ if (this._enableSmartCompress && this._aiClient) {
130
+ try {
131
+ const summaryText = await this._summarizeMessages(messagesToSummarize)
132
+ summaryContent = `[早期对话摘要]: ${summaryText}`
133
+ console.log(`[AgentChat] AI 摘要生成成功 (${summaryText.length} chars)`)
134
+ } catch (err) {
135
+ console.warn('[AgentChat] AI 摘要失败,使用简单压缩:', err.message)
136
+ summaryContent = `[上下文已压缩: 省略了 ${compressedCount} 条早期消息。保留了最近 ${this._keepRecentMessages} 条对话记录。]`
137
+ }
138
+ } else {
139
+ summaryContent = `[上下文已压缩: 省略了 ${compressedCount} 条早期消息。保留了最近 ${this._keepRecentMessages} 条对话记录。]`
140
+ }
141
+
142
+ const summary = {
143
+ role: 'system',
144
+ content: summaryContent
145
+ }
146
+
147
+ this._messages = [...systemMessages, summary, ...recentMessages]
148
+ this._compressionCount++
149
+
150
+ const totalTokens = this._countMessagesTokens(this._messages)
151
+ console.log(`[AgentChat] Context compressed (${this._compressionCount} times). Messages: ${this._messages.length}, Est. tokens: ${totalTokens}`)
152
+ }
153
+
154
+ /**
155
+ * 使用 AI 对消息进行总结
156
+ * @param {Array} messages - 要总结的消息
157
+ * @returns {Promise<string>} 总结文本
158
+ * @private
159
+ */
160
+ async _summarizeMessages(messages) {
161
+ if (!this._aiClient || messages.length === 0) {
162
+ return '(无早期对话)'
163
+ }
164
+
165
+ // 构建总结提示
166
+ const conversationText = messages.map(m => {
167
+ const role = m.role === 'user' ? '用户' : '助手'
168
+ const content = typeof m.content === 'string' ? m.content : JSON.stringify(m.content)
169
+ return `${role}: ${content}`
170
+ }).join('\n')
171
+
172
+ const summarizePrompt = `请简洁地总结以下对话的要点,保留关键信息和用户需求:
173
+
174
+ ${conversationText}
175
+
176
+ 总结要求:
177
+ 1. 提取用户的主要需求和意图
178
+ 2. 保留关键的技术细节或决策
179
+ 3. 不要超过 500 字
180
+ 4. 用中文回复`
181
+
182
+ // 使用 AI 生成摘要
183
+ const { ToolLoopAgent } = await this._importAI()
184
+ const agent = new ToolLoopAgent({
185
+ model: this._aiClient,
186
+ instructions: '你是一个对话总结助手。请根据用户提供的对话生成简洁的摘要。',
187
+ tools: []
188
+ })
189
+
190
+ const result = await agent.generate({
191
+ messages: [
192
+ { role: 'user', content: summarizePrompt }
193
+ ]
194
+ })
195
+
196
+ return result.text || '(总结生成失败)'
32
197
  }
33
198
 
34
199
  /**
@@ -63,6 +228,7 @@ class AgentChatHandler extends EventEmitter {
63
228
  */
64
229
  clearHistory() {
65
230
  this._messages = []
231
+ this._compressionCount = 0
66
232
  return this
67
233
  }
68
234
 
@@ -108,6 +274,11 @@ class AgentChatHandler extends EventEmitter {
108
274
 
109
275
  this._messages.push(userMessage)
110
276
 
277
+ // 检查是否需要压缩上下文
278
+ if (this._shouldCompress()) {
279
+ await this._compressContext()
280
+ }
281
+
111
282
  const maxSteps = options.maxSteps || this._maxSteps
112
283
  const tools = this._getAITools(tool)
113
284
 
@@ -169,6 +340,14 @@ class AgentChatHandler extends EventEmitter {
169
340
 
170
341
  this._messages.push(userMessage)
171
342
 
343
+ // 检查是否需要压缩上下文(同步调用,不阻塞流式输出)
344
+ if (this._shouldCompress()) {
345
+ // 压缩在后台进行,不等待完成,避免阻塞流式输出
346
+ this._compressContext().catch(err => {
347
+ console.warn('[AgentChat] Background compression failed:', err.message)
348
+ })
349
+ }
350
+
172
351
  const maxSteps = options.maxSteps || this._maxSteps
173
352
  const tools = this._getAITools(tool)
174
353
 
@@ -301,6 +480,10 @@ class AgentChatHandler extends EventEmitter {
301
480
  destroy() {
302
481
  this._messages = []
303
482
  this._tools.clear()
483
+ if (this._encoder) {
484
+ this._encoder.free()
485
+ this._encoder = null
486
+ }
304
487
  this.removeAllListeners()
305
488
  }
306
489
  }
@@ -1,58 +1,58 @@
1
- /**
2
- * Executor 基类
3
- * 执行器的基类,定义执行器接口
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter')
7
-
8
- class ExecutorBase extends EventEmitter {
9
- /**
10
- * @param {string} name - 执行器名称
11
- */
12
- constructor(name) {
13
- super()
14
- this.name = name
15
- this._enabled = true
16
- }
17
-
18
- /**
19
- * 执行
20
- * @param {Object} params - 执行参数
21
- * @returns {Promise<any>}
22
- */
23
- async execute(params) {
24
- throw new Error('execute() must be implemented')
25
- }
26
-
27
- /**
28
- * 启用执行器
29
- */
30
- enable() {
31
- this._enabled = true
32
- return this
33
- }
34
-
35
- /**
36
- * 禁用执行器
37
- */
38
- disable() {
39
- this._enabled = false
40
- return this
41
- }
42
-
43
- /**
44
- * 是否启用
45
- */
46
- isEnabled() {
47
- return this._enabled
48
- }
49
-
50
- /**
51
- * 销毁
52
- */
53
- destroy() {
54
- this.removeAllListeners()
55
- }
56
- }
57
-
58
- module.exports = { ExecutorBase }
1
+ /**
2
+ * Executor 基类
3
+ * 执行器的基类,定义执行器接口
4
+ */
5
+
6
+ const { EventEmitter } = require('../utils/event-emitter')
7
+
8
+ class ExecutorBase extends EventEmitter {
9
+ /**
10
+ * @param {string} name - 执行器名称
11
+ */
12
+ constructor(name) {
13
+ super()
14
+ this.name = name
15
+ this._enabled = true
16
+ }
17
+
18
+ /**
19
+ * 执行
20
+ * @param {Object} params - 执行参数
21
+ * @returns {Promise<any>}
22
+ */
23
+ async execute(params) {
24
+ throw new Error('execute() must be implemented')
25
+ }
26
+
27
+ /**
28
+ * 启用执行器
29
+ */
30
+ enable() {
31
+ this._enabled = true
32
+ return this
33
+ }
34
+
35
+ /**
36
+ * 禁用执行器
37
+ */
38
+ disable() {
39
+ this._enabled = false
40
+ return this
41
+ }
42
+
43
+ /**
44
+ * 是否启用
45
+ */
46
+ isEnabled() {
47
+ return this._enabled
48
+ }
49
+
50
+ /**
51
+ * 销毁
52
+ */
53
+ destroy() {
54
+ this.removeAllListeners()
55
+ }
56
+ }
57
+
58
+ module.exports = { ExecutorBase }
package/test-server.js CHANGED
@@ -1,25 +1,25 @@
1
- const { serve } = require('@hono/node-server');
2
- const { Hono } = require('hono');
3
-
4
- const app = new Hono();
5
-
6
- // 简单路由
7
- app.get('/test', (c) => {
8
- console.log('Handler called');
9
- return c.json({ message: 'Hello World' });
10
- });
11
-
12
- const server = serve({
13
- fetch: app.fetch,
14
- port: 3001
15
- });
16
-
17
- server.on('request', (req) => {
18
- console.log('Request:', req.method, req.url);
19
- });
20
-
21
- server.on('error', (err) => {
22
- console.error('Server error:', err);
23
- });
24
-
25
- console.log('Server started on port 3001');
1
+ const { serve } = require('@hono/node-server');
2
+ const { Hono } = require('hono');
3
+
4
+ const app = new Hono();
5
+
6
+ // 简单路由
7
+ app.get('/test', (c) => {
8
+ console.log('Handler called');
9
+ return c.json({ message: 'Hello World' });
10
+ });
11
+
12
+ const server = serve({
13
+ fetch: app.fetch,
14
+ port: 3001
15
+ });
16
+
17
+ server.on('request', (req) => {
18
+ console.log('Request:', req.method, req.url);
19
+ });
20
+
21
+ server.on('error', (err) => {
22
+ console.error('Server error:', err);
23
+ });
24
+
25
+ console.log('Server started on port 3001');
package/test.txt CHANGED
@@ -1,3 +1,3 @@
1
- Hello from static resource test!
2
- This is a test file for verifying static resource serving.
3
- Timestamp: 2026-03-24
1
+ Hello from static resource test!
2
+ This is a test file for verifying static resource serving.
3
+ Timestamp: 2026-03-24