npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dingxiang-me/openclaw-wechat

v2.3.0

Published

WeCom (企业微信) channel plugin for OpenClaw (自建应用回调 + 发送 API).

Readme

OpenClaw-Wechat 企业微信插件

中文 README | English README

OpenClaw-Wechat 是一个面向 OpenClaw 的企业微信渠道插件,支持两种接入方式:

  • Agent 模式:企业微信自建应用(XML 回调,经典模式)
  • Bot 模式:企业微信智能机器人 API 模式(JSON 回调,原生 stream)
  • Webhook 目标出站:将消息主动投递到企业微信群 Webhook 或命名 Webhook 目标

适用于“个人微信扫码进入企业微信应用对话”、“企业内员工问答助手”、“多账户多业务线消息分流”等场景。

目录

可靠投递更新(v2.2.0)

这版重点不在接入元信息,而是把 WeCom 回复链路补成“可感知、可补发、可诊断”的可靠投递。

这版新增了什么

| 项目 | 结果 | |---|---| | 可靠投递状态 | /status 新增 24h 窗口 / 主动发送额度 / Pending Reply 摘要 | | Pending Reply | 最终回复投递失败后自动入队,支持定时重试和下次入站补发 | | Pending Reply 持久化 | 可选落盘,gateway 重启后继续补发未送达的最终回复 | | 配额感知 | 统一区分 窗口过期 / 额度不足 / 传输失败 / 目标无效 | | 推理展示策略 | delivery.reasoning 可控制 <think> 内容分离显示、合并到最终回复或隐藏 | | Selfcheck 摘要 | wecom:selfcheck / wecom:agent:selfcheck / wecom:bot:selfcheck 增加 reliable-delivery 摘要 | | 群策略诊断 | /status 与 selfcheck 会显示当前群规则来源、准入模式以及白名单是否生效 | | 最终回复格式 | delivery.replyFormat 支持 auto / text / markdown,会按链路选择纯文本或 markdown 能力 | | 媒体指令 | 模型最终回复支持 MEDIA: / FILE: 指令,自动回传图片/文件并隐藏指令行 | | Bot/Agent 收口 | Bot fallback 与 Agent 最终回复统一纳入可靠投递跟踪 | | 长连接日志降噪 | 正常的 connect / opened / subscribed 继续保持 debug,默认日志更安静 |

这版对接入有什么实际影响

  • 现在能直接看出当前会话是否仍在 24h 回复窗口内,以及是否存在待补发的最终回复。
  • Bot / Agent 不再只是超时兜底,而是会把失败结果分类并进入 Pending Reply 重试。
  • selfcheck 会明确告诉你可靠投递追踪是否打开、是否持久化,以及当前推理展示模式。
  • 群聊策略不再只能靠日志反推,/status 和 selfcheck 会直接说明当前命中的群规则来源与白名单是否真的在限制触发。
  • Bot 长连接默认日志仍然更安静,排障时再开 debug 看正常心跳和订阅细节。

当前推荐的接入顺序

现在 package / manifest / runtime channel meta 都会暴露同一套 quickstart metadata,便于 installer、quickstart、doctor 和后续集成入口读取同一份推荐模式、starter config 和 setup checklist。

  1. 先选一个主入口:
    • Bot 长连接:适合最快跑通对话
    • Agent:适合需要主动发送、菜单、自建应用能力
  2. 再决定私聊准入:
    • open:直接可聊
    • allowlist:仅显式白名单
    • pairing:首次私聊先审批
  3. 最后再加增强项:
    • bindings
    • dynamicAgent
    • wecom_doc

Quickstart 命令

推荐入口:

npx -y @dingxiang-me/openclaw-wecom-cli install

如果你更想留在仓库内执行同一套流程:

npm run wecom:quickstart -- --mode bot_long_connection
npm run wecom:doctor -- --json

如果你想走交互式向导:

npm run wecom:quickstart -- --wizard

如果你已经准备好了 WECOM_* / WECOM_BOT_* 环境变量,也可以使用兼容性的 env-backed 初始化路径:

export WECOM_BOT_LONG_CONNECTION_BOT_ID=your-bot-id
export WECOM_BOT_LONG_CONNECTION_SECRET=your-bot-secret
openclaw channels add --channel wecom --use-env

这条 channels add --use-env 路径不需要任何 OpenClaw core 补丁,但它只适合 env-backed 初始化。
日常文档、排障和安装说明都默认以 installer / quickstart / doctor 为主路径;如果你需要完整接入和迁移闭环,仍然优先用 npx -y @dingxiang-me/openclaw-wecom-cli install

常见用法:

# 默认推荐模式:Bot 长连接
npm run wecom:quickstart -- --json

# 交互式选择 mode / dm / 群策略,并决定是否直接写入配置
npm run wecom:quickstart -- --wizard

# 把推荐 selfcheck 也串起来跑;如仍有占位项,默认会先阻止执行
npm run wecom:quickstart -- --run-checks

# 即使还没填完占位项,也强制执行推荐检查
npm run wecom:quickstart -- --run-checks --force-checks

# 把修复用的 configPatch 和 .env 模板直接写到目录里
npm run wecom:quickstart -- --run-checks --repair-dir ./.wecom-repair

# 直接把生成的 repair configPatch 合并进目标 openclaw.json
npm run wecom:quickstart -- --run-checks --apply-repair

# 先预览将要修改的字段,再确认是否真的应用 repair patch
npm run wecom:quickstart -- --run-checks --confirm-repair

# 单独盘点当前配置里的 legacy / mixed-layout 问题,并生成迁移 patch
npm run wecom:migrate -- --json

# 一次性聚合安装状态、迁移状态、自检、长连接探针和回调矩阵
npm run wecom:doctor -- --json

# 跑本地黑盒 onboarding E2E:install -> doctor -> fix -> rerun
npm run test:e2e:local

# 检查 root 包、installer CLI、manifest 和 npm pack 产物是否一致
npm run test:release

# 生成 sales 账号的 Agent 回调模板
npm run wecom:quickstart -- --mode agent_callback --account sales --dm-mode allowlist

# 直接带一份群白名单模板(值班群/运营群)
npm run wecom:quickstart -- --mode hybrid --group-profile allowlist_template --group-chat-id wr-ops-room --group-allow ops_lead,oncall_user

# 直接合并写入 openclaw.json,并自动备份原文件
npm run wecom:quickstart -- --mode hybrid --write

--group-profile 可选值有:inheritmention_onlyopen_directallowlist_templatedeny
默认行为只打印 starter config 和检查清单;只有显式传 --write 才会写文件。 --wizard 会把当前 CLI 参数当作默认值,然后逐步提问,最后再确认是否写入 openclaw.json--run-checks 会按当前 mode 的推荐命令执行自检;若 starter config 里还有占位项,默认会阻止执行,除非显式传 --force-checks--apply-repair 会把 postcheck.repairArtifacts.configPatch 直接 merge 到 --config 指向的配置文件,并自动备份原文件。 --confirm-repair 会先打印将要修改的字段,再询问是否真正执行 --apply-repair;交互提示走 stderr,不会污染 --json 的机器输出。 npm run wecom:migrate -- --json 不再生成 starter config,只做当前安装 / 迁移状态盘点,适合排查 legacy_config / mixed_layout / stale_packagenpm run wecom:migrate -- --jsonnpm run wecom:doctor -- --json 现在还会给出 migrationSource,直接区分 official-wecom / sunnoy-wecom / legacy-openclaw-wechat / mixed-sourcenpm run wecom:doctor -- --json 会把 migration + selfcheck + agent/bot e2e + longconn probe + callback matrix 聚合成一份报告;可以加 --skip-network 先只看本地安装 / 迁移问题。 npm run wecom:doctor -- --fix --skip-network --json 会先应用当前可落盘的本地 fix patch(例如 migration patch、plugins.allow/entries),再用修正后的配置重跑 doctor。 npm run wecom:doctor -- --confirm-fix --skip-network --json 会先预览将要修改的字段,再确认是否真正写回。 npm run wecom:quickstart -- --json 现在也会带 sourcePlaybook,把当前来源推荐的检查顺序、占位项提示和默认 repair 策略一起返回。 npx -y @dingxiang-me/openclaw-wecom-cli install 会先尝试执行 openclaw plugins install @dingxiang-me/openclaw-wechat,再写入 starter config,并可选继续跑本地 doctor。 npm run test:e2e:local 会黑盒验证 install -> doctor -> fix -> rerun 这条本地闭环,不依赖真实企微网络。 npm run test:release 会校验 root 包、installer CLI、manifest、运行时版本常量和 npm pack --dry-run 产物,适合作为发版前门禁。 如果当前配置更像官方插件 / sunnoy / 旧版 OpenClaw-Wechat,安装器会在 --json 输出里直接给出 migration.guide、来源说明、legacy 字段路径和回滚命令。 如果你想人工确认是否附带执行 doctor --fix,可以加 --confirm-doctor-fix;要强制不附带 --fix,可加 --no-doctor-fix,自动确认则用 --yes。 安装器的 --json 现在还会直接输出 actions,把来源审阅、迁移 patch、回滚和重跑 doctor 这些步骤结构化暴露出来。 如果你没有显式传 --mode,安装器还会按来源和现有能力自动选择 bot_long_connection / agent_callback / hybrid,并在 sourceProfile 里说明为什么这么选。 sourceProfile 现在还会给出来源专属 checkOrderrepairDefaults。例如官方 / legacy 来源默认允许自动附带 doctor --fix,而 sunnoy / mixed-source 来源默认只给修复建议,不会直接附带 --fix。 仓库现在也自带两条 GitHub Actions 门禁:Onboarding E2E 跑本地安装闭环,Release Check 跑版本/打包一致性;tag 发布会走独立 release workflow,顺序发布插件包和 installer CLI。

