数据截至 (上游 commit 8d6cbee1b527)
入站:通道归一化、安全闸与会话路由
30 秒导读: 一条 WhatsApp/Telegram/Slack 消息不会直接变成 prompt。OpenClaw 让它走一条很长的漏斗——先去重防抖、再过安全闸(陌生人要配对码)、再把上百个平台字段压成一个统一的
MsgContext、再算出「这条消息属于哪个 agent 的哪个会话」、最后落盘。本章只讲这条漏斗;回复怎么发出去见 04。
1. 这是什么(零基础也能懂)
一句话定义: 入站层是 OpenClaw 的「收发室」——把十几个聊天平台各不相同的事件,翻译成同一种「一次 agent 回合」的输入。
它要解决的问题,用大白话讲是四件互相独立的事:
| 子问题 | 白话 | 不做会怎样 |
|---|---|---|
| 同一 条消息可能被送两次 | 平台重推、进程重启、多 worker 抢活 | agent 回两遍,甚至无限自答 |
| 用户会连发三条短消息 | "在吗" / "帮我看下" / "这个报错" | agent 被触发三次,前两次答非所问 |
| 陌生人也能给 bot 发私信 | 私信框对全世界开放 | 任何人都能白嫖你的模型、读你的工具 |
| 平台字段长得都不一样 | Telegram 叫 message_id,Slack 叫 ts,Matrix 叫 event_id | 每加一个通道都要重写一遍上层逻辑 |
给谁用: 通道插件作者(写一个新平台接入)和运维者(配 dmPolicy、群策略、多 agent 绑定)。
一句话直觉: 把它想成海关。飞机(平台事件)落地,先查是不是重复入境记录,再查证件(allowlist/配对码),再把所有语言的表格换成统一表格(MsgContext),最后按护照分配到哪个柜台(agent + 会话键)。任何一关都可以把你原路遣返。
2. 顶层全景(它大概怎么转)
漏斗从左到右,任一段都可能提前结束。虚线是「丢弃」出口。
平台事件 入站漏斗 产出
┌──────────┐
│ Telegram │┐
│ WhatsApp │├─▶ ① 通道插件 ② 缓冲层 ③ 安全闸
│ Slack │┘ 把原始事件 去重 / 防抖 / DM 配对码 /
│ Matrix │ 收进来 回环抑制 allowlist /
└──────────┘ │ │ 群 @ 激活
▼ ▼ │
ingest/classify 丢重复 ┄┄┄┄┄▶ 丢/发配对码 ┄┄┄┄▶
│ │
▼ ▼
④ 归一化 ──────────────────────────▶ ⑤ 会话路由
MsgContext + envelope agent:<id>:<scope>
│ │
└───────────────┬─────────────────────┘
▼
⑥ 落盘 + 派发
sessions.json / 转录(SQLite 护栏)
│
▼
一次 agent 回合(见 05)
怎么读这张图: 从左到右是时间顺序,命中任何一个「丢」就没有下文了。安全闸的「发配对码」是一个特例——它回了一条消息但不跑 agent。
各部件一句话职责:
| 部件 | 干什么 | 主要文件 |
|---|---|---|
| 通道插件 | 起长连接/webhook,产出原始事件 | src/channels/plugins/types.adapters.ts |
| turn kernel | 统一的 ingest→classify→preflight→dispatch 骨架 | src/channels/turn/run-channel-turn.ts |
| ingress queue | SQLite 持久化入站队列 + 墓碑 去重 | src/channels/message/ingress-queue.ts |
| 去重 / 防抖 | 进程内消息 id 去重、同会话短消息合并 | src/auto-reply/reply/inbound-dedupe.ts、src/auto-reply/inbound-debounce.ts |
| 安全闸 | dmPolicy / groupPolicy / 命令授权 / @ 激活 | src/channels/message-access/runtime.ts |
| 配对 | 8 位配对码 + allowFrom 存储(SQLite) | src/pairing/pairing-store.ts |
| 归一化 | 上百字段 → MsgContext | src/channels/inbound-event/context.ts |
| 路由 | 绑定匹配 → agent:<id>:<scope> | src/routing/resolve-route.ts |
| 会话存储 | sessions.json + 转录写入 | src/config/sessions/session-accessor.ts(装配)、session-accessor.sqlite-*.ts(实现) |
turn kernel 的阶段名是这条漏斗的官方骨架,日志和诊断都按它打点(ChannelTurnStage,src/channels/turn/types.ts:434):
ingest → classify → preflight → resolve → authorize → assemble → record → dispatch → finalize