适配器体系

wesgine 的外设适配器(Adapter)体系提供 Cell 与外部世界的连接能力。所有适配器通过 CellSpec 声明式装配,按 Cell 物理隔离,生命周期由引擎统一管理。

概览

CellSpec 声明
    │
    ▼
Cell Boot
    │
    ├── Channel Adapters    IM 渠道(企业微信/飞书/钉钉/...)
    ├── Email Adapter       邮件收发
    ├── MCP Adapters        MCP Server 连接
    ├── Cron Adapter        定时任务
    ├── HeadlessBrowser     服务端匿名浏览器
    ├── Playwright          用户浏览器自动化
    ├── Desktop             桌面自动化 Device Agent
    ├── STT Adapter         语音转写(Whisper)
    └── Plugin Runtime      JSON-RPC 子进程插件

适配器分类

Channel(IM 渠道)

支持多平台即时通讯渠道接入:

spec := wesgine.CellSpec{
    ID: "dept-legal",
    Channels: []channel.ChannelConfig{
        {
            Platform: "wecom",
            Account:  "legal-bot",
            Config: map[string]string{
                "corp_id":  "wx123456",
                "agent_id": "1000001",
            },
            SecretRef: config.SecretRef{Source: "env", Value: "WECOM_SECRET"},
        },
        {
            Platform: "feishu",
            Account:  "legal-feishu",
            // ...
        },
    },
}

支持的平台: 企业微信、飞书、钉钉、Telegram、Discord、Slack 等。

Cell 隔离: 不同 Cell 使用不同的 bot 凭证,消息物理隔离。

Email(邮件)

spec := wesgine.CellSpec{
    ID: "dept-legal",
    Email: []email.Config{
        {
            Address:  "ai@legal.example.com",
            IMAP:     email.IMAPConfig{Host: "imap.example.com", Port: 993},
            SMTP:     email.SMTPConfig{Host: "smtp.example.com", Port: 587},
            Password: config.SecretRef{Source: "env", Value: "EMAIL_PASSWORD"},
        },
    },
}

IMAP 轮询: Cell 处于 Warm 状态时自动轮询新邮件。

MCP(Model Context Protocol)

spec := wesgine.CellSpec{
    ID: "dept-legal",
    MCPs: []mcp.ServerConfig{
        {
            Name:      "legal-mcp",
            Transport: "stdio",
            Command:   []string{"/opt/mcp/legal-server"},
        },
        {
            Name:      "crm-mcp",
            Transport: "sse",
            URL:       "http://crm-service:8080/mcp",
        },
    },
}

运行时管理:

// 动态注册/更新
cell.MCPs().Upsert(ctx, mcp.ServerConfig{Name: "new-mcp", ...})

// 连接探测
cell.MCPs().Probe(ctx, "legal-mcp")

// 连接/断开
cell.MCPs().Connect(ctx, "legal-mcp")
cell.MCPs().Disconnect(ctx, "legal-mcp")

Cron(定时任务)

spec := wesgine.CellSpec{
    ID: "dept-legal",
    Cron: []cron.JobConfig{
        {
            Name:     "weekly-report",
            Schedule: "0 9 * * 1",  // 每周一 9:00
            AgentID:  "reporter",
            Prompt:   "生成本周法务工作汇报",
        },
    },
}

INV-SEED-01:CellSpec.Cron 是出生声明,只在 Cell 首次 boot 播种进 wes_cron_jobs,此后存储是唯一权威。运行时增删改通过 cell.Cron() Handle。

HeadlessBrowser(无头浏览器)

服务端匿名抓取,使用 chromedp:

spec := wesgine.CellSpec{
    ID: "my-cell",
    HeadlessBrowser: &wesgine.HeadlessBrowserConfig{
        // CellSpec 非 nil 即启用
    },
}

Playwright(用户浏览器自动化)

服务端 subprocess + 用户浏览器扩展:

spec := wesgine.CellSpec{
    ID: "my-cell",
    Playwright: &wesgine.PlaywrightConfig{
        // 管理 Playwright MCP 子进程
    },
}

两种模式:

Desktop(桌面自动化)

客户端二进制,通过 MCP 协议连接:

spec := wesgine.CellSpec{
    ID: "my-cell",
    Desktop: &wesgine.DesktopConfig{
        Command:   "/path/to/device-agent",
        Transport: "stdio",  // 本地 stdio
        // 或 Transport: "sse", URL: "..."  // 远程 SSE
    },
}