--json 输出会额外给出:

  • placeholders:还有哪些模板占位项没替换
  • setupChecklist:下一步应该执行的管理台配置和自检命令
  • actions:可被 CLI / UI 直接消费的结构化 setup flow
  • installState / migrationState:当前是 fresh、legacy_config、stale_package、mixed_layout 还是 ready
  • migrationSource / migrationSourceSummary:当前更接近官方插件、sunnoy 配置、legacy-openclaw-wechat,还是 mixed-source
  • fix:doctor --fix 是否已提示、确认、落盘,以及真实 changedPaths
  • sourcePlaybook:quickstart 基于当前来源生成的推荐检查顺序、占位提示和 repair 默认值
  • sourceProfile.checkOrder / sourceProfile.repairDefaults:当前来源推荐的检查顺序,以及 installer 默认采用的修复策略
  • warnings:当前 mode / group profile 下仍需确认的风险点
  • postcheck:推荐 selfcheck 的执行结果、阻塞原因或汇总状态
  • postcheck.remediation:把失败检查翻译成可执行的修复建议
  • postcheck.repairArtifacts:自动生成最小 configPatch.env 模板,便于直接修复当前检查暴露的问题
  • postcheck.repairPlan:按项列出 repair patch 的配置变更、env 变更和会写出的文件
  • migration.configPatch / migration.envTemplate:当前 legacy 配置可直接迁移到的新布局建议

如果再加 --repair-dir <path>,quickstart 还会把这些修复产物直接落盘成:

  • wecom.config-patch.json
  • wecom.account-patch.json
  • wecom.env.template
  • README.txt

如果加的是 --apply-repair,则会在输出中额外看到 repairApply,说明 repair patch 是否已实际写入目标配置。 如果加的是 --confirm-repairrepairApply 里还会带 prompted/confirmed,方便区分“用户拒绝”与“自动执行”;真正写入的字段会出现在 repairApply.changedPaths

5 分钟极速上手

适合“先跑起来再细调”的场景。

Step 1. 安装插件

最快入口:

npx -y @dingxiang-me/openclaw-wecom-cli install

它会复用仓库内的 quickstart / migrate / doctor 能力,把“安装插件 + 写 starter config + 跑本地体检”串成一次执行。

如果你只想单独安装插件包:

openclaw plugins install @dingxiang-me/openclaw-wechat

最低建议版本:2.3.0。如果 openclaw.json 里的 plugins.installs.openclaw-wechat 仍显示 1.7.x,请先升级或重装;旧包不会正确注册 wecom channel 元数据,也不包含当前这套接入、迁移与可靠投递能力。

如果你是在本地开发或要直接跑仓库源码,再用下面这套:

git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
cd OpenClaw-Wechat
npm install

Step 2. 在 OpenClaw 里启用插件

如果你是通过 openclaw plugins install 安装,在 ~/.openclaw/openclaw.json 增加:

{
  "plugins": {
    "enabled": true,
    "allow": ["openclaw-wechat"],
    "entries": {
      "openclaw-wechat": {
        "enabled": true
      }
    }
  }
}

如果你是源码路径加载,再使用下面这版(多一个 load.paths):

{
  "plugins": {
    "enabled": true,
    "allow": ["openclaw-wechat"],
    "load": {
      "paths": ["/path/to/OpenClaw-Wechat"]
    },
    "entries": {
      "openclaw-wechat": {
        "enabled": true
      }
    }
  }
}

Step 3. 选择一种模式配置

| 模式 | 回调路径 | 企业微信侧类型 | 最少需要的配置 | |---|---|---|---| | Agent(自建应用) | /wecom/callback | 自建应用 API 接收 | corpId/corpSecret/agentId/callbackToken/callbackAesKey | | Bot(智能机器人) | /wecom/bot/callback | 智能机器人 API 模式 | bot.enabled/token/encodingAesKey | | Bot(智能机器人长连接) | 无需公网回调 | 智能机器人 长连接模式 | bot.enabled/bot.longConnection.enabled/bot.longConnection.botId/bot.longConnection.secret |

Agent 模式补充(重要):在企业微信自建应用后台请配置可信 IP,把 OpenClaw 网关实际出网 IP 加入白名单。否则可能出现“能收到消息但不回复”。

如果你希望私聊先审批,再开放会话,可以直接加:

{
  "channels": {
    "wecom": {
      "dm": {
        "mode": "pairing"
      }
    }
  }
}

Step 4. 重启并自检

openclaw gateway restart
openclaw gateway status
npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts

现在自检输出会先给出两行摘要:

  • readiness: 当前是否能收、能回、能发
  • routing: 当前是否启用 bindingsdynamicAgent

Step 5. 发一条消息验证

| 验证项 | 预期结果 | |---|---| | 文本消息 | 机器人返回文本 | | 图片消息(Bot) | 不再提示“图片接收失败”,可识别图像内容 | | openclaw gateway status | RPC probe: ok 且 WeCom 状态正常 |

功能概览

核心能力

| 能力 | 状态 | 说明 | |---|---|---| | 企业微信入站消息处理 | ✅ | 文本、图片、语音、链接、文件/视频(Agent + Bot) | | AI 自动回复 | ✅ | 接入 OpenClaw Runtime,自动路由 Agent | | Bot 原生 stream 协议 | ✅ | msgtype=stream 刷新与增量回包 | | Bot 长连接(WebSocket) | ✅ | 原生 aibot_subscribe / aibot_msg_callback / aibot_respond_msg | | Bot 卡片回包 | ✅ | 支持 markdown/template_card,失败自动降级文本 | | 多账户 | ✅ | channels.wecom.accounts.<id> | | 发送者授权控制 | ✅ | allowFrom + 账户级覆盖 | | 私聊策略(DM) | ✅ | dm.mode=open/allowlist/pairing/deny + 账户级覆盖 | | 事件欢迎语(enter_agent) | ✅ | events.enterAgentWelcome* 可配置 | | 命令白名单 | ✅ | /help /status /clear /new 等 | | 群聊触发策略 | ✅ | 支持 direct/mention/keyword 三种模式 | | 企业微信文档工具 | ✅ | 内置 wecom_doc 工具:创建/重命名/分享/权限管理/收集表/表格属性 | | 文本防抖合并 | ✅ | 窗口期内多条消息合并投递 | | 异步补发(超时后) | ✅ | transcript 轮询补发最终回复 | | 观测统计 | ✅ | 入站/回包/错误计数 + 最近失败样本(/status) | | WeCom 出站代理 | ✅ | outboundProxy / WECOM_PROXY |

媒体能力

