跳转至

WhatsApp

状态:已可用于生产环境,通过 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 包之外分发,因此其运行时依赖保留在外部插件中。手动安装:

openclaw plugins install @openclaw/whatsapp

使用 npm:@openclaw/whatsapp 或 clawhub:@openclaw/whatsapp 强制指定来源;只有需要可复现安装时才锁定精确版本。

配对

默认私信策略是对未知发送者进行配对。

频道故障排查

跨频道诊断和修复手册。

网关配置

完整的频道配置模式和示例。

快速设置

1. 配置访问策略

{
  channels: {
    whatsapp: {
      dmPolicy: "pairing",
      allowFrom: ["+15551234567"],
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15551234567"],
    },
  },
}

2. 链接 WhatsApp(二维码)

openclaw channels login --channel whatsapp
登录仅支持二维码。在远程或无头主机上,请在开始登录前确保有一条可靠的路径将实时二维码传送到手机;终端渲染的二维码、截图或聊天附件可能在传输中过期。

针对特定账户:
openclaw channels login --channel whatsapp --account work
在登录前附加现有的/自定义认证目录:
openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-auth
openclaw channels login --channel whatsapp --account work

3. 启动网关

openclaw gateway

4. 批准第一个私信访问请求(配对模式)

打开 **设置 → 频道 → DM 访问请求**,找到 WhatsApp 账户,
然后批准该发送者。如果你更喜欢命令行:
openclaw pairing list whatsapp
openclaw pairing approve whatsapp <CODE>
DM 访问请求在 1 小时后过期;每个账户的待处理请求上限为 3 个。
此审批与用于链接账户本身的 WhatsApp 登录二维码是分开的。

Note

建议使用独立的 WhatsApp 号码(设置和元数据为此优化),但个人号码/自聊设置也完全受支持。

部署模式

专用号码(推荐)
  • 为 OpenClaw 使用独立的 WhatsApp 身份
  • 更清晰的 DM 白名单和路由边界
  • 自聊混淆的可能性更低
{
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551234567"],
    },
  },
}
个人号码回退

引导流程支持个人号码模式,并写入一份适合自聊的基线配置: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 频道/新闻通讯可以通过其原生的 @newsletter JID 作为显式出站目标,使用频道会话元数据(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):
{
  "channels": {
    "whatsapp": {
      "actions": {
        "calls": true
      }
    }
  }
}
当缺失或为 `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: {
      pluginHooks: {
        messageReceived: true,
      },
    },
  },
}

将选择加入范围限定到 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 从不自动配对出站 fromMe DM(你从关联设备自己发送的消息)
群组访问分为两层:

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。

消息传递与投递

消息规范化与上下文

入站信封与回复上下文

传入消息被包装在共享的入站信封中。带引用的回复会以以下形式附加上下文:

[Replying to <sender> id:<stanzaId>]
<quoted body or media placeholder>
[/Replying]

回复元数据(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: { sendReadReceipts: false } } }

按账户覆盖: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: { replyToMode: "first" } } }

表情回应与输入状态

表情回应级别

channels.whatsapp.reactionLevel 控制智能体使用表情回应的广泛程度:

级别 确认回应 智能体主动回应
"off" 否 否
"ack" 是 否
"minimal"(默认) 是 是,保守引导
"extensive" 是 是,鼓励引导

按账户覆盖:channels.whatsapp.accounts.<id>.reactionLevel。

{ channels: { whatsapp: { reactionLevel: "ack" } } }

确认表情回应

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: {
    statusReactions: {
      enabled: true,
    },
  },
}

注意: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 禁用。

故障排除

未链接(需要 QR)
症状:通道状态报告未链接。
openclaw channels login --channel whatsapp
openclaw channels status
已链接但断开 / 重连循环

症状:已链接账户出现反复断开或重连尝试。

空闲账户可以在正常消息超时后保持连接;看门狗仅在 WhatsApp Web 传输活动停止、套接字关闭,或应用层活动在更长的安全窗口内保持静默时才会重启(见上文运行时模型)。

修复:

openclaw channels status --probe
openclaw doctor
openclaw logs --follow
openclaw gateway status

如果在修复主机连接性和时序后循环仍然存在,请备份账户认证目录并重新链接:

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 映射(不进行深度合并)。随后提示词查找只在这一个最终映射上运行:

  1. 群组特定提示词 (groups["<groupId>"].systemPrompt):当群组条目存在且其 systemPrompt 键已定义时使用。空字符串 ("") 会屏蔽通配符提示词,并且不应用任何提示词。
  2. 群组通配符提示词 (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