Slack
OpenCorvus 通过唯一 channel runtime 提供的首选远程 channel。
Slack 是 OpenCorvus 的首选远程 channel,也是 channel-runtime 对接最成熟的平台。托管运行时和独立 channel-runtime package 共用同一个规范适配器。
状态
生产可用。README.md 已列为 Available。
快速配置
1. 创建 Slack App
在 api.slack.com/apps 创建一个 App,必须开启 Socket Mode(代码在 packages/channel-runtime/src/adapters/slack.ts 强制 socketMode: true)。
2. Scopes
Bot Token Scopes(最小集):
| Scope | 用途 |
|---|---|
chat:write | 回复消息 |
chat:write.public | 在未加入的频道回复(可选) |
files:write | 上传截图 / 附件 |
im:history / channels:history | 读取 DM / 频道消息 |
reactions:write | Ack emoji(可选) |
App-Level Token Scope:
| Scope | 用途 |
|---|---|
connections:write | Socket Mode 连接 |
3. 订阅事件
Event Subscriptions 中订阅:
message.channelsmessage.im
(.env.example 说明)
4. 环境变量
export SLACK_BOT_TOKEN=xoxb-... # Bot User OAuth Tokenexport SLACK_APP_TOKEN=xapp-... # App-Level Tokenexport SLACK_SIGNING_SECRET=... # Signing Secret(Socket Mode 下可选)# 可选:allowlist,逗号分隔的 Slack User IDexport SLACK_ALLOWED_USER_IDS=U01234567,U098765435. 启动
启动唯一 channel runtime:
bun run --cwd packages/channel-runtime dev会同时启动所有配置了 env 的 channel。
托管产品路径中,在 OpenCorvus 配置 Slack 后启动 opencorvus serve;
project bootstrap 会通过托管 channel-runtime supervisor 启动同一个适配器。
Token 模型
三种 token 职责分明:
| Token | 前缀 | 职责 |
|---|---|---|
| Bot Token | xoxb- | 代表 bot 的身份调 API(发消息、上传文件) |
| App Token | xapp- | 建立 Socket Mode WebSocket |
| Signing Secret | 无前缀 | 验证 HTTP webhook 签名(Socket Mode 下不用) |
消息流
用户在 Slack 频道/DM 发消息 ↓ Socket Mode WebSocketSlackAdapter.app.message() [packages/channel-runtime/src/adapters/slack.ts] ↓过滤:忽略 bot_id、非支持 subtype、去重 ↓ IncomingMessage { platform: "slack", channel: C..., thread_ts: 123.456 }ChannelRuntime.handleMessage() [packages/channel-runtime/src/core.ts] ↓SessionCoordinator.get("slack:C...:123") ↓ 新 thread → 新 session;同 thread → 复用client.session.prompt(sessionId, message)Thread 语义:Slack 的 thread_ts 唯一标识一条对话;同 thread 内的后续消息会作为 follow-up 注入同一任务循环。
回复流
OpenCorvus 后端 SSE 推事件 ↓handleEvent(event) [packages/channel-runtime/src/core.ts] ↓message.updated → 文本缓冲 → safeSend()assistant completed → 结算当前直接 prompt 请求part.updated(image) → uploadImage() 调 files.uploadV2permission.asked → 若开启自动回复则直接 reply;否则 @ 用户等人工回帖时:所有回复都会带上原 thread_ts,保持在同一 thread 内。
权限交互
在 Slack 里审批权限:
允许一次: allow / 同意 / yes始终允许: always / allow always拒绝: reject / no / 拒绝关键字识别由 channel-runtime 在通用层处理(不是 Slack 特有)。
Ack 反应
Slack 适配器会在接收到消息后立刻给原消息加一个 emoji 反应作为”已收到”的回执(避免用户以为消息没送达)。可通过 config 关闭。
语音消息
Slack 的 file_share 子类型(语音消息)会被下载并走已配置的 STT pipeline(STT_PROVIDER 指定的单一提供者),转写文本后当作普通消息处理。
故障排查
问题:not_in_channel 或 channel_not_found
检查:bot 是否被邀请进入该频道;DM 场景是否开启 Messages Tab。
问题:消息送达延迟高 检查:是否用了 Socket Mode;HTTP Request URL 模式在国内网络下延迟高。
问题:同一消息被处理两次 检查:去重事实由 OpenCorvus channel ingress 的稳定消息 ID 持久化;若看到重复,检查是否有两个托管或独立 channel-runtime owner 使用了同一组 Slack app 凭据。
问题:权限审批消息无人回复
检查:默认权限模式是 Full access。如果项目显式选择了 Ask me,请从操作员界面审批,或把项目切换为 Full access。