| 能力 | 状态 | 说明 | |---|---|---| | 图片识别(入站) | ✅ | 支持 URL 下载、类型识别、必要时解密后识别 | | 图片发送(出站) | ✅ | Agent 模式支持 | | 语音/视频/文件发送(出站) | ✅ | 自动判型上传后发送(语音支持 AMR/SILK) | | 语音转写(本地) | ✅ | 企业微信 Recognition 优先,缺失时回退本地 whisper | | Bot 模式媒体回传 | ✅ | active_stream 优先 msg_item(image);失败自动降级媒体链接,response_url/Webhook Bot 继续兜底 | | Bot 思考过程展示 | ✅ | 识别 <think>/<thinking>/<thought>,映射到原生 thinking_content 折叠区 | | Bot 文件入站 | ✅ | 支持 msgtype=file 下载并注入会话上下文 | | Bot 引用消息上下文 | ✅ | 自动将 quote 内容前置到本轮上下文 |

模式对比

| 维度 | Agent 模式(自建应用) | Bot 模式(智能机器人 API) | |---|---|---| | 回调数据格式 | XML | JSON | | 企业微信创建方式 | 应用管理 -> 自建应用 | 智能机器人 -> API 模式 | | 回调路径默认值 | /wecom/callback | /wecom/bot/callback | | 回复机制 | 主动调用 WeCom 发送 API | 回调响应 stream + 轮询刷新 | | 流式体验 | 多条消息模拟增量 | 原生 stream 协议 | | 思考展示 | 不适用 | 支持 <think> 标签映射到 thinking_content | | 出站媒体(图/语音/视频/文件) | 支持 | 支持(active_stream msg_item(image) + response_url/Webhook 回包,video 自动按 file 回传) | | 典型场景 | 标准企业应用、菜单/回调体系 | 对话机器人、连续流式问答 |

回调路径规划建议

| 场景 | 建议 | |---|---| | 同时开 Agent + Bot | 使用不同路径:/wecom/callback/wecom/bot/callback | | 多账户 Agent | 每个账户独立路径(如 /wecom/sales/callback) | | 与 Telegram/Feishu 并存 | 不复用任何 webhook path,避免路由冲突 |

前置要求

| 项目 | 说明 | |---|---| | OpenClaw | 已安装并可正常运行 Gateway | | 企业微信管理员权限 | 可创建应用或智能机器人并配置回调 | | 公网入口 | 企业微信需回调到可访问 URL(常见用 Cloudflare Tunnel) | | Node.js | 与 OpenClaw 运行环境一致 | | 本地语音识别(可选) | whisper-cliwhisper | | ffmpeg(推荐) | AMR 等格式转码时需要 |

安装与加载

方式 A:通过 OpenClaw 安装(推荐)

openclaw plugins install @dingxiang-me/openclaw-wechat

安装后插件会进入 ~/.openclaw/extensions/openclaw-wechat/。这个目录主要用于 OpenClaw 运行时发现插件,通常不建议直接手改其中的 package.jsonpackage-lock.jsonopenclaw.plugin.json

方式 B:本地路径加载(开发模式)

git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
cd OpenClaw-Wechat
npm install

~/.openclaw/openclaw.json 中配置插件加载:

{
  "plugins": {
    "enabled": true,
    "allow": ["openclaw-wechat"],
    "load": {
      "paths": ["/path/to/OpenClaw-Wechat"]
    },
    "entries": {
      "openclaw-wechat": {
        "enabled": true
      }
    }
  }
}

配置文件与路径职责

Issue #25 里问到的几个路径,职责完全不同。先把边界理清:

