状态:已可用于生产环境,通过 WhatsApp Web(Baileys)运行。网关拥有已链接的会话;没有独立的 Twilio WhatsApp 频道。
设置¶
安装¶
openclaw onboard 和 openclaw channels add --channel whatsapp 会在你首次选择该插件时提示安装;如果插件缺失,openclaw channels login --channel whatsapp 会提供相同的安装流程。开发版检出使用本地插件路径;稳定版/测试版先从 npm 安装 @openclaw/whatsapp,仅当 npm 目标不可用时才回退到其声明的 ClawHub 包。WhatsApp 运行时随核心 OpenClaw npm 包之外分发,因此其运行时依赖保留在外部插件中。手动安装:
使用 npm:@openclaw/whatsapp 或 clawhub:@openclaw/whatsapp 强制指定来源;只有需要可复现安装时才锁定精确版本。
默认私信策略是对未知发送者进行配对。
跨频道诊断和修复手册。
完整的频道配置模式和示例。
快速设置¶
1. 配置访问策略
{
channels: {
whatsapp: {
dmPolicy: "pairing",
allowFrom: ["+15551234567"],
groupPolicy: "allowlist",
groupAllowFrom: ["+15551234567"],
},
},
}
2. 链接 WhatsApp(二维码)
登录仅支持二维码。在远程或无头主机上,请在开始登录前确保有一条可靠的路径将实时二维码传送到手机;终端渲染的二维码、截图或聊天附件可能在传输中过期。
针对特定账户:
在登录前附加现有的/自定义认证目录:
openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-auth
openclaw channels login --channel whatsapp --account work
3. 启动网关
4. 批准第一个私信访问请求(配对模式)
打开 **设置 → 频道 → DM 访问请求**,找到 WhatsApp 账户,
然后批准该发送者。如果你更喜欢命令行:
DM 访问请求在 1 小时后过期;每个账户的待处理请求上限为 3 个。
此审批与用于链接账户本身的 WhatsApp 登录二维码是分开的。
Note
建议使用独立的 WhatsApp 号码(设置和元数据为此优化),但个人号码/自聊设置也完全受支持。
部署模式¶
专用号码(推荐)
- 为 OpenClaw 使用独立的 WhatsApp 身份
- 更清晰的 DM 白名单和路由边界
- 自聊混淆的可能性更低
个人号码回退
引导流程支持个人号码模式,并写入一份适合自聊的基线配置:dmPolicy: "allowlist"、allowFrom 包含你自己的号码、selfChatMode: true。准入和安全规则请参阅个人号码与自聊行为。
运行时模型¶
- 网关拥有 WhatsApp 套接字和重连循环。
- 看门狗独立跟踪两个信号:原始 WhatsApp Web 传输活动和应用消息活动。静止但已连接的会话不会仅仅因为最近没有消息到达而重启;只有当传输帧在固定内部窗口(不可由用户配置)内停止到达,或应用消息超过正常消息超时时间的 4 倍仍然静默时,它才强制重连。在最近活跃的会话重连后,第一个窗口使用较短的正常消息超时时间,而不是 4 倍窗口。OpenClaw 可以自动回复 Baileys 在重连早期送达的离线消息,受入站消息 ID 去重生命周期限制;初始启动保留较短的过期历史保护。
- 出站发送需要目标账户存在活动的 WhatsApp 监听器;否则发送快速失败。
- 群组发送会为
@+<digits>和@<digits>令牌附加原生提及元数据(在文本和媒体说明中),当令牌与当前参与者元数据匹配时,包括支持 LID 的群组。 - 状态和广播聊天(
@status、@broadcast)会被忽略。 - 私聊使用 DM 会话规则(
session.dmScope;默认main将私聊合并到代理主会话)。使用默认的session.groupScope: "per-group"时,群组会话按 JID 隔离(agent:<agentId>:whatsapp:group:<jid>)。 - WhatsApp 频道/新闻通讯可以通过其原生的
@newsletterJID 作为显式出站目标,使用频道会话元数据(agent:<agentId>:whatsapp:channel:<jid>)而不是 DM 语义。 - WhatsApp Web 传输遵循网关主机上的标准代理环境变量(
HTTPS_PROXY、HTTP_PROXY、NO_PROXY、小写变体)。优先使用主机级代理配置,而非每频道设置。 - 媒体上传使用相同的代理环境,
NO_PROXY针对每个实际上传主机独立于 WebSocket 目标进行求值。 - 媒体代理 URL 必须使用 HTTP 或 HTTPS。无效的媒体代理设置会使上传失败,但不会阻止登录或文本消息。
使用 MeowCaller 呼叫当前请求者(实验性)¶
该插件可以在 WhatsApp 发起的代理轮次中暴露 whatsapp_call。它使用 MeowCaller 向当前授权的请求者拨打 WhatsApp 语音电话,并在对方接听后播放 OpenClaw TTS 消息。该工具没有目标号码参数,因此提示词无法重定向呼叫。默认禁用。
Warning
MeowCaller 是实验性的,没有标记版本,并且使用单独配对的 whatsmeow 链接设备会话——它无法复用插件的 Baileys 凭据。配对会向同一个 WhatsApp 账户添加另一个链接设备;请使用 OpenClaw 所用的身份扫码。个人号码/自聊模式无法呼叫自身;请使用专用的 OpenClaw 号码来呼叫你的个人号码。
1. 启用实验性调用
在 WhatsApp 渠道配置中添加 `actions.calls: true`。更改遵循[热重载](../gateway/configuration/hot-reload.md):
当缺失或为 `false` 时,OpenClaw 不会暴露 `whatsapp_call` 工具。
2. 安装已审查的 MeowCaller CLI
适配器期望在网关主机的 `PATH` 上存在 `meowcaller` 可执行文件。在 [MeowCaller PR #7](https://github.com/purpshell/meowcaller/pull/7) 合并之前,请构建已审查的分支:
git clone --branch feat/send-only-notify https://github.com/steipete/meowcaller.git
cd meowcaller
git checkout 752050471fc2bf7a8cdfbf7dbd3cd4e865d85d3f
mkdir -p "$HOME/.local/bin"
go build -o "$HOME/.local/bin/meowcaller" ./cmd/meowcaller
确保 `$HOME/.local/bin` 位于网关服务的 `PATH` 中;如果你更改了其服务环境,请重启 Gateway。此修订版包含明确的 `pair` 和仅发送的 `notify` 命令;`notify` 不会打开麦克风、扬声器、视频设备或诊断捕获。不要替换上游示例 CLI 的 `play` 命令。
3. 配对 MeowCaller 关联设备
让 WhatsApp 代理检查呼叫设置(`whatsapp_call` 状态操作会报告特定于账户的状态目录和配对命令)。对于默认账户:
state_dir="$HOME/.openclaw/credentials/whatsapp-calls/default"
mkdir -p "$state_dir"
chmod 700 "$state_dir"
meowcaller pair --store "$state_dir/wa-voip.db"
交互式运行此命令,从 **WhatsApp > 关联设备** 扫描二维码,并等待 `MeowCaller linked device ready`。保持 `wa-voip.db` 私有——它是 MeowCaller 会话。非默认账户会从状态操作获得自己的存储路径;在 Windows 上,运行其 PowerShell 命令。
4. 配置 TTS 并从 WhatsApp 发起呼叫
配置一个支持电话的 TTS 提供商,然后发送类似 Call me and say the build finished. 的请求。该工具会从可信的入站上下文中解析发送者,合成一个临时私有 WAV 文件,在有限的呼叫窗口内运行 MeowCaller,然后删除音频文件。OpenClaw 会显式传递账户的存储,在接听/播放/挂断后等待零退出状态,并将超时或非零退出视为工具调用失败。
限制:仅支持一对一外呼音频呼叫,不允许任意目标号码,不与聊天连接共享认证,不允许从个人号码/自聊天模式发起自呼叫,合成音频上限为 60 秒,除 MeowCaller 的接听/播放/挂断完成外,没有手机侧可听性回执,并且 OpenClaw 会在有界的 115-175 秒窗口后停止伴随进程(覆盖 MeowCaller 的连接、接听、播放和关闭阶段)。
审批提示¶
WhatsApp 可以将 exec 和插件审批提示渲染为 👍/👎 反应,由顶层审批转发配置控制:
{
approvals: {
exec: {
enabled: true,
mode: "session",
},
plugin: {
enabled: true,
mode: "targets",
targets: [{ channel: "whatsapp", to: "+15551234567" }],
},
},
}
approvals.exec 和 approvals.plugin 相互独立;启用 WhatsApp 作为渠道仅链接传输层,除非匹配的审批类别已启用并路由到该渠道,否则不会发送任何内容。会话模式仅对源自 WhatsApp 的审批提供原生表情审批。目标模式使用共享转发管道处理显式目标,并且不会创建单独的审批人 DM 扇出。
WhatsApp 审批反应需要在 allowFrom 中指定显式审批人(或 "*")。defaultTo 设置普通默认消息目标,而不是审批人列表。手动 /approve 命令在审批解析之前仍会经过正常的 WhatsApp 发送者授权路径。
问题反应¶
对于包含一个非机密、单选题且有一到四个选项的 ask_user 提示,WhatsApp 会在选项标签旁显示 1️⃣ 到 4️⃣。使用匹配的数字对已送达的提示进行反应即可回答。OpenClaw 通过 Gateway 将数字映射到规范选项;过期或重复的点击会被忽略。多问题、多选和自由文本提示仍仅限文本回复。正常的 WhatsApp DM/群组准入规则会授权进行反应的发送者。
插件钩子与隐私¶
入站 WhatsApp 消息可能包含个人内容、电话号码、群组标识符、发送者名称和会话关联字段。除非你选择加入,否则 WhatsApp 不会将入站 message_received 钩子负载广播给插件:
将选择加入范围限定到 channels.whatsapp.accounts.<id>.pluginHooks.messageReceived 下的一个账户。仅为你信任处理入站 WhatsApp 内容和标识符的插件启用此功能。
访问控制¶
访问控制与激活¶
channels.whatsapp.dmPolicy:
| 值 | 行为 |
|---|---|
pairing(默认) |
未知发送者请求配对;所有者批准 |
allowlist |
仅 allowFrom 发送者被准入 |
open |
要求 allowFrom 包含 "*" |
disabled |
阻止所有 DM |
allowFrom 接受 E.164 格式号码(内部会进行规范化)。它仅是 DM 发送者访问控制列表——它不会限制到群组 JID 或 @newsletter 频道 JID 的显式外发发送。
多账户覆盖:channels.whatsapp.accounts.<id>.dmPolicy(以及 .allowFrom)对该账户优先于渠道级默认值。
运行时说明:
- 配对会持久化在渠道允许存储中,并与配置的
allowFrom合并 - 计划自动化和心跳接收者回退使用显式投递目标或配置的
allowFrom;DM 配对批准不是隐式 cron/心跳接收者 - 除非
selfChatMode: false或dmPolicy: "disabled",否则允许相同号码的自 DM;参见自聊天行为 - OpenClaw 从不自动配对出站
fromMeDM(你从关联设备自己发送的消息)
群组访问分为两层:
1. **群组成员白名单** (`channels.whatsapp.groups`):如果省略 `groups`,则所有群组都有资格;如果存在,则作为群组白名单(`"*"` 允许所有)。
2. **群组发送者策略** (`channels.whatsapp.groupPolicy` + `groupAllowFrom`):`open` 绕过发送者白名单,`allowlist` 要求匹配 `groupAllowFrom`(或 `*`),`disabled` 阻止所有群组入站消息。
如果未设置 `groupAllowFrom`,发送者检查会回退到 `allowFrom`(当 `allowFrom` 有条目时)。发送者白名单在提及/回复激活之前进行评估。
如果完全不存在 `channels.whatsapp` 块,运行时将回退到 `groupPolicy: "allowlist"`(并记录警告日志),即使 `channels.defaults.groupPolicy` 被设置为其他值。
Note
入站群组处理在设置时会使用 channels.whatsapp.accounts.<id>.groups。否则,命名账户会继承 channels.whatsapp.accounts.default.groups,然后继承 channels.whatsapp.groups;默认账户使用自己的映射或根映射。群组映射作为整体互相替换,而不是合并单个群组条目。显式为空的映射({})也会替换继承的映射。
群组回复默认需要提及。提及检测包括:
- 对机器人身份的显式 WhatsApp 提及
- 提及正则模式(
agents.entries.*.groupChat.mentionPatterns,回退到messages.groupChat.mentionPatterns);当两者均未设置时,模式从路由代理的identity.name和identity.emoji派生 - 已授权群组消息的入站语音备忘录转写
- 隐式回复机器人检测(回复发送者与机器人身份匹配)
在所选代理或全局级别显式设置 mentionPatterns: [] 会抑制源自身份的文本模式。原生提及和回复机器人检测仍然保持独立。
要处理群组中所有允许的消息,请在已经提供账户群组策略的映射中设置 groups["<group-id>"].requireMention: false:channels.whatsapp.groups 或有效的 channels.whatsapp.accounts.<id>.groups 映射,包括继承的 accounts.default.groups。保留所有现有的通配符和每群组设置。如果你有意创建账户特定映射而不是编辑继承的映射,请先完整复制继承的映射,然后只更改目标群组的 requireMention。如果之前没有应用任何映射,请包含 "*": {} 以保持其他聊天被允许;否则保留现有限制。已保存的会话激活模式优先于该配置默认值;使用 /activation always 针对该会话。
安全性:引用/回复仅满足提及门控——它不授予发送者授权。使用 groupPolicy: "allowlist" 时,未列入白名单的发送者即使回复了白名单用户的消息,也仍然会被阻止。
会话级激活命令:/activation mention 或 /activation always。这会更新会话状态(而非全局配置),并且受所有者门控。
配置的 ACP 绑定¶
WhatsApp 通过顶层 bindings[] 支持持久 ACP 绑定:
{
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "whatsapp",
accountId: "work",
peer: { kind: "direct", id: "+15555550123" },
},
},
{
type: "acp",
agentId: "codex",
match: {
channel: "whatsapp",
accountId: "work",
peer: { kind: "group", id: "120363424282127706@g.us" },
},
},
],
}
直接聊天匹配 E.164 号码;群组匹配 WhatsApp 群组 JID。群组白名单、发送者策略以及提及/激活门控在 OpenClaw 确保绑定 ACP 会话存在之前运行。匹配的绑定拥有该路由——广播群组不会将该轮次扇出到普通的 WhatsApp 会话。
个人号码与自我聊天行为¶
channels.whatsapp.selfChatMode 控制同号码 DM 准入和自我聊天保护。你可以在频道级别设置它,或者使用 channels.whatsapp.accounts.<id>.selfChatMode 按账户覆盖它。
true或未设置: 来自已关联号码发送给其自身的 DM 会被接受为代理输入,即使该号码不在allowFrom中。dmPolicy: "disabled"仍然会阻止所有 DM。false: 源自自身的 DM 会被忽略,即使你的号码在allowFrom中。其他入站 DM 和群组消息仍遵循各自的访问策略;此设置不会使账户变为仅出站。
隐式的自身号码允许仅适用于 DM,不适用于群组白名单。
自我聊天保护由 true 启用,由 false 禁用。当该设置未设置时,如果配置的 allowFrom 中出现已关联的自身号码,OpenClaw 会启用这些保护。这些保护会跳过已读回执,抑制原生自我提及触发器,并在未配置响应前缀时提供身份回复前缀。
因此,发送到你自己号码的存活探测在 selfChatMode 未设置或为 true 时可能会成为代理输入。如果你想排除这些源自自身的 DM,请设置 selfChatMode: false。
消息传递与投递¶
消息规范化与上下文¶
入站信封与回复上下文
传入消息被包装在共享的入站信封中。带引用的回复会以以下形式附加上下文:
回复元数据(ReplyToId、ReplyToBody、ReplyToSender、发送者 JID/E.164)在可用时会被填充。如果被引用的目标是可下载的媒体,OpenClaw 会通过正常的入站媒体存储保存它,并暴露 MediaPath/MediaType,以便代理可以直接检查它,而不是只看到 <media:image>。
媒体占位符与位置/联系人提取
仅包含媒体的消息会被规范化为占位符:<media:image>、<media:video>、<media:audio>、<media:document>、<media:sticker>。
授权群组语音留言在提及门控前进行转写,当正文仅为 <media:audio> 时,在语音留言中提及机器人即可触发回复。如果转写文本仍未提及机器人,则会作为待处理群组历史记录保留,而非原始占位符。
位置正文渲染为简洁的坐标文本。位置标签/备注以及联系人/vCard 详情渲染为带围栏的不可信元数据,而非内联提示文本。
待处理群组历史注入
未处理的群组消息会缓冲并在机器人最终被触发时作为上下文注入。
- 默认限制:
50 - 配置:
channels.whatsapp.historyLimit,回退到messages.groupChat.historyLimit 0表示禁用
注入标记:[Chat messages since your last reply - for context] 和 [Current message - respond to this]。
已读回执
默认对已接受的入站消息启用。全局禁用:
按账户覆盖:channels.whatsapp.accounts.<id>.sendReadReceipts。自聊保护会在全局启用时也跳过已读回执(参见 自聊行为)。
投递、分块与媒体¶
文本分块
- 默认分块限制:
channels.whatsapp.textChunkLimit = 4000 - Markdown 在分块发送前完成转换,跨消息边界保留样式,并将 WhatsApp 格式标记计入限制
channels.whatsapp.streaming.chunkMode = "length" | "newline";newline优先选择段落边界(空行),然后回退到按长度安全分块
出站媒体行为
- 支持图片、视频、音频(PTT 语音留言)和文档负载
- 音频以 Baileys
audio负载发送并携带ptt: true,渲染为按下即说的语音留言;audioAsVoice保留在回复负载上,因此 TTS 语音留言输出无论提供方的源格式如何都会走此路径 - 原生 Ogg/Opus 音频以
audio/ogg; codecs=opus发送;其他所有格式(包括 Microsoft Edge TTS MP3/WebM 输出)在 PTT 投递前都会使用ffmpeg转码为 48 kHz 单声道 Ogg/Opus /tts latest将最新一条助手回复作为一条语音留言发送,并抑制同一回复的重复发送;/tts chat on|off|default控制当前聊天的自动 TTS- 视频发送中的
gifPlayback: true支持动画 GIF 播放 forceDocument/asDocument将出站图片、GIF 和视频路由到 Baileys 文档负载,以避免 WhatsApp 的媒体压缩,并保留解析后的文件名和 MIME 类型- 字幕应用于多条目媒体回复中的第一个媒体项,但 PTT 语音留言除外:音频先无字幕发送,然后字幕作为单独文本消息发送(WhatsApp 客户端对语音留言字幕的渲染不一致)
- 当后续带字幕的回复重复出现待处理附件时,只有 WhatsApp 接受的附件会替换其待处理副本;未匹配的附件仍排队投递
- 媒体源可以是 HTTP(S)、
file://或本地路径
媒体大小限制与回退行为
- 入站保存上限和出站发送上限:
channels.whatsapp.mediaMaxMb(默认50) - 按账户覆盖:
channels.whatsapp.accounts.<id>.mediaMaxMb - 图片会自动优化(调整大小/质量扫描)以适应限制,除非
forceDocument/asDocument请求文档投递 - 媒体发送失败时,首个条目的回退会发送文本警告,而不是静默丢弃响应
回复引用¶
channels.whatsapp.replyToMode 控制原生回复引用(出站回复以可见方式引用入站消息):
| 值 | 行为 |
|---|---|
"off"(默认) |
从不引用;作为普通消息发送 |
"first" |
仅引用第一条出站回复分块 |
"all" |
引用每条出站回复分块 |
"batched" |
引用排队批处理的回复;即时回复保持不引用 |
如果原始消息文本和媒体详情不再缓存,OpenClaw 会将回复作为普通消息发送。回复正文得以保留,但其与原始消息的视觉关联会丢失。
按账户覆盖:channels.whatsapp.accounts.<id>.replyToMode。
表情回应与输入状态¶
表情回应级别¶
channels.whatsapp.reactionLevel 控制智能体使用表情回应的广泛程度:
| 级别 | 确认回应 | 智能体主动回应 |
|---|---|---|
"off" |
否 | 否 |
"ack" |
是 | 否 |
"minimal"(默认) |
是 | 是,保守引导 |
"extensive" |
是 | 是,鼓励引导 |
按账户覆盖:channels.whatsapp.accounts.<id>.reactionLevel。
确认表情回应¶
messages.ackReaction 在入站消息接收时立即发送表情回应,由当前 WhatsApp 账户的 reactionLevel 门控(当为 "off" 时抑制)。messages.ackReactionScope 选择私聊、群组或两者:
{
messages: {
ackReaction: "👀",
ackReactionScope: "group-mentions", // all | direct | group-all | group-mentions | off
},
}
注意:表情回应在入站消息被接受后立即发送(回复之前);省略 messages.ackReaction 或将其设为 "" 表示不发送确认。失败会被记录,但不会阻止回复投递。默认范围为 "group-mentions";使用 "all" 表示私聊和所有符合条件的群组。在激活方式为 always 的群组中,"group-mentions" 会对每条消息都发送确认,而非仅针对提及触发的轮次,因为激活方式取代了提及检查。
生命周期状态反应¶
设置 messages.statusReactions.enabled: true,让 WhatsApp 在回合期间替换确认反应,而不是保留静态的回执表情,并在排队、思考、工具活动、压缩、完成和错误等状态之间循环:
注意:messages.ackReactionScope 仍然控制直接消息和群组的适用性;排队状态使用与普通确认反应相同的有效表情。每条消息只有一个机器人反应槽位,因此生命周期更新会就地替换当前反应,并在最终的完成/错误状态后恢复确认反应。
活动回合输入状态¶
对于允许输入指示的已接纳自动回合,WhatsApp 会在代理执行开始时发送 composing 在线状态更新,并在回合保持活动期间刷新它。当运行完成时,包括终止失败或取消,刷新会停止。当回复分发器报告空闲时,或如果该信号未到达,则在短暂的安全超时后,控制器会封存并清理。对于现有输入和抑制策略禁用输入指示的回合,不会启动此活动。
输入在线状态是临时性的、尽力而为的活动反馈。它不是持久化消息、送达回执,也不保证每个 WhatsApp 客户端都会显示持续活动;重连和客户端行为可能导致指示器消失。生命周期状态反应仍然是上述描述的、看起来持久的可选状态界面。
多账户与凭据¶
账户选择与默认值
账户 ID 来自 channels.whatsapp.accounts。如果存在 default,默认账户选择为 default,否则为第一个已配置的账户 ID(按字母顺序排序)。账户 ID 在内部会规范化以便查找。
命名账户按以下顺序解析共享设置:该账户、accounts.default,然后是通道根。这包括 dmPolicy 和 groupPolicy:省略时继承,而显式值优先。未配置策略时,DM 使用 pairing,群组使用 allowlist。默认账户的 authDir、enabled、name 和 selfChatMode 不会与命名账户共享。
凭据路径与旧版兼容性
- 当前认证路径:
~/.openclaw/credentials/whatsapp/<accountId>/creds.json(备份:creds.json.bak) - 位于
~/.openclaw/credentials/的旧版默认认证仍会被识别/迁移,用于默认账户流程
登出行为
openclaw channels logout --channel whatsapp [--account <id>] 会清除该账户的 WhatsApp 认证状态。当网关可达时,登出会先停止该账户的实时监听器,因此关联会话会在下次重启前停止接收消息。openclaw channels remove --channel whatsapp 也会在禁用或删除账户配置前停止实时监听器。
在旧版认证目录中,oauth.json 会被保留,而 Baileys 认证文件会被删除。
工具、操作与配置写入¶
- 代理工具支持包括 WhatsApp 反应操作(
react)。 - 操作门控:
channels.whatsapp.actions.reactions、channels.whatsapp.actions.polls(现有操作默认为true)、channels.whatsapp.actions.calls(默认为false,见上文 MeowCaller)。 - 通道发起的配置写入默认启用;通过
channels.whatsapp.configWrites: false禁用。
故障排除¶
已链接但断开 / 重连循环
症状:已链接账户出现反复断开或重连尝试。
空闲账户可以在正常消息超时后保持连接;看门狗仅在 WhatsApp Web 传输活动停止、套接字关闭,或应用层活动在更长的安全窗口内保持静默时才会重启(见上文运行时模型)。
修复:
如果在修复主机连接性和时序后循环仍然存在,请备份账户认证目录并重新链接:
cp -a ~/.openclaw/credentials/whatsapp/<accountId> \
~/.openclaw/credentials/whatsapp/<accountId>.bak
openclaw channels logout --channel whatsapp --account <accountId>
openclaw channels login --channel whatsapp --account <accountId>
如果 ~/.openclaw/logs/whatsapp-health.log 显示 Gateway inactive,但 openclaw gateway status 和 openclaw channels status --probe 均显示健康,请运行 openclaw doctor。在 Linux 上,doctor 会警告调用已弃用的 ~/.openclaw/bin/ensure-whatsapp.sh 脚本的旧版 crontab 条目;使用 crontab -e 删除这些条目 — cron 可能缺少 systemd 用户总线环境,并导致该旧脚本错误报告网关健康状态。
代理后 QR 登录超时
症状:openclaw channels login --channel whatsapp 在显示可用 QR 之前失败,并出现 status=408 Request Time-out 或 TLS 套接字断开。
WhatsApp Web 登录使用网关主机的标准代理环境变量(HTTPS_PROXY、HTTP_PROXY、小写变体、NO_PROXY)。请验证网关进程继承了代理环境变量,并且 NO_PROXY 不匹配 mmg.whatsapp.net。
发送时无活动监听器
当目标账户不存在活动的网关监听器时,出站发送会快速失败。请确认网关正在运行且账户已链接。
回复出现在转录中但未出现在 WhatsApp 中
转录行记录代理生成的内容;WhatsApp 送达会单独检查。OpenClaw 只有在 Baileys 为至少一个可见文本或媒体发送返回出站消息 ID 后,才将自动回复视为已发送。
确认反应是独立的回复前回执 — 成功的反应并不能证明后续的文本/媒体回复已被接受。请检查网关日志中的 auto-reply delivery failed 或 auto-reply was not accepted by WhatsApp provider。
群组消息意外被忽略
按此顺序检查:groupPolicy、groupAllowFrom/allowFrom、groups 白名单条目、提及门控(requireMention + 提及模式),以及 openclaw.json 中的重复键(JSON5 中后面的条目会覆盖前面的条目——每个作用域只保留一个 groupPolicy)。
如果存在 channels.whatsapp.groups,WhatsApp 仍然可以观察到其他群组的消息,但 OpenClaw 会在会话路由之前丢弃这些消息。将群组 JID 添加到 channels.whatsapp.groups,或添加 groups["*"] 以允许所有群组,同时仍由 groupPolicy/groupAllowFrom 控制发送者授权。
Bun 运行时警告
Node 仍然是主要且推荐的 Gateway 运行时。使用 WAL 重置安全的 node:sqlite 的 Bun 1.4+ 构建,作为显式选择加入项受支持;doctor 仅将不受支持的 Bun 服务迁移到 Node。
系统提示词¶
WhatsApp 通过 groups 和 direct 映射,为群组和私聊提供 Telegram 风格的系统提示词。
群组消息的解析:首先确定有效的 groups 映射——只要账户定义了自己的 groups 键,它就会完全替换根级 groups 映射(不进行深度合并)。随后提示词查找只在这一个最终映射上运行:
- 群组特定提示词 (
groups["<groupId>"].systemPrompt):当群组条目存在且其systemPrompt键已定义时使用。空字符串 ("") 会屏蔽通配符提示词,并且不应用任何提示词。 - 群组通配符提示词 (
groups["*"].systemPrompt):当特定群组条目不存在,或存在但没有systemPrompt键时使用。
私聊消息的解析针对 direct 映射和 direct["*"] 遵循完全相同的模式。
Note
dms 仍然是轻量级的按私聊历史记录覆盖桶(dms.<id>.historyLimit)。提示词覆盖则位于 direct 之下。
Note
这种「账户替换根级」的提示词解析行为是一种简单的浅层覆盖:账户中的任何 groups/direct 键,包括显式的空对象,都会替换根级映射。这与上文所述的群组成员资格白名单检查不同,后者对意外为空的 groups: {} 设有单账户安全网。
与 Telegram 的区别: Telegram 在多账户配置中对 groups 也采用相同的整体映射账户覆盖方式,但单个账户的空 groups: {} 会回退到根级 groups,作为迁移安全网。Telegram 的 direct 映射还具有独立的私聊话题语义。在 WhatsApp 中——或者对于多个 Telegram 账户中的某一个账户——当该账户不应继承根级群组默认值时,请使用显式的空 groups: {}。
重要行为:
channels.whatsapp.groups既是按群组的配置映射,也是聊天级别的群组白名单。在根级或账户级作用域中,groups["*"]表示该作用域内「所有群组都被允许」。- 仅当你本来就希望该作用域允许所有群组时,才添加通配符
systemPrompt。若只想让固定的一组群组 ID 具备准入资格,请在每个显式白名单条目上重复该提示词,而不要使用groups["*"]。 - 群组准入和发送者授权是两项独立的检查。
groups["*"]扩大了可进入群组处理流程的群组范围;它并不会授权这些群组中的每个发送者——这仍然由groupPolicy/groupAllowFrom控制。 channels.whatsapp.direct对私聊没有等效的副作用:direct["*"]仅在私聊已经由dmPolicy加上allowFrom或配对存储规则准入之后,才提供默认配置。
示例:
{
channels: {
whatsapp: {
groups: {
// Use only if all groups should be admitted at the root scope.
// Applies to all accounts that do not define their own groups map.
"*": { systemPrompt: "Default prompt for all groups." },
},
direct: {
// Applies to all accounts that do not define their own direct map.
"*": { systemPrompt: "Default prompt for all direct chats." },
},
accounts: {
work: {
groups: {
// This account defines its own groups, so root groups are fully
// replaced. To keep a wildcard, define "*" explicitly here too.
"120363406415684625@g.us": {
requireMention: false,
systemPrompt: "Focus on project management.",
},
// Use only if all groups should be admitted in this account.
"*": { systemPrompt: "Default prompt for work groups." },
},
direct: {
// This account defines its own direct map, so root direct entries are
// fully replaced. To keep a wildcard, define "*" explicitly here too.
"+15551234567": { systemPrompt: "Prompt for a specific work direct chat." },
"*": { systemPrompt: "Default prompt for work direct chats." },
},
},
},
},
},
}
配置参考指引¶
主要参考:配置参考 - WhatsApp
| 区域 | 字段 |
|---|---|
| 访问控制 | dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups |
| 消息投递 | textChunkLimit, streaming.chunkMode, mediaMaxMb, sendReadReceipts, reactionLevel |
| 多账户 | accounts.<id>.enabled, accounts.<id>.authDir, 以及其他按账户的覆盖项 |
| 操作 | configWrites, enabled |
| 入站批处理 | messages.inbound.debounceMs, messages.inbound.byChannel.whatsapp |
| 回执 | messages.ackReaction, messages.ackReactionScope |
| 区域 | 字段 |
|---|---|
| 会话行为 | session.dmScope, historyLimit, dmHistoryLimit, dms.<id>.historyLimit |
| 提示词 | groups.<id>.systemPrompt, groups["*"].systemPrompt, direct.<id>.systemPrompt, direct["*"].systemPrompt |
相关¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw