Files
Agent-System-Documents/docs/proposals/2026-10-14-svc-plugin-compose-deploy.md
weichenandCursor 2a8deac89d Add the svc plugin compose deploy proposal
Why: deploy needs a reviewed design for compiling selected plugins into the base binary before that behavior is treated as approved.
Evidence: the proposal records the throwaway compose build; implementation status stays unreviewed.
Impact: adds a pending proposal and an index link. Inclusion does not approve the design.
Refs: Dev .task/feature-svc-plugin-compose.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 02:03:03 +00:00

5.4 KiB
Raw Permalink Blame History

svc 插件组合部署(--with)方案 r1

状态:待评审。日期:2026-10-14。负责人:weichen。 任务卡:Dev .task/feature-svc-plugin-compose.md。 需求来源:部署时用交互或参数选择把哪些插件与基座编译成同一个二进制服务,并在服务中激活这些插件。

1. 范围

做:

  • 每次 svc.sh 的 agent deploy 可以选择零个或多个已登记插件。
  • 被选中的插件与 --from 指定的 Dev 基座编译成一个仍名为 agent-system 的二进制。
  • 部署后校验这些插件已注册且命令面处于启用;失败走现有 release 回退。
  • 插件清单来自 Dev 仓 plugins/registry.json,不自动发现。

不做:

  • 不做 sidecar,不把插件部署成独立服务。
  • 不让插件自带基座 pin。基座就是本次 --from 的 Dev 提交;对不上就构建失败并报原因。
  • 第一版最多一个带静态工作台(web)的插件。
  • 不删除旧的 --from rdm。它仍用 RDM 仓自己的 pins/ 构建,与 --with 互斥。

2. 步骤 0 试验结论(不留代码)

2026-10-14 在 /tmp/svc-compose-spike 复制当前 Dev 的 backend 模块,空白导入 agent-system-rdm/plugins/rdm(指向 ~/.cache/agent-system-svc/rdm-src), go mod edit -require/-replace 后执行 CGO_ENABLED=0 go build -mod=mod。

  • 构建成功。产物约 40MB,version 仍是基座的 agent-system 0.1.0-dev。
  • go version -m 显示主模块 agent-system-backend,依赖 agent-system-rdm v0.0.0。
  • 二进制内可见 rdm.project.create 与 rdm.ping。
  • 聚焦依赖(golang.org/x/*、github.com/jackc/*、modernc.org/sqlite、gopkg.in/yaml)版本无变化。
  • 新增模块只有 agent-system-rdm、github.com/kr/text、github.com/rogpeppe/go-internal。
  • 默认 -mod=readonly 会拒绝更新 go.mod/go.sum,组合构建必须使用 -mod=mod。
  • 依赖模块自己的 replace 不生效,插件按主模块(Dev 基座)解析 agent-system-backend。这正是“基座以 Dev 提交为准”所要的结果。

试验目录是一次性的,不进入任何仓库。

3. 行为

3.1 选择

  • --with rdm,foo 选择插件;--with rdm@<sha> 钉住单个插件提交;--with none 明确不带插件。
  • 标准输入是终端且没有 --with 时,按登记表给出编号勾选。默认勾选上次 svc.env 的 plugins=;第一次默认不选。回车接受默认,none 清空。
  • 非交互且没有 --with:沿用上次选择,没有则不带插件。已有脚本和 CI 的行为不变。
  • --dry-run 打印基座提交和每个插件的提交,不构建。
  • --from rdm 与 --with(除 none)互斥。--from release 不能再注入插件。

3.2 构建

  1. 物化 Dev 提交的隔离 worktree,并完成前端构建,使嵌入资源就绪。--from local 不改主检出的 go.mod:把 backend 模块复制到 runtime/.worktrees/ 再构建。
  2. 每个插件使用独立源仓缓存(~/.cache/agent-system-svc/plugin-<id>,repoEnv 可覆盖克隆地址)并物化 worktree。
  3. 在这份一次性 backend 副本里生成 cmd/agent-system/zz_plugins_gen.go(空白导入 entryPackage),并用 go mod edit 增加 require 与 replace。
  4. go build -mod=mod 产出 agent-system。基座的 version、身份和 user 等子命令保持不变。
  5. 测试可设 SVC_COMPOSE_STUB=1,跳过真实 go build,只记录插件选择。这不是生产路径。

3.3 激活与记录

  • GET /api/plugins 与 GET /api/registry 的 compiled 列表必须包含每个所选插件。
  • GET /api/commands 中该插件 commandPrefix 下至少有一条 enabled 命令。
  • 插件在而命令全部禁用时,用与设置播种相同的临时管理员 key 调用 POST /api/plugins/{id}/enabled,再复查。失败则 svc_rollback_deploy。
  • svc.env 写 plugins=id@sha,id@sha。source 形如 dev@<sha>+rdm@<sha>。release 目录的 release.json 带同一 plugins 字段。
  • update 把基座升到远端最新,并原样带上已记录的 --with,不再询问。recover 只拉起已有二进制,不重新选择。
  • 插件 id 集合变化(含从无到有、从有到无)与源种类变化一样,需要 --allow-source-switch。只改提交不需要。

3.4 工作台

登记表里 web 非空的插件,沿用现有伴生 static 服务(<name>web)。多于一个带 web 的插件直接拒绝。

4. 跨仓

  • Backend:extension.InProc 增加可选 HostOptions 与 CLI。布尔默认按“任一为 true”合并,不覆盖显式 serve 旗标。GET /api/registry 增加 compiled。
  • RDM:plugins/rdm 在 InProc 上声明 HostOptions(含关闭上传自动索引、会话卡镜像、执行原语)和 -bootstrap-admin 钩子。RDM 自己的 main.go 继续可用,旧 --from rdm 不依赖这次钩子。
  • Dev:scripts/svc.sh、plugins/registry.json、docs/svc.md、help plugins、tests/test_svc_plugins.py,并推进 backend 与 documents 的 gitlink。

5. 验收

  • 登记、选择、换源门禁、dry-run、stub 部署与激活走 tests/test_svc_plugins.py。
  • Backend 的合并与 CLI 钩子走 go test ./pkg/extension/。
  • 真实 go build 组合(Dev 提交 + RDM 提交)在步骤 0 已证实可编译。带网络的完整 svc deploy --with rdm 与 make test-lifecycle 不在本增量的 stub 套件里,未在本机再跑时标 NOT_RUN。