| 路径 | 应不应该手改 | 作用 | |---|---|---| | ~/.openclaw/openclaw.json | 应该 | OpenClaw 主配置入口。插件加载、channels.wecom.*bindingsenv.vars 都写这里 | | ~/.openclaw/extensions/openclaw-wechat/package.json | 一般不要 | 已安装插件包的元数据,不是业务配置入口 | | ~/.openclaw/extensions/openclaw-wechat/openclaw.plugin.json | 一般不要 | 插件 manifest / schema,供 OpenClaw 识别配置结构 | | ~/.openclaw/extensions/openclaw-wechat/package-lock.json | 不要 | 安装锁文件,不承载运行配置 | | ~/.openclaw/agents/<id>/sessions/sessions.json | 不要 | 运行时会话索引,属于状态数据,不是配置文件 | | ~/.openclaw/agents/<id>/sessions/*.jsonl | 不要 | 会话 transcript / 运行产物 |

Windows 对应关系也是同一套逻辑,例如:

| Windows 示例路径 | 结论 | |---|---| | D:\\Win\\AppData\\LocalLow\\.openclaw\\openclaw.json | 这是主配置文件,参数加这里 | | D:\\Win\\AppData\\LocalLow\\.openclaw\\extensions\\openclaw-wechat\\openclaw.plugin.json | 这是插件 schema,不是让你填业务参数的地方 | | D:\\Win\\AppData\\LocalLow\\.openclaw\\agents\\main\\sessions\\sessions.json | 这是运行态索引,不要手动写参数 |

参数应该放到哪里

| 参数类型 | 推荐位置 | |---|---| | 插件启用 / 加载 | plugins.enabledplugins.allowplugins.entries.openclaw-wechat | | 企业微信业务配置 | channels.wecom.* | | 多账号配置 | channels.wecom.accounts.<id>.* | | 文档工具默认账号 | channels.wecom.defaultAccount | | 账号到 Agent 路由 | OpenClaw 根配置 bindings | | 敏感信息 | 优先 env.vars.* 或系统环境变量;其次写入 openclaw.json |

Control UI、文件、环境变量怎么分工

| 方式 | 适合什么 | |---|---| | Control UI | 日常调整常规字段:corpIdcallbackTokenaccounts.*tools.doc | | openclaw.json | 结构化配置、版本管理、多人协作、bindings | | env.vars / 系统环境变量 | Secret、代理、不同环境下的覆盖项 |

快速开始

1) 企业微信侧准备

Agent 模式(自建应用)

  1. 创建自建应用,拿到 AgentIdSecret
  2. 在“我的企业”拿到 CorpId
  3. 开启“接收消息”,配置:
    • URL: https://你的域名/wecom/callback
    • Token: 自定义随机字符串
    • EncodingAESKey: 企业微信生成

Bot 模式(智能机器人)

  1. 创建智能机器人时选择 API 模式
  2. 配置回调 URL:https://你的域名/wecom/bot/callback
  3. 获取并保存 tokenencodingAesKey

2) OpenClaw 最小配置示例

Agent 最小可用

{
  "channels": {
    "wecom": {
      "enabled": true,
      "corpId": "wwxxxx",
      "corpSecret": "xxxx",
      "agentId": 1000004,
      "callbackToken": "xxxx",
      "callbackAesKey": "xxxx",
      "webhookPath": "/wecom/callback"
    }
  }
}

Bot 最小可用(Bot-only)

{
  "channels": {
    "wecom": {
      "enabled": true,
      "bot": {
        "enabled": true,
        "token": "xxxx",
        "encodingAesKey": "xxxx",
        "webhookPath": "/wecom/bot/callback"
      }
    }
  }
}

Bot 长连接最小可用(无需公网 Bot 回调)

{
  "channels": {
    "wecom": {
      "enabled": true,
      "bot": {
        "enabled": true,
        "longConnection": {
          "enabled": true,
          "botId": "your-bot-id",
          "secret": "your-bot-secret"
        }
      }
    }
  }
}

3) 启动与验证

openclaw gateway restart
openclaw gateway status
openclaw plugins list
npm run wecom:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --account default

wecom:selfcheck 帮助:

node ./scripts/wecom-selfcheck.mjs --help

wecom:bot:selfcheck 帮助:

node ./scripts/wecom-bot-selfcheck.mjs --help

文档工具(WeCom Doc)

插件现在内置了 wecom_doc 工具,不需要额外安装第二个插件。它复用当前 OpenClaw-Wechat 的账号、代理和多账户配置。

当前 wecom_doc 重点覆盖创建、权限、分享、收集表和诊断能力;不包含富文本正文编辑器式的文档内容编辑。如果需要改正文,请先在产品描述里明确这是后续能力,不要按“已支持编辑”对外承诺。

支持的动作

| action | 说明 | 关键参数 | |---|---|---| | create | 新建文档/表格,可创建后立即授权 | docName docType viewers? collaborators? | | rename | 重命名文档 | docId newName | | get_info | 获取文档基础信息 | docId | | share | 获取文档分享信息 | docId | | get_auth | 获取文档权限信息 | docId | | diagnose_auth | 诊断为什么打不开文档/链接 | docId | | validate_share_link | 校验分享链接对 guest/外部访问是否可用 | shareUrl | | delete | 删除文档或收集表 | docIdformId | | grant_access | 批量增删查看人/协作者 | docId viewers? collaborators? remove*? | | add_collaborators | 快速添加协作者 | docId collaborators | | set_join_rule | 修改文档可见范围/加入规则 | docId request | | set_member_auth | 修改文档通知成员与权限 | docId request | | set_safety_setting | 修改文档安全设置 | docId request | | create_collect | 创建收集表 | formInfo spaceId? fatherId? | | modify_collect | 修改收集表 | oper formId formInfo | | get_form_info | 获取收集表定义 | formId | | get_form_answer | 获取收集表答案 | repeatedId answerIds? | | get_form_statistic | 获取收集表统计 | requests | | get_sheet_properties | 获取在线表格属性 | docId |

启用方式

默认启用。你也可以显式配置:

{
  "channels": {
    "wecom": {
      "defaultAccount": "docs",
      "tools": {
        "doc": true,
        "docAutoGrantRequesterCollaborator": true
      },
      "accounts": {
        "docs": {
          "corpId": "wwxxxx",
          "corpSecret": "xxxx",
          "agentId": 1000008,
          "tools": {
            "doc": true
          }
        }
      }
    }
  }
}

账号选择规则

wecom_doc 在执行时按下面顺序选择账号:

  1. 工具参数里的 accountId
  2. 当前 agent 绑定账号
  3. channels.wecom.defaultAccount
  4. 第一个启用了文档工具的可用账号

创建后自动授权

默认开启:如果 wecom_doc 是在企业微信会话里被调用,插件会把当前发送者自动加成文档协作者,避免“文档已创建但发起人无权限查看”。

create / share 结果现在会明确返回真实 docId,后续做权限、分享和诊断时应优先使用这个 docId,不要直接拿分享链接路径里的片段代替。

可关闭:

{
  "channels": {
    "wecom": {
      "tools": {
        "doc": true,
        "docAutoGrantRequesterCollaborator": false
      }
    }
  }
}

使用示例

  • “帮我新建一个企微文档,标题是《周会纪要》”
  • “把这个文档改名为《Q2 Roadmap》”
  • “查询文档 docxxxx 的权限信息”
  • “诊断为什么这个企微文档链接打不开”
  • “校验这个企微文档分享链接为什么对外打不开”
  • “创建一个企微文档,并把我加成协作者”
  • “给文档 docxxxx 添加协作者 dingxiang
  • “把文档 docxxxx 授权给 alice 查看,给 bob 协作”
  • “把文档 docxxxx 的查看规则改成仅企业内部可见”
  • “创建一个收集表,标题是《报名表》”
  • “查询收集表 formxxxx 的定义和题目”
  • “读取这份收集表最近一次提交答案”
  • “获取这个表格的 sheet 属性”

推荐工作流

| 目标 | 推荐动作顺序 | |---|---| | 创建后立刻给业务同事协作 | create -> grant_access / add_collaborators | | 判断“为什么别人打不开这个文档” | diagnose_auth -> validate_share_link | | 给外部链接排障 | 先看 validate_share_link,再决定是否执行 set_join_rule | | 后续继续操作同一文档 | 始终使用 create/share 返回的真实 docId,不要直接复制分享链接路径片段 |

常见误区

| 误区 | 正确做法 | |---|---| | 分享链接路径里的 ID 就是 docId | 不一定。以后续工具返回的真实 docId 为准 | | “加了协作者”就等于任何浏览器都能打开 | 不是。协作者权限、企业内访问、企业外访问、外部分享是不同层级 | | 链接能在企业微信里打开,就代表外部环境也能打开 | 不成立。guest 视角可能仍然是 blankpage |

配置参考

主配置键(channels.wecom

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | enabled | boolean | true | 是否启用 WeCom 渠道 | | corpId | string | - | 企业 ID(Agent 模式) | | corpSecret | string | - | 应用 Secret(敏感) | | agentId | number/string | - | 应用 AgentId | | callbackToken | string | - | 回调 Token(敏感) | | callbackAesKey | string | - | 回调 AES Key(敏感) | | webhookPath | string | /wecom/callback | Agent 回调路径(非 default 账户未配置时自动生成 /wecom/<accountId>/callback) | | agent | object | - | 兼容旧配置:agent.corpId/corpSecret/agentId(与顶层 Agent 字段等价) | | outboundProxy | string | - | WeCom 出站代理 | | apiBaseUrl | string | https://qyapi.weixin.qq.com | 可选:覆盖默认 WeCom API Base URL | | defaultAccount | string | - | 多账号下的默认账号 ID(文档工具等优先使用) | | tools.doc | boolean | true | 是否启用 wecom_doc 文档工具 | | webhooks | object | - | 命名 Webhook 目标映射(如 { "ops": "https://...key=xxx" }) | | accounts | object | - | 多账户配置(支持 accounts.<id>.bot 独立 Bot 配置) |

兼容说明:支持旧字段与旧结构迁移:nametoken / encodingAesKeyagent.*dynamicAgents.*dm.createAgentOnFirstMessagedm.allowFromworkspaceTemplatecommandAllowlist/commandBlockMessagecommands.blockMessage、inline 账户写法 channels.wecom.<accountId>,以及官方 / sunnoy 风格的 botIdsecretnetwork.egressProxyUrlnetwork.apiBaseUrl。新配置建议优先使用 accounts.<id>callbackToken/callbackAesKeybot.longConnection.*outboundProxy/apiBaseUrlcommands.*dynamicAgent.*

提示:accounts.<id> 现在支持 Bot-only 账号(仅配置 bot.*),不再强制要求 corpId/corpSecret/agentId。 兼容提示:当使用默认新路径时会自动附加 legacy alias,便于旧回调地址平滑迁移:Agent 默认路径会附加 /webhooks/app(多账号为 /webhooks/app/<id>),Bot 默认路径会附加 /webhooks/wecom(多账号为 /webhooks/wecom/<id>)。若 alias 与另一类路由冲突会自动跳过并告警。

Bot 配置(channels.wecom.bot

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | enabled | boolean | false | 启用 Bot 模式 | | token | string | - | Bot 回调 Token(敏感) | | encodingAesKey | string | - | Bot 回调 AESKey(43 位,敏感) | | webhookPath | string | /wecom/bot/callback | Bot 回调路径(非 default 账户未配置时自动生成 /wecom/<accountId>/bot/callback) | | placeholderText | string | 消息已收到... | stream 初始占位文案(可设为空字符串) | | streamExpireMs | integer | 600000 | stream 状态保留时间(30s~1h) | | replyTimeoutMs | integer | 90000 | Bot 等待模型回包超时(15s~10m) | | lateReplyWatchMs | integer | 180000 | Bot 超时后异步补发观察窗口(30s~10m) | | lateReplyPollMs | integer | 2000 | Bot 异步补发轮询间隔(500ms~10s) | | longConnection | object | - | 企业微信智能机器人长连接(WebSocket)配置 | | card | object | 见下方 | Bot 卡片回包策略(response_url / webhook_bot) |

重要限制:企业微信官方 Bot 在群聊里通常仅对 @机器人 消息触发回调。
因此 Bot 模式下即使配置 groupChat.triggerMode=direct/keyword,也会按 mention 处理(插件会输出告警)。

Bot 长连接配置(channels.wecom.bot.longConnection

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | enabled | boolean | false | 启用企业微信智能机器人长连接 | | botId | string | - | 企业微信智能机器人 BotID | | secret | string | - | 企业微信智能机器人 Secret(敏感) | | url | string | wss://openws.work.weixin.qq.com | 官方长连接地址 | | pingIntervalMs | integer | 30000 | 心跳 ping 间隔 | | reconnectDelayMs | integer | 5000 | 首次重连延迟 | | maxReconnectDelayMs | integer | 60000 | 指数退避最大重连延迟 |

说明:

  • 长连接模式下不需要暴露公网 Bot 回调地址。
  • 插件会在网关启动后主动连接 wss://openws.work.weixin.qq.com,并自动发送 aibot_subscribe
  • 入站消息与事件分别使用 aibot_msg_callback / aibot_event_callback,统一接入现有 Bot 处理链路。
  • 模型 block 输出会直接通过长连接发送 aibot_respond_msg,不是被动等待 stream-refresh 拉取。

Bot 卡片配置(channels.wecom.bot.card

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | enabled | boolean | false | 启用卡片回包 | | mode | string | markdown | markdown(兼容优先)或 template_card | | title | string | OpenClaw-Wechat | 卡片标题 | | subtitle | string | - | 卡片副标题 | | footer | string | - | 卡片底部说明 | | maxContentLength | integer | 1400 | 卡片正文最大长度(自动截断) | | responseUrlEnabled | boolean | true | 是否在 response_url 层发送卡片 | | webhookBotEnabled | boolean | true | 是否在 webhook_bot 层发送卡片 |

多账户 Bot 覆盖配置(channels.wecom.accounts.<id>.bot

当你启用了 accounts 多账户时,可以为每个账户单独配置 Bot 回调密钥、路径、超时和代理;若未配置,则回退到 channels.wecom.bot

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | enabled | boolean | false | 是否启用该账户 Bot | | token / callbackToken | string | - | 该账户 Bot 回调 Token(兼容旧字段) | | encodingAesKey / callbackAesKey | string | - | 该账户 Bot 回调 AESKey(兼容旧字段) | | webhookPath | string | /wecom/bot/callback | 该账户 Bot 回调路径 | | placeholderText | string | 消息已收到... | stream 初始占位文案 | | streamExpireMs | integer | 600000 | stream 状态保留时间 | | replyTimeoutMs | integer | 90000 | Bot 等待模型回包超时 | | lateReplyWatchMs | integer | 180000 | 超时后异步补发观察窗口 | | lateReplyPollMs | integer | 2000 | 异步补发轮询间隔 | | longConnection | object | - | 该账户专用长连接配置(覆盖全局 bot.longConnection) | | card | object | - | 该账户专用卡片回包配置(覆盖全局 bot.card) |

兼容提示:如果你是从官方插件或 sunnoy 配置直接迁移,也可以先保留 channels.wecom.botId/secretaccounts.<id>.botId/secret,以及 network.egressProxyUrl/apiBaseUrl;插件会在运行时兼容读取,npm run wecom:migrate -- --json 会给出归一化 patch。

多账户文档工具覆盖(channels.wecom.accounts.<id>.tools

| 键 | 类型 | 默认 | 说明 | |---|---|---|---| | doc | boolean | true | 是否启用该账户的 wecom_doc 工具 | | outboundProxy / proxyUrl / proxy | string | - | 该账户 Bot 专用代理(优先于全局) |

授权与指令策略

| 模块 | 配置键 | 作用 | |---|---|---| | 发送者授权 | allowFrom / accounts.<id>.allowFrom | 限定可对话用户;支持 * | | 拒绝文案 | allowFromRejectMessage | 未授权提示 | | 管理员 | adminUsers | 绕过命令白名单 | | 命令白名单 | commands.enabled + commands.allowlist | 限制 / 指令 | | 私聊策略 | dm.mode + dm.allowFrom + dm.rejectMessage | 控制私聊开放/白名单/配对审批/拒绝 | | 事件策略 | events.enabled + events.enterAgentWelcomeEnabled + events.enterAgentWelcomeText | 控制事件处理与 enter_agent 欢迎语 | | 群聊触发 | groupChat.enabled + triggerMode + mentionPatterns + triggerKeywords | 控制群消息触发条件(自建应用支持 direct/mention/keyword;Bot 模式按平台限制固定 mention) | | 群聊准入策略 | groupPolicy + groupChat.policy + groups.<chatId>.policy | 显式控制 open / allowlist / deny;支持账户级覆盖与按群覆盖 | | 群聊成员授权 | groupAllowFrom + groups.<chatId>.allowFrom | 与 allowlist 搭配使用,控制哪些群成员可以触发机器人;支持账户级覆盖与按群覆盖 | | 动态路由 | dynamicAgent.*(兼容 dynamicAgents.*dm.createAgentOnFirstMessage) | 动态 Agent + workspace bootstrap 播种 |

吞吐与稳定性

| 模块 | 配置键 | 说明 | |---|---|---| | 文本防抖 | debounce.enabled/windowMs/maxBatch | 合并短时间多条文本 | | Agent 增量回包 | streaming.enabled/minChars/minIntervalMs | 多消息模拟流式 | | 异步补发 | WECOM_LATE_REPLY_WATCH_MS/POLL_MS | dispatch 超时后补发最终回复 | | Pending Reply 持久化 | delivery.pendingReply.persist/storeFile | 重启后恢复未送达最终回复;未指定 storeFile 时自动写入 OpenClaw state 目录 | | 推理展示 | delivery.reasoning.mode/title/maxChars | 控制 <think> / reasoning 分离显示、附加到最终回复,或完全隐藏 | | 最终回复格式 | delivery.replyFormat | auto / text / markdown;优先在支持的 WeCom 链路上保留 markdown,其余链路自动回退纯文本 | | 观测统计 | observability.enabled/logPayloadMeta | 记录入站/回包/错误并在 /status 展示 |

语音转写(本地)

| 键 | 默认 | 说明 | |---|---|---| | voiceTranscription.enabled | true | 开启回退转写 | | provider | local-whisper-cli | local-whisper-cli / local-whisper | | command | 自动探测 | 本地命令路径 | | modelPath | - | whisper-cli 模型路径 | | model | base | whisper 模型名 | | timeoutMs | 120000 | 单次转写超时 | | maxBytes | 10485760 | 最大音频大小 | | ffmpegEnabled | true | 不兼容格式自动转码 | | transcodeToWav | true | 优先转为 wav |

多账户示例

{
  "channels": {
    "wecom": {
      "outboundProxy": "http://127.0.0.1:7890",
      "accounts": {
        "default": {
          "enabled": true,
          "corpId": "ww-default",
          "corpSecret": "secret-default",
          "agentId": 1000004,
          "callbackToken": "token-default",
          "callbackAesKey": "aes-default",
          "webhookPath": "/wecom/callback",
          "allowFrom": ["*"]
        },
        "sales": {
          "enabled": true,
          "corpId": "ww-sales",
          "corpSecret": "secret-sales",
          "agentId": 1000005,
          "callbackToken": "token-sales",
          "callbackAesKey": "aes-sales",
          "webhookPath": "/wecom/sales/callback",
          "outboundProxy": "http://10.0.0.5:8888",
          "bot": {
            "enabled": true,
            "token": "sales-bot-token",
            "encodingAesKey": "sales-bot-aes",
            "webhookPath": "/wecom/sales/bot/callback",
            "replyTimeoutMs": 120000,
            "outboundProxy": "http://10.0.0.9:7890"
          },
          "allowFrom": ["alice", "wecom:bob"],
          "allowFromRejectMessage": "销售助手未授权,请联系管理员。"
        }
      }
    }
  }
}

使用 OpenClaw bindings 做账号级 Agent 路由

OpenClaw-Wechat 不自己实现第二套路由规则;账号到 Agent 的稳定绑定,直接走 OpenClaw 核心 bindings。插件会把 channel=wecomaccountId=<id> 传给核心路由层。

示例:

{
  "bindings": [
    {
      "match": {
        "channel": "wecom",
        "accountId": "sales"
      },
      "agentId": "sales"
    },
    {
      "match": {
        "channel": "wecom",
        "accountId": "support"
      },
      "agentId": "support"
    }
  ]
}

这套绑定优先级高于插件里的动态账号猜测,适合多账号、多业务线、同一 OpenClaw 上挂多个 WeCom 入口的场景。

消息能力矩阵

Agent 模式

| 类型 | 入站 | 出站 | 备注 | |---|---|---|---| | 文本 | ✅ | ✅ | 自动分段 | | 图片 | ✅ | ✅ | 入站可识别,出站可发送 | | 语音 | ✅ | ✅ | 入站支持本地转写回退;出站支持 AMR/SILK | | 视频 | ✅ | ✅ | 下载并可回包 | | 文件 | ✅ | ✅ | 下载并可回包 | | 链接 | ✅ | ❌ | 提取标题/描述/URL |

Bot 模式

| 类型 | 入站 | 出站 | 备注 | |---|---|---|---| | 文本 | ✅ | ✅ | 原生 stream | | 图片 | ✅ | ✅ | response_url mixed + webhook fallback | | 语音 | ✅ | ✅ | 以文本结果回传 | | 文件 | ✅ | ✅ | Bot 文件入站下载;出站可按 file 回传 | | mixed(图文) | ✅ | ✅ | 聚合后回文本 | | 链接/位置 | ✅ | ✅ | 转换为文本上下文 |

命令与会话策略

命令

| 命令 | 说明 | |---|---| | /help | 查看帮助 | | /status | 查看运行状态 | | /clear | 清理会话(兼容映射到 /reset) | | /new | 新建会话(兼容映射到 /reset) | | /reset | 重置会话 | | /compact | 压缩会话(由上层运行时支持) |

会话策略

  • 默认账号一用户一会话:wecom:<userid>
  • 非默认账号一用户一会话:wecom:<accountId>:<userid>
  • 群聊可配置“仅 @ 才触发”,避免误触发

出站目标格式

  • userwecom:alice / user:alice
  • group(chat)group:wrxxxx / chat:wcxxxx(自动走 appchat/send
  • partyparty:2 / dept:2
  • tagtag:ops
  • webhookwebhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxwebhook:key:xxx
  • webhook(命名)webhook:ops(从 channels.wecom.webhooks.opsaccounts.<id>.webhooks.ops 解析)

环境变量速查

核心与回调

| 变量 | 必填 | 说明 | |---|---|---| | WECOM_CORP_ID | Agent 必填 | 企业 ID | | WECOM_CORP_SECRET | Agent 必填 | 应用 Secret | | WECOM_AGENT_ID | Agent 必填 | AgentId | | WECOM_CALLBACK_TOKEN | Agent 必填 | 回调 Token | | WECOM_CALLBACK_AES_KEY | Agent 必填 | 回调 AESKey | | WECOM_WEBHOOK_PATH | 否 | Agent 回调路径(默认 /wecom/callback) | | WECOM_WEBHOOK_TARGETS | 否 | 命名 Webhook 目标映射(name=url,多个用 ,/; 分隔) |

Bot

| 变量 | 必填 | 说明 | |---|---|---| | WECOM_BOT_ENABLED | 否 | 是否启用 Bot 模式 | | WECOM_BOT_TOKEN | Bot 必填 | Bot Token | | WECOM_BOT_ENCODING_AES_KEY | Bot 必填 | Bot EncodingAESKey | | WECOM_BOT_WEBHOOK_PATH | 否 | Bot 回调路径 | | WECOM_BOT_PLACEHOLDER_TEXT | 否 | stream 占位文案 | | WECOM_BOT_STREAM_EXPIRE_MS | 否 | stream 保留时长 | | WECOM_BOT_REPLY_TIMEOUT_MS | 否 | Bot 等待模型回包超时 | | WECOM_BOT_LATE_REPLY_WATCH_MS | 否 | Bot 超时后补发观察窗口 | | WECOM_BOT_LATE_REPLY_POLL_MS | 否 | Bot 补发轮询间隔 | | WECOM_BOT_CARD_ENABLED | 否 | 是否启用 Bot 卡片回包 | | WECOM_BOT_CARD_MODE | 否 | 卡片模式:markdown / template_card | | WECOM_BOT_CARD_TITLE | 否 | 卡片标题 | | WECOM_BOT_CARD_SUBTITLE | 否 | 卡片副标题 | | WECOM_BOT_CARD_FOOTER | 否 | 卡片底部说明 | | WECOM_BOT_CARD_MAX_CONTENT_LENGTH | 否 | 卡片正文最大长度 | | WECOM_BOT_CARD_RESPONSE_URL_ENABLED | 否 | response_url 层卡片开关 | | WECOM_BOT_CARD_WEBHOOK_BOT_ENABLED | 否 | webhook_bot 层卡片开关 | | WECOM_<ACCOUNT>_BOT_* | 否 | 账户级 Bot 覆盖(如 WECOM_SALES_BOT_TOKEN) | | WECOM_<ACCOUNT>_BOT_PROXY | 否 | 账户级 Bot 媒体下载/回包代理 |

策略与流控

| 变量 | 说明 | |---|---| | WECOM_ALLOW_FROM / WECOM_<ACCOUNT>_ALLOW_FROM | 发送者白名单 | | WECOM_ALLOW_FROM_REJECT_MESSAGE / WECOM_<ACCOUNT>_ALLOW_FROM_REJECT_MESSAGE | 未授权提示 | | WECOM_ADMIN_USERS | 管理员用户列表 | | WECOM_COMMANDS_ENABLED / WECOM_COMMANDS_ALLOWLIST / WECOM_COMMANDS_REJECT_MESSAGE | 命令白名单策略 | | WECOM_DM_POLICY / WECOM_DM_MODE / WECOM_DM_ALLOW_FROM / WECOM_DM_REJECT_MESSAGE | 私聊策略(支持 WECOM_<ACCOUNT>_DM_* 覆盖) | | WECOM_EVENTS_ENABLED / WECOM_EVENTS_ENTER_AGENT_WELCOME_ENABLED / WECOM_EVENTS_ENTER_AGENT_WELCOME_TEXT | 事件处理与 enter_agent 欢迎语(支持 WECOM_<ACCOUNT>_EVENTS_*) | | WECOM_GROUP_CHAT_ENABLED / WECOM_GROUP_CHAT_REQUIRE_MENTION / WECOM_GROUP_CHAT_MENTION_PATTERNS | 群触发策略 | | WECOM_DEBOUNCE_ENABLED / WECOM_DEBOUNCE_WINDOW_MS / WECOM_DEBOUNCE_MAX_BATCH | 文本防抖 | | WECOM_STREAMING_ENABLED / WECOM_STREAMING_MIN_CHARS / WECOM_STREAMING_MIN_INTERVAL_MS | Agent 增量回包 | | WECOM_LATE_REPLY_WATCH_MS / WECOM_LATE_REPLY_POLL_MS | 异步补发窗口与轮询频率 | | WECOM_OBSERVABILITY_ENABLED / WECOM_OBSERVABILITY_PAYLOAD_META | 观测统计与载荷元信息日志开关 |

语音回退转写

| 变量 | 说明 | |---|---| | WECOM_VOICE_TRANSCRIBE_ENABLED | 启用本地语音转写回退 | | WECOM_VOICE_TRANSCRIBE_PROVIDER | local-whisper-cli / local-whisper | | WECOM_VOICE_TRANSCRIBE_COMMAND | 转写命令 | | WECOM_VOICE_TRANSCRIBE_MODEL_PATH | whisper-cli 模型路径 | | WECOM_VOICE_TRANSCRIBE_MODEL | whisper 模型名 | | WECOM_VOICE_TRANSCRIBE_TIMEOUT_MS | 转写超时 | | WECOM_VOICE_TRANSCRIBE_MAX_BYTES | 音频大小上限 | | WECOM_VOICE_TRANSCRIBE_FFMPEG_ENABLED | 是否允许 ffmpeg 转码 | | WECOM_VOICE_TRANSCRIBE_TRANSCODE_TO_WAV | 是否优先转 WAV |

公网回调与 Gateway Auth

目标

企业微信访问你的回调地址时,必须直接命中 OpenClaw 网关的 webhook 路由。
不能被这些中间层拦住:

  • Gateway Auth / Token 鉴权
  • 反向代理登录页 / SSO
  • 前端 WebUI 路由
  • 另一台静态站点或错误 upstream

推荐架构

| 场景 | 推荐做法 | |---|---| | 单域名 | 将 /wecom/*、legacy /webhooks/app*/webhooks/wecom* 单独反代到 OpenClaw 网关端口 | | 有 Gateway Auth / Zero Trust | 对上述 webhook 路径做认证豁免,不要求 Authorization/Cookie | | 前端与网关共用域名 | 前端只接管 /ui、静态资源等路径,不要吞掉 /wecom/* | | 最稳妥 | 单独给企微回调使用一个子域名,只代理到 OpenClaw |

最小验证

| 探测 | 预期 | |---|---| | curl -i http://127.0.0.1:8885/wecom/callback | 200 + wecom webhook ok | | curl -i http://127.0.0.1:8885/wecom/bot/callback | 200 + wecom bot webhook ok | | curl -i https://你的域名/wecom/callback | 与本机一致,不应返回 HTML、401/403 或跳转 | | curl -i https://你的域名/wecom/bot/callback | 与本机一致,不应返回 HTML、401/403 或跳转 |

常见返回值的含义

| 现象 | 结论 | 处理 | |---|---|---| | 200 + wecom webhook ok / wecom bot webhook ok | 路由命中正常 | 继续做 URL 验证与企业微信后台配置 | | 200 + HTML | 请求被前端/WebUI 接走 | 单独为 /wecom/* 配反代,不要落到前端 | | 401/403 | 被 Gateway Auth / Zero Trust / 反代鉴权拦截 | 为 webhook 路径放行认证 | | 301/302/307/308 | 被登录页、SSO 或前端路由重定向 | 取消 webhook 路径重定向,直接代理到网关 | | 502/503/504 | OpenClaw 网关端口不可达 | 先修网关存活与 upstream | | 404 | 路径写错或插件路由没注册 | 核对 webhookPath、插件启用状态和 legacy alias |

反代示例(Nginx)

server {
  listen 443 ssl http2;
  server_name wecom.example.com;

  location /wecom/ {
    proxy_pass http://127.0.0.1:8885;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }

  location /webhooks/app {
    proxy_pass http://127.0.0.1:8885;
  }

  location /webhooks/wecom {
    proxy_pass http://127.0.0.1:8885;
  }
}

Cloudflare Tunnel 示例

ingress:
  - hostname: wecom.example.com
    service: http://127.0.0.1:8885
  - service: http_status:404

建议把企微回调放到单独子域名,不要和前端登录页共用同一套路由规则。

自检建议

npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts
npm run wecom:callback:matrix -- --agent-url https://你的域名/wecom/callback --bot-url https://你的域名/wecom/bot/callback

现在自检会明确提示这些原因:

  • route-not-found
  • html-fallback
  • gateway-auth
  • redirect-auth
  • gateway-unreachable

如果你要把新路径和 legacy alias 一次跑完,直接用:

npm run wecom:callback:matrix -- \
  --agent-url https://你的域名/wecom/callback \
  --bot-url https://你的域名/wecom/bot/callback \
  --agent-legacy-url https://你的域名/webhooks/app \
  --bot-legacy-url https://你的域名/webhooks/wecom

Webhook 与 Heartbeat 运维

适用场景

| 需求 | 推荐方式 | |---|---| | 手工发一条群通知 | openclaw message send --channel wecom --target webhook:<name> | | 让 agent 处理后发到群 | openclaw agent --deliver --reply-channel wecom --reply-to webhook:<name> | | 固定周期发摘要/巡检结果 | OpenClaw agents.defaults.heartbeat + target: "wecom" + to: "webhook:<name>" |

先配置命名 Webhook

{
  "channels": {
    "wecom": {
      "webhooks": {
        "ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx",
        "dev": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy"
      }
    }
  }
}

多账号时,也可以挂到 channels.wecom.accounts.<id>.webhooks

直接发送

openclaw message send --channel wecom --target webhook:ops --message "服务已恢复正常"

让 Agent 结果投递到群

openclaw agent \
  --message "整理今天的告警摘要" \
  --deliver \
  --reply-channel wecom \
  --reply-to webhook:ops

用 Heartbeat 定时投递到群

当前机器上的 OpenClaw 2026.3.2 支持把 heartbeat 直接投递到指定渠道和目标。
对 WeCom Webhook 的推荐写法是:

{
  "channels": {
    "wecom": {
      "webhooks": {
        "ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
      }
    }
  },
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "target": "wecom",
        "to": "webhook:ops",
        "prompt": "检查网关状态、最近告警和企业微信通道健康;如果一切正常,以三行内摘要输出。",
        "ackMaxChars": 300
      }
    }
  }
}

多账号 webhook 场景可以再加:

{
  "agents": {
    "defaults": {
      "heartbeat": {
        "target": "wecom",
        "to": "webhook:ops",
        "accountId": "sales"
      }
    }
  }
}

说明:

  • target: "wecom" 指定投递到 WeCom 渠道
  • to: "webhook:ops" 指定 WeCom 渠道里的命名 webhook 目标
  • accountId 只在多账号场景需要
  • 如果不设 target,heartbeat 默认运行但不会向外发送消息

运维常用命令

openclaw system heartbeat last
openclaw config get agents.defaults.heartbeat
openclaw status --deep
openclaw logs --follow

需要手工触发一次立即执行:

openclaw system event --mode now --text "立即执行下一轮运维心跳"

与其他渠道并存建议

建议固定以下三点,减少“偶发无回复/冲突”风险:

  1. 配置 plugins.allow 显式白名单(至少包含 openclaw-wechat
  2. 各渠道使用独立 webhook path,不复用
  3. 同一台机器尽量只运行一个 OpenClaw gateway 进程

详细说明见:docs/troubleshooting/coexistence.md

故障排查

快速定位表

| 现象 | 先看什么 | 常见原因 | 处理建议 | |---|---|---|---| | 回调验证失败 | curl https://域名/wecom/callback | URL 不通、Token/AESKey 不一致 | 先通公网,再核对配置 | | curl 到公网回调是 200,但企业微信后台仍提示 openapi回调地址请求不通过 | 企业微信后台校验 | 临时隧道域名、不受信任公网域名、企业侧域名策略或回调链路仍被中间层改写 | 优先换成稳定公网域名;不要把 trycloudflare.com 之类临时域名当正式 Agent 回调地址 | | curl /wecom/callback 返回 WebUI 页面 | 反向代理路由与回调路径 | 域名把 /wecom/callback 转发到了前端/静态站点 | 单独为 /wecom/* 配置反向代理到 OpenClaw 网关端口 | | curl https://域名/wecom/callback 返回 401/403 | Gateway Auth / Zero Trust / 反代鉴权 | webhook 路径被要求登录或带 Token | 对 /wecom/*/webhooks/app*/webhooks/wecom* 做认证豁免 | | curl https://域名/wecom/callback 返回 301/302/307/308 | 登录跳转 / SSO / 前端路由 | webhook 被重定向到登录页或前端 | 让 webhook 路径直接反代到 OpenClaw 网关 | | 能收到消息但不回复 | openclaw gateway status + openclaw logs --follow | 模型超时、会话排队、权限策略拦截 | 查看 dispatch/allowFrom/commands 日志 | | 能收到消息但不回复(已确认本地日志正常) | 企业微信自建应用后台 -> 开发设置 | 未配置“可信 IP”,企业微信拒绝部分回调/发送链路 | 在应用里补充 OpenClaw 出网 IP 到可信 IP 列表(保存后重试) | | Bot 图片识别失败 | wecom(bot): failed to fetch image url | URL 失效、返回非图像流 | 已支持 octet-stream+解密兜底,先升级到最新版本 | | 语音转写失败 | wecom: voice transcription failed | 本地命令或模型路径错误 | 检查 commandmodelPathffmpeg | | 启动出现账号体检告警 | wecom: account diagnosis ... | 多账号 Token/Agent/路径存在冲突风险 | 按日志 code 与账户列表调整配置,优先处理 warn 级别 | | wecom:selfcheck -- --all-accounts 提示 account '<id>' not found or incomplete | 账号配置结构 | 旧版本自检脚本没完全识别 agent 子块、legacy inline 账户,或账号字段确实缺失 | 升级到最新版本后重跑;再核对 channels.wecom.accounts.<id> 是否包含完整 Agent 凭据 | | gettoken 失败 | 企业微信 API 返回码 | CorpId/Secret 错或网络受限 | 检查凭据/配置代理 |