AX-5 物理边界: Desktop Agent 二进制运行在客户端,代码由 wesgine 提供(adapter/desktop/),消费应用编译/分发。

STT(语音转写)

spec := wesgine.CellSpec{
    ID: "my-cell",
    STT: &wesgine.STTConfig{
        // CellSpec.STT 非 nil 即启用
        // 使用 Whisper 转写
    },
}

Plugin(JSON-RPC 子进程插件)

spec := wesgine.CellSpec{
    ID: "my-cell",
    Plugins: []wesgine.PluginDir{
        "/opt/plugins/my-plugin",  // 含 manifest.yaml + 可执行文件
    },
}

Boot 时 Manager 扫描目录、启动子进程、桥接 Tools 到 Cell ToolRegistry。受 CellQuotas.MaxPlugins 限制。


声明式装配

装配原则

所有适配器通过 CellSpec 声明式装配,遵循以下原则:

  1. CellSpec 是声明:描述 Cell 应该具有什么能力
  2. 装配发生在 Cell Boot:声明转化为运行时实例
  3. 播种语义:Cron/Email 是出生声明,首次 boot 后存储是权威(INV-SEED-01)
  4. 覆盖语义:Channels/MCPs 的声明就是唯一副本(无运行时存储)

两类适配器的差异

Cron / EmailChannels / MCPs
运行时存储有(wes_cron_jobs / wes_email_configs)无(spec 就是副本)
声明语义出生声明,首次播种覆盖声明,每次 boot 生效
运行时修改通过 Handle API通过 UpdateSpec
INV-SEED-01适用不适用

配额限制(INV-QUOTA-05)

每类适配器有数量上限,在唯一增长点判定:

适配器配额字段判定位置
IM ChannelsMaxIMChannelsUpdateSpec 的 append 路径
MCP ServersMaxMCPServersUpdateSpec 的 append 路径
Cron JobsMaxCronJobscron.Scheduler.Add
Email AccountsMaxEmailAccountsemail.Store.PutAccount
SkillsMaxSkillsInstalled技能安装的唯一入口

运行时生命周期

Cell 温度与适配器

温度适配器状态
Hot全部活跃
Warmgoroutine 运行(Cron tick、IMAP 轮询)
Cool停止,首请求自动 WarmUp
ColdStopped,需显式启动

外设需 Warm:有活跃 Cron 任务或 IMAP 轮询的 Cell 无法降到 Cool。

生命周期回调

Cell.Start()
    │
    ├── adapters.seedSpecOnce()     播种 Cron/Email(首次)
    ├── channel.Start()             启动 IM 渠道
    ├── email.StartPolling()        启动邮件轮询
    ├── mcp.ConnectAll()            连接所有 MCP
    ├── cron.Start()                启动定时调度器
    ├── headlessBrowser.Init()      初始化无头浏览器
    ├── playwright.Start()          启动 Playwright
    ├── desktop.Connect()           连接桌面代理
    ├── stt.Init()                  初始化语音转写
    └── plugin.Manager.Start()      启动所有插件
    │
    ▼
Cell 运行中
    │
    ▼
Cell.Stop()
    │
    ├── plugin.Manager.Drain()      关闭所有插件
    ├── cron.Stop()
    ├── email.StopPolling()
    ├── mcp.DisconnectAll()
    └── ...

自定义适配器开发

新适配器检查清单

  1. 在 adapter/<name>/ 下实现
  2. 不加 engine 级 AttachXxx() — 使用声明式装配
  3. Cell 声明 CellSpec.Xxx + cell.Xxx().Add/Remove/List
  4. 实现 Start/Stop 生命周期
  5. 实现配额检查(如需)
  6. 添加到 CellSpec 嵌入的 CellAdapterSpec

判断树

新能力 X →
├── 引擎机制? → Tier E / Hypervisor
├── 业务技能? → Tier C / Cell(Skill)
├── 用户浏览器? → CellSpec.Playwright
├── 桌面/剪贴板? → CellSpec.Desktop
├── 服务端匿名爬取? → CellSpec.HeadlessBrowser
├── 其他客户端硬件? → AX-5:消费应用自建 + cell.MCPs()
└── 新外设协议? → adapter/ + Cell 声明式装配

相关 Handle API

Handle说明
cell.Channels()IM 渠道管理
cell.Email()邮件管理
cell.MCPs()MCP Server 管理
cell.Cron()定时任务管理
cell.HeadlessBrowser()无头浏览器状态
cell.Playwright()Playwright 状态
cell.Desktop()Desktop Agent 状态
cell.Skills()技能管理(Tier C)