Plugin 运行时
wesgine 的 JSON-RPC 子进程 Plugin 运行时,通过 CellSpec 声明式装配外部可执行文件为 Cell 工具。
Plugin 概念
Plugin Runtime(adapter/plugin/)是一套完整的 JSON-RPC 子进程生命周期管理系统:
| 组件 | 职责 |
|---|---|
protocol.go | JSON-RPC 协议定义 |
runtime.go | 子进程运行时管理 |
bridge.go | 工具桥接(Plugin ↔ Cell ToolRegistry) |
manager.go | Plugin 集合管理 |
Plugin 通过子进程方式运行,与引擎进程隔离,通过 JSON-RPC 通信。
CellSpec.Plugins 声明
每个 Plugin 项是一个容器目录,子目录含 manifest.yaml + 可执行文件:
spec := wesgine.CellSpec{
Plugins: []string{
"/opt/plugins/data-analysis",
"/opt/plugins/code-interpreter",
},
}
目录结构:
/opt/plugins/data-analysis/
├── manifest.yaml # 声明:名称、版本、工具列表
└── bin/
└── data-analysis # 可执行文件(JSON-RPC server)
manifest.yaml 示例
name: data-analysis
version: "1.0.0"
description: "数据分析工具集"
command: "./bin/data-analysis"
tools:
- name: analyze_csv
description: "分析 CSV 数据文件"
parameters:
type: object
properties:
file_path:
type: string
description: "CSV 文件路径"
query:
type: string
description: "分析查询"
Plugin 生命周期
Boot 阶段
Cell.Start()
→ Manager.Boot()
→ 扫描 CellSpec.Plugins 目录
→ 解析每个子目录的 manifest.yaml
→ 启动子进程(JSON-RPC server)
→ 桥接 Tools 到 Cell ToolRegistry
运行时
Model 调用 Plugin 工具
→ Cell ToolRegistry 查找
→ Bridge 转发 JSON-RPC 请求
→ 子进程执行
→ Bridge 转发 JSON-RPC 响应
→ 返回给 Model
Drain 阶段
Cell.Stop()
→ Manager.Drain()
→ 向每个子进程发送 Shutdown RPC
→ 等待优雅退出
→ 超时后强制终止
Plugin 配额
CellQuotas.MaxPlugins 的行为与其他外设配额不同:
| 特性 | 说明 |
|---|---|
| 判定时机 | Boot 期截断 |
| 运行期写门 | 没有(不是写点拒绝) |
| 超限行为 | 截断目录列表,多余的 Plugin 不启动 |
// Boot 时
plugins := scanPluginDirs(spec.Plugins)
if len(plugins) > quotas.MaxPlugins {
plugins = plugins[:quotas.MaxPlugins]
// 日志警告截断
}
这与 Cron/Email/MCP/Channel 的"写点拒绝"模式不同——Plugin 没有运行期增删 API。
PluginPolicy — 签名验证
Plugin 可通过 ed25519 签名验证确保安全:
spec := wesgine.CellSpec{
PluginPolicy: &wesgine.PluginPolicy{
RequireSignature: true,
TrustedKeys: []string{
"ed25519:abc123...",
},
},
}
| 策略 | 行为 |
|---|---|
RequireSignature: false | 接受所有 Plugin |
RequireSignature: true | 只接受签名匹配 TrustedKeys 的 Plugin |
Plugin 与 Tool 关系
Plugin 暴露的工具自动注册到 Cell ToolRegistry:
Cell ToolRegistry
├── 引擎内置工具 (read, write, exec, grep, ...)
├── SDK 注册工具 (cell.Tools().Register)
├── MCP 代理工具 (cell.MCPs().Upsert)
├── Plugin 工具 (adapter/plugin/) ← Plugin 工具在这里
├── Adapter 派生工具 (kb/email/cron/...)
└── Per-run 临时工具 (RunParams.Tools)
Cell 之间物理不可见——Cell A 的 Plugin 工具不会出现在 Cell B 的工具列表中。
JSON-RPC 协议
Plugin 子进程实现标准 JSON-RPC 2.0 协议:
请求
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "analyze_csv",
"arguments": {
"file_path": "/data/report.csv",
"query": "计算每月销售总额"
}
}
}
响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "分析结果:1月销售额 100万..."
}
]
}
}
生命周期方法
| 方法 | 说明 |
|---|---|
initialize | 初始化 Plugin |
tools/list | 列出工具 |
tools/call | 调用工具 |
shutdown | 优雅关闭 |
Plugin vs MCP
Plugin 与 MCP 都是扩展 Cell 工具集的方式,但定位不同:
| 特性 | Plugin | MCP |
|---|---|---|
| 进程管理 | 引擎管理子进程生命周期 | 外部独立进程 |
| 传输 | JSON-RPC over stdio | stdio / SSE / HTTP |
| 配置 | CellSpec.Plugins | cell.MCPs().Upsert |
| 运行时增删 | ❌ Boot 期固定 | ✅ 运行时动态 |
| 签名验证 | ✅ PluginPolicy | ❌ |
| 适用场景 | 紧密集成的扩展 | 松耦合的外部服务 |
开发 Plugin
1. 创建目录
mkdir -p my-plugin/bin
2. 编写 manifest.yaml
name: my-plugin
version: "1.0.0"
description: "我的自定义插件"
command: "./bin/my-plugin"
tools:
- name: my_tool
description: "工具描述"
parameters:
type: object
properties:
input:
type: string
3. 实现 JSON-RPC Server
使用任何语言实现 stdin/stdout JSON-RPC 2.0 服务。
4. 配置到 CellSpec
spec.Plugins = []string{"/path/to/my-plugin"}
最佳实践
- Plugin 用于紧密集成:需要引擎管理生命周期的场景
- MCP 用于松耦合:外部服务或运行时动态增删
- 注意 MaxPlugins:超限的 Plugin 会被截断不启动
- 签名验证:生产环境建议启用 PluginPolicy
- 优雅关闭:实现
shutdown方法,释放资源