推荐检查命令

openclaw gateway status
openclaw status --deep
openclaw logs --follow
npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts

开发与发布

常用命令

| 命令 | 作用 | |---|---| | npm test | 语法与单测 | | WECOM_E2E_ENABLE=1 npm run test:e2e:remote | 运行远程 E2E 测试(默认跳过;支持 WECOM_E2E_* 与兼容 E2E_WECOM_* 两套变量) | | WECOM_E2E_MATRIX_ENABLE=1 npm run test:e2e:matrix | 运行远程矩阵 E2E(签名验签/异常请求/stream refresh/去重链路) | | npm run test:e2e:prepare-browser | 远程浏览器沙箱就绪检查(可选自动安装 Chromium) | | npm run test:e2e:collect-pdf | 收集远端浏览器沙箱中的 PDF 产物到本地 | | npm run wecom:selfcheck -- --all-accounts | 配置+网络体检 | | npm run wecom:agent:selfcheck -- --account <id> | Agent 单账号端到端链路体检(URL 验证 + 加密 POST) | | npm run wecom:agent:selfcheck -- --all-accounts | Agent 多账号端到端链路体检(逐账号跑 URL 验证 + 加密 POST) | | npm run wecom:bot:selfcheck -- --account <id> | Bot 端到端链路体检(URL 验证/签名/加密/stream-refresh,支持多账户) | | npm run wecom:callback:matrix -- --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 公网回调矩阵体检(可附带 legacy alias URL) | | npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 远端矩阵验证(Agent+Bot) | | npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调> --prepare-browser --collect-pdf | 远端矩阵验证(含浏览器沙箱检查与 PDF 回收) | | WECOM_E2E_BOT_URL=<...> WECOM_E2E_AGENT_URL=<...> npm run wecom:remote:e2e -- --mode all | 用环境变量驱动远端 E2E(兼容旧 E2E_WECOM_*) | | npm run wecom:e2e:scenario -- --scenario full-smoke --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 场景化 E2E(预置 smoke/queue 场景) | | npm run wecom:e2e:scenario -- --scenario callback-matrix --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 只做公网回调矩阵检查 | | npm run wecom:e2e:scenario -- --scenario compat-smoke --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调> | 兼容矩阵验证(新旧回调地址都跑一遍) | | npm run wecom:e2e:scenario -- --scenario matrix-smoke --bot-url <公网Bot回调> | Bot 协议矩阵验证(验签/异常请求/stream-refresh/去重;需 WECOM_BOT_TOKEN/WECOM_BOT_ENCODING_AES_KEY) | | npm run wecom:e2e:compat -- --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调> | 兼容矩阵快捷命令(等价 --scenario compat-smoke) | | npm run wecom:e2e:full -- --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 一键 full-smoke(默认带 --prepare-browser --collect-pdf) | | GitHub Actions -> CI -> Run workflow | 在仓库 CI 手动触发远程 E2E:设置 run_remote_e2e=true,可选 e2e_scenario(含 compat-smoke)与浏览器参数 | | npm run wecom:smoke | 升级后快速回归(Agent 主链路) | | npm run wecom:smoke -- --with-bot-e2e | 升级后快速回归(含 Bot E2E) | | openclaw gateway restart | 重启网关 |

