IM 渠道
Cell 内的 IM 通道集成,支持企业微信、飞书、钉钉等平台的消息收发。
渠道概念
每个 Cell 拥有独立的 IM 渠道集合。渠道是 per-cell 装配——不同部门 Cell 连接各自的企业微信 bot、飞书应用等。
支持的平台:
| 平台 | 类型 |
|---|---|
| 企业微信 | wecom |
| 飞书 | feishu |
| 钉钉 | dingtalk |
| 自定义 Webhook | webhook |
Cell 之间的 IM 消息物理隔离——不同 credentials 不可能收到对方消息。
CellSpec.Channels 声明
CellSpec.Channels 是出生声明(INV-SEED-01):
- 只在 Cell 首次 boot 播种
- 此后存储是唯一权威
- 声明不再被读
spec := wesgine.CellSpec{
Channels: []channel.Config{
{
Platform: "wecom",
CorpID: "wxLegal...",
AgentID: 1000001,
SecretRef: config.SecretRef{Source: "env", Name: "WECOM_SECRET"},
},
},
}
注意:Channels 与 MCPs 没有运行时存储——spec 就是那唯一一份副本,故 spec 权威。这与 Cron/Email 不同(它们有运行时存储)。
Channel API
渠道管理
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /channels | 渠道列表 |
POST | /channels | 注册/更新渠道 |
DELETE | /channels/{platform}/{account} | 删除渠道 |
绑定管理
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /channels/bindings | 绑定列表 |
PUT | /channels/bindings | 替换绑定 |
消息操作
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /channels/preflight | 预检验证 |
POST | /channels/send | 发送消息 |
GET | /channels/events | SSE 事件流 |
SDK 调用
// 列出
channels, err := cell.Channels().List(ctx)
// 注册
err := cell.Channels().Register(ctx, channel.Config{
Platform: "feishu",
AppID: "cli_xxx",
// ...
})
// 发送
err := cell.Channels().Send(ctx, channel.SendRequest{
Platform: "wecom",
Target: "user123",
Content: "你好,这是 AI 助手的消息",
})
// SSE 事件流
events := cell.Channels().Events(ctx)
Webhook 路由
IM 平台的回调消息通过 Webhook 路由到对应 Cell:
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /webhook/wecom | 企业微信回调 |
POST | /webhook/feishu | 飞书回调 |
POST | /webhook/dingtalk | 钉钉回调 |
多租户路由
多租户部署时,每个部门 Cell 需要独立的 callback URL:
POST /cells/dept-legal/webhook/wecom
POST /cells/dept-audit/webhook/feishu
POST /cells/dept-sales/webhook/dingtalk
Gateway 从 URL path 提取 cellID,分发到对应 Cell 处理。
渠道绑定
渠道绑定将 Agent 与 IM 平台账号关联:
cell.Channels().SetBindings(ctx, []channel.Binding{
{
Platform: "wecom",
AccountID: "bot-legal",
AgentID: "agent-legal",
},
})
收到消息后,Gateway 根据绑定关系确定由哪个 Agent 处理。
配额(INV-QUOTA-05)
MaxIMChannels 遵循外设配额统一规则:
| 规则 | 说明 |
|---|---|
| 唯一增长点 | Channel 注册是唯一能让集合变大的地方 |
| 整体替换幂等 | UpdateSpec 的 Channels = append(nil, patch...) 对 cap 幂等 |
| 收缩不需要 cap | 删除渠道不触发配额检查 |
| 覆盖已有名字 delta=0 | upsert 是编辑手势,卡在上限的 Cell 必须还能轮换凭据 |
// 配额检查在唯一增长点
err := quotaFn(currentCount, delta) // delta=1 新增, delta=0 覆盖
渠道事件流
GET /channels/events 返回 SSE 事件流,包含渠道相关的实时事件:
- 收到新消息
- 消息发送结果
- 连接状态变化
const eventSource = new EventSource('/cells/main/channels/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Channel event:', data.type, data.payload);
};
消费方集成示例
企业微信
# 在 CellSpec 或 TenantBootstrap 中声明
channels:
- platform: wecom
corp_id: "wx1234567890"
agent_id: 1000001
secret_ref: "env:WECOM_SECRET"
token_ref: "env:WECOM_TOKEN"
aes_key_ref: "env:WECOM_AES_KEY"
飞书
channels:
- platform: feishu
app_id: "cli_xxx"
app_secret_ref: "env:FEISHU_APP_SECRET"
verification_token_ref: "env:FEISHU_VERIFY_TOKEN"
最佳实践
- 每部门独立 callback URL:包含 cellID 避免歧义
- 凭据使用 SecretRef:不在配置文件中明文存放
- 绑定明确:每个 IM 账号绑定一个 Agent
- 事件流监听:通过 SSE 实时感知消息收发状态