foliko 1.0.7 → 1.0.9
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/.claude/settings.local.json +7 -1
- package/.env.example +23 -0
- package/README.md +29 -2
- package/SPEC.md +75 -2
- package/cli/src/ui/chat-ui.js +41 -2
- package/docs/quick-reference.md +30 -4
- package/docs/user-manual.md +158 -3
- package/{test-chat.js → examples/test-chat.js} +2 -2
- package/{test-mcp.js → examples/test-mcp.js} +2 -2
- package/{test-reload.js → examples/test-reload.js} +2 -2
- package/{test-telegram.js → examples/test-telegram.js} +1 -1
- package/{test-tg-bot.js → examples/test-tg-bot.js} +1 -1
- package/{test-tg.js → examples/test-tg.js} +1 -1
- package/{test-think.js → examples/test-think.js} +1 -1
- package/package.json +4 -1
- package/plugins/ai-plugin.js +8 -0
- package/plugins/default-plugins.js +139 -59
- package/plugins/email.js +382 -0
- package/plugins/install-plugin.js +115 -12
- package/plugins/telegram-plugin.js +9 -0
- package/plugins/tools-plugin.js +75 -0
- package/skills/vb-agent-dev/AGENTS.md +81 -10
- package/skills/vb-agent-dev/SKILL.md +149 -25
- package/src/core/framework.js +27 -0
- package/src/core/plugin-manager.js +272 -16
- /package/{test-tg-simple.js → examples/test-tg-simple.js} +0 -0
|
@@ -8,26 +8,50 @@ This file provides guidance to AI coding agents on how to create plugins for the
|
|
|
8
8
|
|
|
9
9
|
User plugins go in `.agent/plugins/` and are **automatically loaded** on bootstrap.
|
|
10
10
|
|
|
11
|
+
**Recommended: Use folder structure for complex plugins**
|
|
12
|
+
|
|
11
13
|
```
|
|
12
14
|
项目目录/
|
|
13
15
|
└── .agent/
|
|
14
16
|
└── plugins/
|
|
15
|
-
├── my-plugin
|
|
16
|
-
|
|
17
|
+
├── my-plugin/ ✅ folder structure (recommended)
|
|
18
|
+
│ ├── package.json # optional, main field specifies entry
|
|
19
|
+
│ ├── index.js # default entry point
|
|
20
|
+
│ └── node_modules/ # optional, plugin-private dependencies
|
|
21
|
+
├── another-plugin/ ✅ another folder plugin
|
|
22
|
+
│ └── index.js
|
|
23
|
+
└── legacy.js ✅ single-file still supported
|
|
17
24
|
```
|
|
18
25
|
|
|
26
|
+
**Why folder structure?**
|
|
27
|
+
- Supports `package.json` with `main` field for custom entry points
|
|
28
|
+
- Supports `node_modules` for plugin-private dependencies
|
|
29
|
+
- Better organization for complex plugins
|
|
30
|
+
|
|
19
31
|
### Built-in Plugins: `plugins/` (internal)
|
|
20
32
|
|
|
21
33
|
Built-in framework plugins are in `plugins/` directory.
|
|
22
34
|
|
|
23
35
|
## Plugin Export Formats
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
### Folder structure (recommended for `.agent/plugins/`)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
.agent/plugins/my-plugin/
|
|
41
|
+
├── package.json # optional
|
|
42
|
+
└── index.js # entry point
|
|
43
|
+
```
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
```json
|
|
46
|
+
// package.json example
|
|
47
|
+
{
|
|
48
|
+
"name": "my-plugin",
|
|
49
|
+
"main": "index.js"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
28
52
|
|
|
29
53
|
```javascript
|
|
30
|
-
// .agent/plugins/my-plugin.js
|
|
54
|
+
// .agent/plugins/my-plugin/index.js
|
|
31
55
|
module.exports = function(Plugin) {
|
|
32
56
|
return class MyPlugin extends Plugin {
|
|
33
57
|
constructor(config = {}) {
|
|
@@ -60,10 +84,22 @@ module.exports = function(Plugin) {
|
|
|
60
84
|
}
|
|
61
85
|
```
|
|
62
86
|
|
|
87
|
+
### Single-file structure (still supported)
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
// .agent/plugins/my-plugin.js
|
|
91
|
+
module.exports = function(Plugin) {
|
|
92
|
+
return class MyPlugin extends Plugin {
|
|
93
|
+
// ... same as above
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
63
98
|
**Key points:**
|
|
64
99
|
- `Plugin` base class passed automatically by system (no require needed)
|
|
65
100
|
- Factory function returns plugin class
|
|
66
101
|
- Use `require('zod')` inside methods
|
|
102
|
+
- Folder takes priority over single-file if both exist with same name
|
|
67
103
|
|
|
68
104
|
### Traditional format for `plugins/` (built-in)
|
|
69
105
|
|
|
@@ -149,14 +185,49 @@ The framework object provides:
|
|
|
149
185
|
| `framework.registerTool(tool)` | Register tool |
|
|
150
186
|
| `framework.getTools()` | Get all tools |
|
|
151
187
|
| `framework.executeTool(name, args)` | Execute tool |
|
|
188
|
+
| `framework.callTool(name, args)` | Call tool (for installing deps) |
|
|
152
189
|
| `framework.createAgent(config)` | Create Agent |
|
|
153
190
|
| `framework.reloadPlugin(name)` | Reload single plugin |
|
|
154
191
|
| `framework.reloadAllPlugins()` | Reload all plugins |
|
|
155
192
|
|
|
193
|
+
## Dependency Management
|
|
194
|
+
|
|
195
|
+
Use the `install` tool to install npm packages:
|
|
196
|
+
|
|
197
|
+
| Plugin Type | Install Location | Command |
|
|
198
|
+
|-------------|------------------|---------|
|
|
199
|
+
| **Folder plugin** | `.agent/plugins/plugin-name/node_modules/` | `install({ package: "pkg", path: ".agent/plugins/plugin-name" })` |
|
|
200
|
+
| **Single-file plugin** | `.agent/node_modules/` | `install({ package: "pkg" })` |
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
// Folder plugin - install to plugin directory
|
|
204
|
+
await framework.callTool('install', {
|
|
205
|
+
package: 'axios',
|
|
206
|
+
path: '.agent/plugins/my-plugin'
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// Single-file plugin - install to .agent
|
|
210
|
+
await framework.callTool('install', {
|
|
211
|
+
package: 'zod'
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
// Install from package.json
|
|
215
|
+
await framework.callTool('install', {
|
|
216
|
+
file: './my-plugin/package.json',
|
|
217
|
+
path: '.agent/plugins/my-plugin'
|
|
218
|
+
})
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**When encountering `Cannot find module 'xxx'` error:**
|
|
222
|
+
1. Identify plugin directory
|
|
223
|
+
2. Call `install` tool with `path` parameter for folder plugins
|
|
224
|
+
3. Reload plugin
|
|
225
|
+
4. Report status to user
|
|
226
|
+
|
|
156
227
|
## Common Mistakes
|
|
157
228
|
|
|
158
|
-
1. ❌
|
|
159
|
-
2. ❌ Forgetting `
|
|
160
|
-
3. ❌
|
|
161
|
-
4. ❌
|
|
162
|
-
5. ❌
|
|
229
|
+
1. ❌ Forgetting `install()` - tools won't be registered
|
|
230
|
+
2. ❌ Forgetting `return this` - chain calls will fail
|
|
231
|
+
3. ❌ Using `parameters` instead of `inputSchema`
|
|
232
|
+
4. ❌ Registering tools outside `install()`
|
|
233
|
+
5. ❌ Using same name for folder and file - folder takes priority, file will be ignored
|
|
@@ -18,14 +18,26 @@ VB-Agent 是一个基于插件的 Agent 框架,核心简单,通过插件扩
|
|
|
18
18
|
|
|
19
19
|
用户自定义插件放在项目根目录的 `.agent/plugins/` 下,**自动加载**,无需手动注册。
|
|
20
20
|
|
|
21
|
+
**推荐使用文件夹结构**(适合复杂插件):
|
|
22
|
+
|
|
21
23
|
```
|
|
22
24
|
项目目录/
|
|
23
25
|
└── .agent/
|
|
24
26
|
└── plugins/
|
|
25
|
-
├── my-plugin
|
|
26
|
-
|
|
27
|
+
├── my-plugin/ ✅ 文件夹结构(推荐)
|
|
28
|
+
│ ├── package.json # 可选,main 字段指定入口
|
|
29
|
+
│ ├── index.js # 默认入口
|
|
30
|
+
│ └── node_modules/ # 可选,插件私有依赖
|
|
31
|
+
├── another-plugin/ ✅ 另一个文件夹插件
|
|
32
|
+
│ └── index.js
|
|
33
|
+
└── legacy.js ✅ 单文件仍支持
|
|
27
34
|
```
|
|
28
35
|
|
|
36
|
+
**文件夹结构的优势:**
|
|
37
|
+
- 支持 `package.json` 的 `main` 字段自定义入口
|
|
38
|
+
- 支持 `node_modules` 存放插件私有依赖
|
|
39
|
+
- 更适合复杂插件的代码组织
|
|
40
|
+
|
|
29
41
|
### `plugins/` 目录(内置插件)
|
|
30
42
|
|
|
31
43
|
框架内置插件位于 `plugins/` 目录。
|
|
@@ -36,6 +48,69 @@ VB-Agent 是一个基于插件的 Agent 框架,核心简单,通过插件扩
|
|
|
36
48
|
|
|
37
49
|
**必须使用免引入写法**:
|
|
38
50
|
|
|
51
|
+
### 文件夹结构(推荐)
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
.agent/plugins/my-plugin/
|
|
55
|
+
├── package.json # 可选
|
|
56
|
+
└── index.js # 入口
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
// package.json 示例
|
|
61
|
+
{
|
|
62
|
+
"name": "my-plugin",
|
|
63
|
+
"main": "index.js"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
// .agent/plugins/my-plugin/index.js
|
|
69
|
+
module.exports = function(Plugin) {
|
|
70
|
+
return class MyPlugin extends Plugin {
|
|
71
|
+
constructor(config = {}) {
|
|
72
|
+
super()
|
|
73
|
+
this.name = 'my-plugin'
|
|
74
|
+
this.version = '1.0.0'
|
|
75
|
+
this.description = '我的工具插件'
|
|
76
|
+
this.priority = 10
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
install(framework) {
|
|
80
|
+
const { z } = require('zod')
|
|
81
|
+
framework.registerTool({
|
|
82
|
+
name: 'my_tool',
|
|
83
|
+
description: '我的工具',
|
|
84
|
+
inputSchema: z.object({
|
|
85
|
+
param: z.string().describe('参数描述')
|
|
86
|
+
}),
|
|
87
|
+
execute: async (args, framework) => {
|
|
88
|
+
return { success: true, result: args.param }
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
uninstall(framework) {
|
|
95
|
+
// 清理资源
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 单文件结构(仍支持)
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// .agent/plugins/my-plugin.js
|
|
105
|
+
module.exports = function(Plugin) {
|
|
106
|
+
return class MyPlugin extends Plugin {
|
|
107
|
+
// ... 与上面相同
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**注意**:如果文件夹和同名 `.js` 文件同时存在,**文件夹优先**。
|
|
113
|
+
|
|
39
114
|
```javascript
|
|
40
115
|
// .agent/plugins/my-plugin.js
|
|
41
116
|
module.exports = function(Plugin) {
|
|
@@ -70,8 +145,10 @@ module.exports = function(Plugin) {
|
|
|
70
145
|
}
|
|
71
146
|
```
|
|
72
147
|
**插件开发流程:**
|
|
73
|
-
1.
|
|
74
|
-
2.
|
|
148
|
+
1. **创建插件**(优先使用文件夹结构)
|
|
149
|
+
2. **安装依赖**:
|
|
150
|
+
- 文件夹插件:`install { package: "包名", path: ".agent/plugins/插件名" }`
|
|
151
|
+
- 单文件插件:`install { package: "包名" }`
|
|
75
152
|
3. **热重载**:`reload_plugins`
|
|
76
153
|
4. **检查加载状态**
|
|
77
154
|
|
|
@@ -85,27 +162,69 @@ module.exports = function(Plugin) {
|
|
|
85
162
|
|
|
86
163
|
## 依赖管理
|
|
87
164
|
|
|
88
|
-
当插件需要使用第三方 npm 包(如 `zod`、`axios`
|
|
165
|
+
当插件需要使用第三方 npm 包(如 `zod`、`axios` 等)时,根据插件类型选择安装位置:
|
|
166
|
+
|
|
167
|
+
| 插件类型 | 安装位置 | 说明 |
|
|
168
|
+
|----------|----------|------|
|
|
169
|
+
| **文件夹插件** | `.agent/plugins/插件名/node_modules/` | 插件自包含,可独立迁移 |
|
|
170
|
+
| **单文件插件** | `.agent/node_modules/` | 共享依赖 |
|
|
89
171
|
|
|
90
172
|
### 自动安装工具
|
|
91
173
|
|
|
92
|
-
框架提供了 `install`
|
|
174
|
+
框架提供了 `install` 工具,支持以下用法:
|
|
93
175
|
|
|
94
176
|
```javascript
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
// 安装缺失的包
|
|
98
|
-
const installResult = await framework.callTool('install', {
|
|
99
|
-
package: 'zod' // 或 'zod@4.3.6' 指定版本
|
|
100
|
-
})
|
|
177
|
+
// 安装到默认位置 .agent/node_modules
|
|
178
|
+
install({ package: "zod" })
|
|
101
179
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
180
|
+
// 安装到指定目录(用于文件夹插件)
|
|
181
|
+
install({ package: "axios", path: ".agent/plugins/my-plugin" })
|
|
105
182
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
183
|
+
// 从 package.json 安装所有依赖到默认位置
|
|
184
|
+
install({ file: "./package.json" })
|
|
185
|
+
|
|
186
|
+
// 从 package.json 安装所有依赖到指定目录
|
|
187
|
+
install({ file: "./my-plugin/package.json", path: ".agent/plugins/my-plugin" })
|
|
188
|
+
|
|
189
|
+
// 仅指定路径,安装该目录下的 package.json 依赖
|
|
190
|
+
install({ path: ".agent/plugins/my-plugin" })
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 文件夹插件的依赖安装示例
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// .agent/plugins/my-plugin/index.js
|
|
197
|
+
module.exports = function(Plugin) {
|
|
198
|
+
return class MyPlugin extends Plugin {
|
|
199
|
+
constructor(config = {}) {
|
|
200
|
+
super()
|
|
201
|
+
this.name = 'my-plugin'
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
install(framework) {
|
|
205
|
+
framework.registerTool({
|
|
206
|
+
name: 'fetch_data',
|
|
207
|
+
description: '获取远程数据',
|
|
208
|
+
inputSchema: z.object({
|
|
209
|
+
url: z.string().describe('API URL')
|
|
210
|
+
}),
|
|
211
|
+
execute: async (args, framework) => {
|
|
212
|
+
// 安装到插件自己的目录
|
|
213
|
+
const pluginDir = '.agent/plugins/my-plugin'
|
|
214
|
+
await framework.callTool('install', {
|
|
215
|
+
package: 'axios',
|
|
216
|
+
path: pluginDir
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
// 引入插件目录下的 node_modules
|
|
220
|
+
const axios = require(`${pluginDir}/node_modules/axios`)
|
|
221
|
+
const response = await axios.get(args.url)
|
|
222
|
+
return { success: true, data: response.data }
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
return this
|
|
226
|
+
}
|
|
227
|
+
}
|
|
109
228
|
}
|
|
110
229
|
```
|
|
111
230
|
|
|
@@ -113,15 +232,18 @@ execute: async (args, framework) => {
|
|
|
113
232
|
|
|
114
233
|
当 LLM 检测到 `Cannot find module 'xxx'` 错误时,必须:
|
|
115
234
|
|
|
116
|
-
1.
|
|
117
|
-
2.
|
|
118
|
-
3.
|
|
235
|
+
1. **确定插件目录**:如果插件是文件夹结构,安装到插件目录
|
|
236
|
+
2. **调用 `install` 工具** 安装缺失的包
|
|
237
|
+
3. **安装完成后** 重新加载插件
|
|
238
|
+
4. **返回状态** 给用户
|
|
119
239
|
|
|
120
|
-
|
|
240
|
+
示例流程(文件夹插件):
|
|
121
241
|
```
|
|
122
242
|
错误: Cannot find module 'axios'
|
|
123
243
|
↓
|
|
124
|
-
|
|
244
|
+
确定插件目录: .agent/plugins/my-plugin
|
|
245
|
+
↓
|
|
246
|
+
自动安装: install { package: "axios", path: ".agent/plugins/my-plugin" }
|
|
125
247
|
↓
|
|
126
248
|
重新加载插件
|
|
127
249
|
↓
|
|
@@ -130,7 +252,8 @@ execute: async (args, framework) => {
|
|
|
130
252
|
|
|
131
253
|
### 重要提醒
|
|
132
254
|
|
|
133
|
-
-
|
|
255
|
+
- **文件夹插件优先安装到插件目录** - 使用 `path` 参数指定插件目录
|
|
256
|
+
- **不要尝试手动 require 全局安装的包** - 必须在指定目录中安装
|
|
134
257
|
- **使用 `install` 工具自动处理** - 让 LLM 知道如何处理缺失依赖
|
|
135
258
|
- **插件加载失败时检查依赖** - 优先安装缺失的包再重试
|
|
136
259
|
|
|
@@ -223,10 +346,11 @@ install(framework) {
|
|
|
223
346
|
|
|
224
347
|
| 规则 | 说明 |
|
|
225
348
|
|------|------|
|
|
226
|
-
|
|
|
349
|
+
| **优先使用文件夹结构** | 复杂插件推荐用文件夹,便于管理依赖和代码 |
|
|
227
350
|
| **必须用 inputSchema** | `inputSchema: z.object({})`(不是 parameters!) |
|
|
228
351
|
| **必须用 zod 定义参数** | `param: z.string().describe('描述')` |
|
|
229
352
|
| **install 必须返回 this** | 确保链式调用 |
|
|
353
|
+
| **文件夹与文件重名时** | 文件夹优先,同名 `.js` 文件会被忽略 |
|
|
230
354
|
|
|
231
355
|
## 开发完成后注意事项
|
|
232
356
|
|
package/src/core/framework.js
CHANGED
|
@@ -89,6 +89,33 @@ class Framework extends EventEmitter {
|
|
|
89
89
|
return this
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* 启用插件
|
|
94
|
+
* @param {string} name - 插件名称
|
|
95
|
+
*/
|
|
96
|
+
async enablePlugin(name) {
|
|
97
|
+
await this.pluginManager.enable(name)
|
|
98
|
+
return this
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 禁用插件
|
|
103
|
+
* @param {string} name - 插件名称
|
|
104
|
+
*/
|
|
105
|
+
async disablePlugin(name) {
|
|
106
|
+
await this.pluginManager.disable(name)
|
|
107
|
+
return this
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 更新插件配置
|
|
112
|
+
* @param {string} name - 插件名称
|
|
113
|
+
* @param {Object} config - 新配置
|
|
114
|
+
*/
|
|
115
|
+
updatePluginConfig(name, config) {
|
|
116
|
+
return this.pluginManager.updatePluginConfig(name, config)
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
/**
|
|
93
120
|
* 注册工具
|
|
94
121
|
* @param {Object} tool - 工具定义
|