发版建议流程

  1. 更新 CHANGELOG.md 与版本号
  2. 运行 npm testwecom:selfcheck
  3. 打 tag 并发布 GitHub Release
  4. (可选)发布 npm 包

FAQ

Q1:Bot 模式回调一直失败?

通常是机器人创建成“标准模式”。请重建为 API 模式(JSON 回调)。

Q2:为什么图片偶发识别失败?

企业微信可能返回非标准 content-type 或加密媒体流。插件已增加类型识别与解密兜底;仍失败时请查看日志中的 header/下载错误。

Q3:能收消息但一直不回复,日志看起来也正常?

优先检查企业微信自建应用后台是否配置了可信 IP。如果可信 IP 缺失,企业微信可能在发送/回调链路上做安全拦截,表现为“能收到但不回”。

建议:把 OpenClaw 网关实际出网 IP 加入该应用的可信 IP 列表,保存后重试。

Q4:Telegram 和 WeCom 会互相影响吗?

理论上独立;实战中若复用 webhook 路径、多进程抢占、或 plugins.allow 未收紧,会出现干扰。按“并存建议”配置可大幅降低风险。

Q5:支持个人微信吗?

支持企业微信场景下的“微信插件入口”(个人微信扫码进入企业应用对话),不等同于“个人微信网页版协议”。

