内置插件开发
Weave v0.1 只支持随发布物一起编译、一起测试、一起升级的内置插件。插件不是第三方扩展市场,也没有独立安装、卸载、版本选择、制品上传、WebAssembly(WASM)、原生子进程(native subprocess)、沙箱或微服务运行时。
这个边界是有意的:当前阶段优先保证平台和设备代理能够快速、可靠地发布。需要独立演进的智能体能力,后续可基于 Pi SDK 设计 Weave 项目专用的工作进程协议(worker protocol),不复用通用插件运行时。该协议是 Weave 的待设计方案,不是 Pi SDK 已提供的接口。
运行模型
| 位置 | 形式 | 注册位置 | 发布单元 |
|---|---|---|---|
| 后端 | 进程内 Go 模块,实现 pluginsdk.BackendPlugin | internal/backend/plugins/catalog/ | weave |
| 设备端 | 进程内 Go 模块,实现 agentplugin.AgentPlugin | internal/agent/plugins/catalog/ | weave-agent |
生命周期固定为:
编译期目录 → Init → Start → Health → Stop(逆序)注册顺序就是启动顺序。单个插件的 Init 或 Start 失败会被记录并隔离,其他内置插件继续启动。
后端插件
在 internal/backend/plugins/{plugin-id}/ 实现:
type Plugin struct {
host pluginsdk.HostAPI
}
func New() *Plugin { return &Plugin{} }
func (p *Plugin) Manifest() pluginsdk.PluginManifest {
return pluginsdk.PluginManifest{
ID: "example",
Version: "1.0.0",
Description: "Example builtin module",
Bus: &pluginsdk.BusCapability{
Topics: []string{"evt.plugin.example.*"},
},
Capabilities: []pluginsdk.Capability{
"bus.subscribe.evt.plugin.example.*",
},
}
}
func (p *Plugin) Init(ctx context.Context, host pluginsdk.HostAPI) error {
p.host = host
return nil
}
func (p *Plugin) Start(ctx context.Context) error { return nil }
func (p *Plugin) Stop(ctx context.Context) error { return nil }
func (p *Plugin) Health() pluginsdk.HealthReport {
return pluginsdk.HealthReport{Healthy: true}
}PluginManifest 只描述平台真正消费的内容:
- 身份:
ID、Version、Description - HostAPI 声明:
HTTP、Bus、Metrics、DB - 控制面:
Permissions、ConfigSchema、Surfaces - 配置范围:
ApplyScopes、DefaultApplyTarget - 安全能力:
Capabilities - 可选设备本地端口:
UIPort
没有运行时类型、制品地址、依赖图或资源预算字段。
HostAPI 边界
插件只通过 pluginsdk.HostAPI 使用平台能力:
HTTP():在/api/v1/plugins/{plugin-id}/下注册路由Bus():发布和订阅声明过的主题Metrics():注册插件命名空间指标DB():执行插件迁移和查询Store():使用按插件 ID 隔离的键值存储(key-value store,KV)PluginConfig()、Shadow()、Secrets()、Auditor()HTTPClient(tenantID):执行按主机能力检查的外部请求
HTTP 路由必须在 Init 注册,因为此时服务器尚未开始监听。总线订阅和后台任务放在 Start。
数据库和租户隔离
声明 DB 只代表请求数据库能力。组合根还必须把插件 ID 放进可信内置名单。
访问启用行级安全(Row-Level Security, RLS)的租户表时必须调用:
db := host.DB().WithTenant(tenantID)实现使用事务内的 SET LOCAL app.tenant_id。不得使用 SET SESSION,也不得在插件中导入 bun。
HTTP 和基于角色的访问控制(role-based access control,RBAC)
Manifest 中声明路由和权限:
HTTP: &pluginsdk.HTTPCapability{Routes: []pluginsdk.RouteDecl{
{
Pattern: "/items/{id}",
Method: "GET",
Subresource: "item",
Action: "read",
},
}},
Permissions: []pluginsdk.PluginPermissionDecl{
{
Subresource: "item",
Action: "read",
Description: "Read example items",
DefaultRoles: []string{"viewer", "operator", "tenant_admin"},
},
},在 Init 中注册:
host.HTTP().Handle("GET /items/{id}", "item", "read", handler)权限资源名为 {plugin-id}/{subresource}。管理器在启动时根据 Manifest 幂等写入权限。
注册
后端构造函数只加入 internal/backend/plugins/catalog/catalog.go。设备端构造函数只加入 internal/agent/plugins/catalog/catalog.go。不要从 cmd/weave 或 cmd/weave-agent 直接导入具体插件。
新增内置插件至少要验证:
go test ./internal/backend/plugin/... ./internal/backend/plugins/...
go test ./internal/agent/plugin/... ./internal/agent/plugins/...
go test ./...如果修改 Protobuf,再运行 make proto 和 make web-proto。