Files
Agent-System-Documents/docs/proposals/2026-10-01-plugin-contract-v2.md
weichenandCursor a0da588f90 Document the base extension roadmap and plugin contract v2
Why: The base must stay unmodified by downstream products, so the roadmap, compatibility window, and plugin contract need a written proposal before further forks.
Evidence: Three proposals under docs/proposals and a short pointer in the plugin development guide.
Impact: Downstream work follows extension-point requests and a published base version. Tag commands in the compat proposal are not executed.
Refs: .task/feature-base-extension-roadmap.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-01 10:34:30 +00:00

80 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 插件契约 v2
状态:**实施中(2026-10-01)**;owner:weichen;主任务:Dev 仓 `feature/base-extension-roadmap`。
撰写日期:2026-10-01。配套:[路线图](2026-10-01-base-extension-roadmap.md)、[兼容规则](2026-10-01-extension-compat-policy.md)。
## 1. 四种形态
下游按需要选一种或组合。基座对四种形态使用同一份 manifest 与同一套 fail-closed:任一资产解析失败则整包拒绝,保留上一状态。
| 形态 | 下游交付 | 基座职责 |
|---|---|---|
| 声明 | `plugin.json` + 资产目录 | 注册 tools/skills/mcp/knowledge/parsers/agents/channels/pages/commands/… |
| 进程内编译 | 下游 `main` import `pkg/extension` 并 `RegisterCompiled` | `link` + builder 模式产出**下游自己的**单二进制 |
| sidecar | 原生进程,manifest `backend.mode=sidecar` | 拉起、健康(进程存活)、停止;环境变量注入 Host API |
| 前端 ESM | `pages/*.json` 指向模块 | UI SDK 只暴露命令、SSE 与 `@ui` 组件;页面不得另起设计令牌 |
进程内编译适合要事务一致性的领域逻辑。sidecar 适合异构语言或强隔离。声明式 HTTP 工具仍然只描述调用,不携带任意代码。
## 2. manifest 增补
`apiVersion` 用 `2.0-experimental` 才强制网络白名单。字段见 `modules/core/plugin_v2.go`。
- `provides.skills`:`skills/<name>.md`,宿主写入 `<data>/skills/plugin-<id>/`。
- `provides.mcpServers`:并入小队 MCP 配置(与 `tools.mcp.servers` 合并)。
- `provides.knowledge|parsers|agents|channels|pages`:声明登记,供清单 API 与前端加载。
- `scope.tenants/projects`:空 = 全部可见。
- `backend.command`:sidecar 可执行文件(相对插件目录或 PATH)。`schemaVersion` 记入 `plugin_schema`。
密钥查找顺序:`secrets.<pluginId>.<authRef>`(按工具执行时的 `OwnerID`),再回落同名全局设置。不再在绑定期固定读 `OwnerDefault`。
## 3. Host API(sidecar 与外部进程)
监听由基座在本机拉起,令牌随进程环境变量 `AGENT_HOST_API`、`AGENT_HOST_TOKEN` 下发。
| 方法 | 路径 | 作用 |
|---|---|---|
| PUT/GET | `/host/v1/kv/{key}` | 插件隔离 KV(带 owner 与 plugin id) |
| POST | `/host/v1/audit` | 写通用审计 |
| POST | `/host/v1/commands/{id}` | 走命令总线 |
| POST | `/host/v1/llm` | 代理聊天补全;未配置模型返回 503,不静默伪造 |
| GET | `/host/v1/knowledge/search` | 混合检索(引擎在基座) |
插件故障不拖垮基座:sidecar 退出只记日志与审计,不退出主进程。
## 4. 进程内注册
```go
func init() {
extension.RegisterCompiled(extension.InProc{
ID: "rdm",
Register: func(reg extension.Registry) error {
return reg.AddSkill("rdm-note", "# …")
},
})
}
```
下游 main:
```go
import _ "agent-system-backend/pkg/extension/link"
func main() { extension.Main(extension.Options{Addr: "127.0.0.1:8787"}) }
```
## 5. 前端
`@ui` 导出 `createPluginBridge`:`execCommand` 与 `subscribeEvents`。插件页面模块默认导出 `mount(el, bridge)` / `unmount()`。宿主按 `pages[].module` 动态 `import()`。插件 TSX 与基座一样受 design-guard 约束(令牌、无私人 keyframes、无行内字号)。
## 6. 生命周期
- 启用:`POST /api/plugins/{id}/enabled`,按租户记 `plugin_grants`。
- 升级:`backend.schemaVersion` 大于已记录版本时调用宿主迁移钩子(KV 命名空间不清空;钩子由进程内扩展提供)。版本只升不降,降级拒绝装载。
- 管理面:`GET /api/plugins` 返回 manifest(含 v2 provides)以及技能/页面/渠道声明。既有设置页「插件」分组继续承担热重载。
## 7. 开发体验
- `make plugin-new NAME=<id>` 在 `examples/plugins/<id>` 生成声明式骨架。
- `examples/plugins/decl-demo`、`examples/downstream-rdm`、`examples/sidecar-demo`、`examples/page-demo` 各覆盖一种形态。
- 验收:`examples/downstream-rdm` 的测试不导入 `internal`,并由 `make test-boundaries` 卡住。