Q4.1:为什么 Bot 模式在“微信插件入口”里看不到机器人联系人?

这是企业微信产品形态差异,不是插件故障。
在很多租户里,“微信插件入口”主要对应**自建应用(Agent 回调)**可见,Bot 模式(智能机器人 API)不会以可直接会话的联系人形态出现。

建议:

  1. 需要稳定私聊入口:优先用自建应用(Agent 模式)
  2. 需要群聊通知/群内对话:优先用 Webhook Bot / Bot 模式
  3. 需要两者兼顾:并行启用 Agent(入口)+ Bot(群能力)
  4. 运行 npm run wecom:bot:selfcheck -- --account <id>(或 --all-accounts)可看到 bot.entry.visibility 提示,用于快速确认该行为属于产品形态差异而非插件故障

Q5:为什么 curl https://域名/wecom/callback 返回的是 WebUI 页面?

这是路由层问题,不是插件正常行为。GET /wecom/callback(无 echostr)应返回纯文本 wecom webhook ok
若返回 WebUI,说明你的反向代理把该路径转发到了前端服务而不是 OpenClaw 网关。

建议按顺序排查:

  1. 本机验证:curl http://127.0.0.1:8885/wecom/callback(应返回 wecom webhook ok
  2. 公网验证:curl -i https://你的域名/wecom/callback
  3. 代理配置:为 /wecom/* 单独反代到 OpenClaw 网关端口,不要落到 WebUI 路由

Q5.1:为什么本机和公网 curl 都是 200 wecom webhook ok,企业微信后台仍提示 openapi回调地址请求不通过

这说明“你的路由打通了”,但还不能证明企业微信后台会接受这条回调地址

常见根因:

  1. 用了临时公网域名,例如 trycloudflare.com
  2. 企业侧要求更稳定/更受信任的公网域名
  3. 你的回调链路虽然 curl200,但企业微信实际校验时仍遇到了中间层改写

明确建议:

  1. 自建应用正式回调地址优先用你自己的稳定公网域名
  2. 不要把 trycloudflare.com 这类临时隧道域名当正式 Agent 回调地址
  3. 继续确认该域名的 /wecom/callback 没有鉴权、跳转、前端兜底和缓存层干扰
  4. 如果只是想快速群聊验证,Bot/Webhook 路径通常比自建应用回调更容易先跑通

Q6:自建应用群聊怎么开?为什么群里不 @ 就不触发?

先区分两种通道能力:

  1. 群机器人(Webhook Bot):可直接添加到企微群,天然适合群聊收发;但群聊通常仅 @机器人 时才会回调。
  2. 自建应用(Agent 回调):插件支持处理 ChatId 群消息;但是否能收到“普通群消息”取决于企业微信实际下发能力(很多租户里普通群只能加机器人,无法像成员一样加自建应用)。

如果你的场景是“普通群里稳定对话”,优先用 Webhook Bot 模式(注意通常仍需 @机器人 才触发)。
如果你确认企业微信会把群消息回调到自建应用(日志里有 chatId=...),再配置触发模式:

{
  "channels": {
    "wecom": {
      "groupPolicy": "open",
      "groupChat": {
        "enabled": true,
        "triggerMode": "direct"
      }
    }
  }
}

如果还要限制“只有指定群成员能触发”,可以再加一层群聊成员授权:

{
  "channels": {
    "wecom": {
      "groupPolicy": "allowlist",
      "groupAllowFrom": ["alice", "bob"],
      "groups": {
        "wr9N1x...": {
          "policy": "allowlist",
          "allowFrom": ["ops_lead"],
          "rejectMessage": "当前群仅限值班同学触发。"
        }
      }
    }
  }
}

如果你要“一刀切关闭群聊处理”,直接用:

{
  "channels": {
    "wecom": {
      "groupPolicy": "deny"
    }
  }
}

同时确认企业微信侧前提:

  1. 自建应用已开启“接收消息”并完成 URL 验证
  2. 应用可见范围包含该群成员
  3. 日志里能看到 chatId=...(若没有 chatId,说明企业微信没有把群消息推送到该回调)

若你在企微侧只能给群添加“机器人”而不能添加“自建应用”,这不是插件配置问题,属于企微产品形态差异;建议走 Bot 模式承载群聊,自建应用用于私聊/应用会话/主动推送。

Q7:多账号创建了两个 agent,但只有一个回复,或者会话串了?

这是多账号隔离问题,不是“企微互相干扰”。

从当前版本开始:

  1. Agent 会话 key 已按账号隔离
  2. wecom:selfcheck -- --all-accounts 会识别 accounts.<id>agent 子块、legacy inline 账户
  3. bindings.match.channel=wecom + accountId=<id> 可以把不同账号稳定路由到不同 Agent

建议排查顺序:

  1. npm run wecom:selfcheck -- --all-accounts
  2. 确认每个账号 config.account 都是 OK
  3. openclaw.json 中为多账号配置 bindings
  4. 确认会话 key 形态符合预期:默认账号为 wecom:<userid>;非默认账号为 wecom:<accountId>:<userid>

版本与贡献

欢迎提交 Issue / PR。

Star History

Star History Chart