连接器依赖——Requires,fail-closed 解析

更新于 · 在 sijie.xyz 查看原条目 ↗

父节点:connector

这是 capabilities 支柱与 connector 支柱之间的正式接口——设计上就是 fail-closed 且不关心消费者身份的。插件清单声明 Requires: ["calendar", "smtp"]——这些是应用内依赖提供方的名字,每一个都由某个连接器类别背书。capreg/depresolver.go 就是这个注册表;解析发生在装配阶段:只要有一个所需依赖不处于 Connected 状态,该能力就会在全局范围内被隐藏(fail-closed)——这是发现层面的降级,不是运行时报错。提供方只对外暴露两样东西:一个 Connected 谓词和一个调用句柄——绝不暴露凭证(这是 connector-plugins 划出的边界)。

不关心消费者身份这个设计决定,让整套机制变得通用且双向:同一套按名字解析依赖的逻辑,同时服务于 agent、平台自身功能,以及未来的消费者(IM 网关、job-loop),并且在两个方向上都成立(主动执行动作和被动同步)。

flowchart LR
  M["plugin manifest
Requires: [calendar]"] --> DR["capreg depresolver
(named providers)"]
  DR --> Q{"provider Connected?"}
  Q -- yes --> H["inject call handle
(never creds)"]
  Q -- no --> X["capability HIDDEN
(fail-closed)"]

类视图

classDiagram
  class DepProvider {
    <<interface>>
    +Name() string
    +Connected(ctx, ownerID) (bool, error)
  }
  class DepRegistry {
    -providers map[string]DepProvider
    +Register(p)
    +Lookup(name) (DepProvider, bool)
    +Unknown(names) []string
    +AllConnected(ctx, ownerID, names) (bool, error)
  }
  class RequiresDeps {
    <<interface>>
    +Requires() []string
  }
  class funcProvider {
    -name string
    -connected func(ctx, ownerID) (bool, error)
    built by NamedProvider(name, fn)
  }
  DepProvider <|.. funcProvider
  DepRegistry o-- DepProvider : by name
  RequiresDeps ..> DepRegistry : AllConnected at assembly

精确说明:DepProvider 只回答 Connected——它是一个谓词,不是调用句柄。消费者实际使用的句柄是类别代理(connector-plugins 里的 CalendarProxy/MailProxy),是另外单独装配的;依赖机制只负责决定这个能力是否会被暴露出来(AllConnected 为 false → 隐藏,fail-closed)。

自 2026-08-20 起(a9c446937)在此之上又多了一个谓词:OpProvider.CanPerform(ctx, ownerID, op)(depresolver.go:151),由 NamedOpProvider 构造。一个能力可以要求一个操作(calendar:events.insert),而不只是一个连接,于是只读授权会藏起"预订会议"却不藏"空闲时段"。到 36789537d 为止,组合根把 calendar 注册为 NamedOpProvider(背后是 ConnectorSlots.CanPerform),把 smtp 注册为普通的 NamedProvider(cmd/server/axisconn/register.go:207-214)——这两个名字就是全部的 provider 表。

相关笔记