@dingxiang-me/openclaw-wechat 1.7.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.en.md +379 -11
  3. package/README.md +620 -12
  4. package/docs/channels/wecom.md +181 -3
  5. package/openclaw.plugin.json +148 -5
  6. package/package.json +9 -5
  7. package/src/core/delivery-router.js +2 -0
  8. package/src/core/stream-manager.js +13 -2
  9. package/src/core.js +96 -6
  10. package/src/wecom/account-config-core.js +2 -0
  11. package/src/wecom/account-config.js +12 -3
  12. package/src/wecom/agent-context.js +7 -1
  13. package/src/wecom/agent-dispatch-executor.js +13 -1
  14. package/src/wecom/agent-dispatch-fallback.js +23 -0
  15. package/src/wecom/agent-inbound-dispatch.js +1 -1
  16. package/src/wecom/agent-inbound-processor.js +33 -2
  17. package/src/wecom/agent-late-reply-runtime.js +31 -1
  18. package/src/wecom/agent-runtime-context.js +3 -0
  19. package/src/wecom/agent-webhook-handler.js +5 -0
  20. package/src/wecom/api-client-core.js +1 -1
  21. package/src/wecom/bot-context.js +7 -1
  22. package/src/wecom/bot-dispatch-fallback.js +34 -3
  23. package/src/wecom/bot-dispatch-handlers.js +47 -4
  24. package/src/wecom/bot-inbound-dispatch-runtime.js +10 -0
  25. package/src/wecom/bot-inbound-executor-helpers.js +11 -4
  26. package/src/wecom/bot-inbound-executor.js +34 -0
  27. package/src/wecom/bot-long-connection-manager.js +971 -0
  28. package/src/wecom/bot-reply-runtime.js +36 -6
  29. package/src/wecom/bot-runtime-context.js +3 -0
  30. package/src/wecom/bot-state-store.js +4 -5
  31. package/src/wecom/bot-webhook-dispatch.js +5 -0
  32. package/src/wecom/bot-webhook-handler.js +5 -0
  33. package/src/wecom/callback-health-diagnostics.js +86 -0
  34. package/src/wecom/channel-config-schema.js +242 -0
  35. package/src/wecom/channel-plugin.js +162 -4
  36. package/src/wecom/channel-status-state.js +150 -0
  37. package/src/wecom/command-handlers.js +6 -0
  38. package/src/wecom/command-status-text.js +32 -3
  39. package/src/wecom/doc-client.js +537 -0
  40. package/src/wecom/doc-schema.js +380 -0
  41. package/src/wecom/doc-tool.js +833 -0
  42. package/src/wecom/outbound-active-stream.js +17 -10
  43. package/src/wecom/outbound-delivery.js +49 -0
  44. package/src/wecom/plugin-account-policy-services.js +4 -1
  45. package/src/wecom/plugin-composition.js +2 -0
  46. package/src/wecom/plugin-constants.js +1 -1
  47. package/src/wecom/plugin-delivery-inbound-services.js +4 -0
  48. package/src/wecom/plugin-processing-deps.js +5 -0
  49. package/src/wecom/plugin-route-runtime-deps.js +2 -0
  50. package/src/wecom/plugin-services.js +37 -0
  51. package/src/wecom/register-runtime.js +20 -1
  52. package/src/wecom/request-parsers.js +1 -0
  53. package/src/wecom/route-registration.js +4 -1
  54. package/src/wecom/session-reset.js +168 -0
  55. package/src/wecom/text-format.js +22 -5
  56. package/src/wecom/text-inbound-scheduler.js +1 -1
  57. package/src/wecom/thinking-parser.js +74 -0
  58. package/src/wecom/voice-transcription-process.js +80 -8
  59. package/src/wecom/voice-transcription.js +11 -0
package/README.md CHANGED
@@ -6,42 +6,142 @@ OpenClaw-Wechat 是一个面向 OpenClaw 的企业微信渠道插件,支持两
6
6
 
7
7
  - `Agent 模式`:企业微信自建应用(XML 回调,经典模式)
8
8
  - `Bot 模式`:企业微信智能机器人 API 模式(JSON 回调,原生 stream)
9
+ - `Webhook 目标出站`:将消息主动投递到企业微信群 Webhook 或命名 Webhook 目标
9
10
 
10
11
  适用于“个人微信扫码进入企业微信应用对话”、“企业内员工问答助手”、“多账户多业务线消息分流”等场景。
11
12
 
12
13
  ## 目录
13
14
 
15
+ - [重大更新(v2.0.0)](#重大更新v200)
14
16
  - [功能概览](#功能概览)
15
17
  - [模式对比](#模式对比)
16
18
  - [5 分钟极速上手](#5-分钟极速上手)
17
19
  - [前置要求](#前置要求)
18
20
  - [安装与加载](#安装与加载)
21
+ - [配置文件与路径职责](#配置文件与路径职责)
19
22
  - [快速开始](#快速开始)
23
+ - [文档工具(WeCom Doc)](#文档工具wecom-doc)
20
24
  - [配置参考](#配置参考)
21
25
  - [消息能力矩阵](#消息能力矩阵)
22
26
  - [命令与会话策略](#命令与会话策略)
23
27
  - [环境变量速查](#环境变量速查)
28
+ - [公网回调与 Gateway Auth](#公网回调与-gateway-auth)
29
+ - [Webhook 与 Heartbeat 运维](#webhook-与-heartbeat-运维)
24
30
  - [与其他渠道并存建议](#与其他渠道并存建议)
25
31
  - [故障排查](#故障排查)
26
32
  - [开发与发布](#开发与发布)
27
33
  - [FAQ](#faq)
28
34
  - [版本与贡献](#版本与贡献)
29
35
 
36
+ ## 重大更新(v2.0.0)
37
+
38
+ 这次是一次真正的能力级更新,不是小修补。
39
+ `OpenClaw-Wechat` 现在已经把 **企业微信智能机器人长连接** 正式做成可用能力,并且已经在真实网关环境下完成:
40
+
41
+ - WebSocket 握手成功
42
+ - `aibot_subscribe` 鉴权成功
43
+ - 心跳 `ping` / 回执成功
44
+ - 网关日志出现 `socket opened` 和 `subscribed`
45
+
46
+ ### 企业微信 Bot 长连接已正式可用
47
+
48
+ | 项目 | 结果 |
49
+ |---|---|
50
+ | 官方地址 | `wss://openws.work.weixin.qq.com` |
51
+ | 入站命令 | `aibot_msg_callback` / `aibot_event_callback` |
52
+ | 出站命令 | `aibot_respond_msg` |
53
+ | 运行时实现 | 已切换为 `ws`,不再使用会导致 `1006` 的 Node 内置 WebSocket |
54
+ | Bot 回调公网依赖 | 长连接模式下不需要 |
55
+ | 自检命令 | `npm run wecom:bot:longconn:probe -- --json` |
56
+
57
+ 这次版本同时还保留并增强了原有的 **WeCom Doc 工具链**。
58
+ 现在 `OpenClaw-Wechat` 已经同时具备:
59
+
60
+ - 后台可视化配置
61
+ - WeCom Doc 文档/表格/收集表工具
62
+ - 文档权限与协作者管理
63
+ - 分享链接可用性诊断
64
+ - 文档权限打不开问题的直接诊断
65
+ - 链接文本输出完整性修复(URL 下划线不再丢失)
66
+
67
+ ### 这次版本解决了什么
68
+
69
+ | 场景 | 旧问题 | 现在的处理方式 |
70
+ |---|---|---|
71
+ | 企业微信 Bot 长连接 | 旧版地址、命令字和运行时实现不对,连接阶段直接 `1006` | 已对齐官方地址、协议命令和 `ws` 实现,真实网关已订阅成功 |
72
+ | 想验证“到底连上没有” | 只能看零散日志,难以区分握手、鉴权还是心跳失败 | `wecom:bot:longconn:probe` 会直接验证握手、鉴权与心跳 |
73
+ | 创建文档后自己打不开 | 文档创建成功,但发起人没被自动授权 | `create` 默认自动把当前企微请求人加入协作者 |
74
+ | 分享链接能发出来,但别人打开像“文档不存在” | 无法快速判断是权限、分享码还是 guest 访问问题 | `validate_share_link` 直接诊断 `guest / blankpage / scode / 路径资源 ID` |
75
+ | 只知道“更新成员权限成功”,但还是打不开 | 成员权限、查看规则、外部分享是三套概念,容易混淆 | `diagnose_auth` 直接输出企业内/企业外访问、查看成员、协作者与请求人角色 |
76
+ | 把分享链接路径当成 `docId` 使用 | 后续 API 调用报 `invalid docid` | `create/share/get_auth` 结果显式返回真实 `docId`,并给出使用提示 |
77
+ | 链接里有下划线,发出去后被改坏 | Markdown 清洗误伤 URL | 文本格式化已修复,URL 下划线完整保留 |
78
+
79
+ ### 可视化配置能力(Control UI)
80
+
81
+ | 项目 | 现状 | 说明 |
82
+ |---|---|---|
83
+ | WeCom 配置表单 | ✅ | `channels.wecom` 支持在后台页面直接编辑与保存 |
84
+ | 中文字段标签 | ✅ | 常用字段(如 `corpId`、`callbackToken`、`accounts.*`)均已中文化 |
85
+ | 敏感项标记 | ✅ | `secret/token/aesKey` 字段按敏感项展示 |
86
+ | 状态展示 | ✅ | `Connected` 不再长期 `n/a`,默认账号显示名中文化为“默认账号” |
87
+ | 入站状态追踪 | ✅ | 收到回调后自动更新 `Last inbound`(重启后首次入站前为 `n/a` 属正常) |
88
+ | 文档工具开关 | ✅ | `tools.doc` 等文档相关配置可被 schema 正确识别 |
89
+
90
+ ### 文档工具升级摘要
91
+
92
+ | 能力层 | 新增内容 |
93
+ |---|---|
94
+ | 文档基础 | `create`、`rename`、`get_info`、`share`、`delete` |
95
+ | 权限管理 | `grant_access`、`add_collaborators`、`set_join_rule`、`set_member_auth`、`set_safety_setting` |
96
+ | 运维诊断 | `get_auth`、`diagnose_auth`、`validate_share_link` |
97
+ | 表格/收集表 | `get_sheet_properties`、`create_collect`、`modify_collect`、`get_form_info`、`get_form_answer`、`get_form_statistic` |
98
+
99
+ ### 你升级后能直接获得的变化
100
+
101
+ - 在 OpenClaw 后台的 `Channels -> WeCom` 页面可直接配置并保存核心参数。
102
+ - 在同一个插件里直接调用 `wecom_doc`,不需要额外安装第二个 WeCom Doc 插件。
103
+ - 现在排查“为什么这个链接打不开”不需要再手翻日志和原始 JSON,工具会直接给出结论。
104
+ - 文档创建、协作者授权、分享链接诊断已经形成闭环,适合直接上线给真实企微用户使用。
105
+
30
106
  ## 5 分钟极速上手
31
107
 
32
108
  适合“先跑起来再细调”的场景。
33
109
 
34
110
  ### Step 1. 安装插件
35
111
 
112
+ ```bash
113
+ openclaw plugins install @dingxiang-me/openclaw-wechat
114
+ ```
115
+
116
+ > 最低建议版本:`2.0.0`。如果 `openclaw.json` 里的 `plugins.installs.openclaw-wechat` 仍显示 `1.7.x`,请先升级或重装;旧包不会正确注册 `wecom` channel 元数据。
117
+
118
+ 如果你是在本地开发或要直接跑仓库源码,再用下面这套:
119
+
36
120
  ```bash
37
121
  git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
38
122
  cd OpenClaw-Wechat
39
123
  npm install
40
124
  ```
41
125
 
42
- ### Step 2. 在 OpenClaw 里加载插件
126
+ ### Step 2. 在 OpenClaw 里启用插件
43
127
 
44
- `~/.openclaw/openclaw.json` 增加:
128
+ 如果你是通过 `openclaw plugins install` 安装,在 `~/.openclaw/openclaw.json` 增加:
129
+
130
+ ```json
131
+ {
132
+ "plugins": {
133
+ "enabled": true,
134
+ "allow": ["openclaw-wechat"],
135
+ "entries": {
136
+ "openclaw-wechat": {
137
+ "enabled": true
138
+ }
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ 如果你是源码路径加载,再使用下面这版(多一个 `load.paths`):
45
145
 
46
146
  ```json
47
147
  {
@@ -66,6 +166,9 @@ npm install
66
166
  |---|---|---|---|
67
167
  | Agent(自建应用) | `/wecom/callback` | 自建应用 API 接收 | `corpId/corpSecret/agentId/callbackToken/callbackAesKey` |
68
168
  | Bot(智能机器人) | `/wecom/bot/callback` | 智能机器人 **API 模式** | `bot.enabled/token/encodingAesKey` |
169
+ | Bot(智能机器人长连接) | 无需公网回调 | 智能机器人 **长连接模式** | `bot.enabled/bot.longConnection.enabled/bot.longConnection.botId/bot.longConnection.secret` |
170
+
171
+ > Agent 模式补充(重要):在企业微信自建应用后台请配置**可信 IP**,把 OpenClaw 网关实际出网 IP 加入白名单。否则可能出现“能收到消息但不回复”。
69
172
 
70
173
  ### Step 4. 重启并自检
71
174
 
@@ -73,6 +176,8 @@ npm install
73
176
  openclaw gateway restart
74
177
  openclaw gateway status
75
178
  npm run wecom:selfcheck -- --all-accounts
179
+ npm run wecom:agent:selfcheck -- --all-accounts
180
+ npm run wecom:bot:selfcheck -- --all-accounts
76
181
  ```
77
182
 
78
183
  ### Step 5. 发一条消息验证
@@ -92,6 +197,7 @@ npm run wecom:selfcheck -- --all-accounts
92
197
  | 企业微信入站消息处理 | ✅ | 文本、图片、语音、链接、文件/视频(Agent + Bot) |
93
198
  | AI 自动回复 | ✅ | 接入 OpenClaw Runtime,自动路由 Agent |
94
199
  | Bot 原生 stream 协议 | ✅ | `msgtype=stream` 刷新与增量回包 |
200
+ | Bot 长连接(WebSocket) | ✅ | 原生 `aibot_subscribe` / `aibot_msg_callback` / `aibot_respond_msg` |
95
201
  | Bot 卡片回包 | ✅ | 支持 `markdown/template_card`,失败自动降级文本 |
96
202
  | 多账户 | ✅ | `channels.wecom.accounts.<id>` |
97
203
  | 发送者授权控制 | ✅ | `allowFrom` + 账户级覆盖 |
@@ -99,6 +205,7 @@ npm run wecom:selfcheck -- --all-accounts
99
205
  | 事件欢迎语(enter_agent) | ✅ | `events.enterAgentWelcome*` 可配置 |
100
206
  | 命令白名单 | ✅ | `/help` `/status` `/clear` `/new` 等 |
101
207
  | 群聊触发策略 | ✅ | 支持 `direct/mention/keyword` 三种模式 |
208
+ | 企业微信文档工具 | ✅ | 内置 `wecom_doc` 工具:创建/重命名/分享/权限管理/收集表/表格属性 |
102
209
  | 文本防抖合并 | ✅ | 窗口期内多条消息合并投递 |
103
210
  | 异步补发(超时后) | ✅ | transcript 轮询补发最终回复 |
104
211
  | 观测统计 | ✅ | 入站/回包/错误计数 + 最近失败样本(`/status`) |
@@ -113,6 +220,7 @@ npm run wecom:selfcheck -- --all-accounts
113
220
  | 语音/视频/文件发送(出站) | ✅ | 自动判型上传后发送(语音支持 AMR/SILK) |
114
221
  | 语音转写(本地) | ✅ | 企业微信 Recognition 优先,缺失时回退本地 whisper |
115
222
  | Bot 模式媒体回传 | ✅ | `active_stream` 优先 `msg_item(image)`;失败自动降级媒体链接,`response_url`/Webhook Bot 继续兜底 |
223
+ | Bot 思考过程展示 | ✅ | 识别 `<think>/<thinking>/<thought>`,映射到原生 `thinking_content` 折叠区 |
116
224
  | Bot 文件入站 | ✅ | 支持 `msgtype=file` 下载并注入会话上下文 |
117
225
  | Bot 引用消息上下文 | ✅ | 自动将 `quote` 内容前置到本轮上下文 |
118
226
 
@@ -125,6 +233,7 @@ npm run wecom:selfcheck -- --all-accounts
125
233
  | 回调路径默认值 | `/wecom/callback` | `/wecom/bot/callback` |
126
234
  | 回复机制 | 主动调用 WeCom 发送 API | 回调响应 `stream` + 轮询刷新 |
127
235
  | 流式体验 | 多条消息模拟增量 | 原生 stream 协议 |
236
+ | 思考展示 | 不适用 | 支持 `<think>` 标签映射到 `thinking_content` |
128
237
  | 出站媒体(图/语音/视频/文件) | 支持 | 支持(`active_stream msg_item(image)` + `response_url/Webhook` 回包,video 自动按 file 回传) |
129
238
  | 典型场景 | 标准企业应用、菜单/回调体系 | 对话机器人、连续流式问答 |
130
239
 
@@ -149,7 +258,15 @@ npm run wecom:selfcheck -- --all-accounts
149
258
 
150
259
  ## 安装与加载
151
260
 
152
- ### 方式 A:本地路径加载(推荐)
261
+ ### 方式 A:通过 OpenClaw 安装(推荐)
262
+
263
+ ```bash
264
+ openclaw plugins install @dingxiang-me/openclaw-wechat
265
+ ```
266
+
267
+ 安装后插件会进入 `~/.openclaw/extensions/openclaw-wechat/`。这个目录主要用于 OpenClaw 运行时发现插件,通常**不建议**直接手改其中的 `package.json`、`package-lock.json`、`openclaw.plugin.json`。
268
+
269
+ ### 方式 B:本地路径加载(开发模式)
153
270
 
154
271
  ```bash
155
272
  git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
@@ -176,11 +293,45 @@ npm install
176
293
  }
177
294
  ```
178
295
 
179
- ### 方式 B:npm 安装(包发布后)
296
+ ## 配置文件与路径职责
180
297
 
181
- ```bash
182
- openclaw plugins install @dingxiang-me/openclaw-wechat
183
- ```
298
+ Issue #25 里问到的几个路径,职责完全不同。先把边界理清:
299
+
300
+ | 路径 | 应不应该手改 | 作用 |
301
+ |---|---|---|
302
+ | `~/.openclaw/openclaw.json` | **应该** | OpenClaw 主配置入口。插件加载、`channels.wecom.*`、`bindings`、`env.vars` 都写这里 |
303
+ | `~/.openclaw/extensions/openclaw-wechat/package.json` | 一般不要 | 已安装插件包的元数据,不是业务配置入口 |
304
+ | `~/.openclaw/extensions/openclaw-wechat/openclaw.plugin.json` | 一般不要 | 插件 manifest / schema,供 OpenClaw 识别配置结构 |
305
+ | `~/.openclaw/extensions/openclaw-wechat/package-lock.json` | 不要 | 安装锁文件,不承载运行配置 |
306
+ | `~/.openclaw/agents/<id>/sessions/sessions.json` | 不要 | 运行时会话索引,属于状态数据,不是配置文件 |
307
+ | `~/.openclaw/agents/<id>/sessions/*.jsonl` | 不要 | 会话 transcript / 运行产物 |
308
+
309
+ Windows 对应关系也是同一套逻辑,例如:
310
+
311
+ | Windows 示例路径 | 结论 |
312
+ |---|---|
313
+ | `D:\\Win\\AppData\\LocalLow\\.openclaw\\openclaw.json` | 这是主配置文件,参数加这里 |
314
+ | `D:\\Win\\AppData\\LocalLow\\.openclaw\\extensions\\openclaw-wechat\\openclaw.plugin.json` | 这是插件 schema,不是让你填业务参数的地方 |
315
+ | `D:\\Win\\AppData\\LocalLow\\.openclaw\\agents\\main\\sessions\\sessions.json` | 这是运行态索引,不要手动写参数 |
316
+
317
+ ### 参数应该放到哪里
318
+
319
+ | 参数类型 | 推荐位置 |
320
+ |---|---|
321
+ | 插件启用 / 加载 | `plugins.enabled`、`plugins.allow`、`plugins.entries.openclaw-wechat` |
322
+ | 企业微信业务配置 | `channels.wecom.*` |
323
+ | 多账号配置 | `channels.wecom.accounts.<id>.*` |
324
+ | 文档工具默认账号 | `channels.wecom.defaultAccount` |
325
+ | 账号到 Agent 路由 | OpenClaw 根配置 `bindings` |
326
+ | 敏感信息 | 优先 `env.vars.*` 或系统环境变量;其次写入 `openclaw.json` |
327
+
328
+ ### Control UI、文件、环境变量怎么分工
329
+
330
+ | 方式 | 适合什么 |
331
+ |---|---|
332
+ | Control UI | 日常调整常规字段:`corpId`、`callbackToken`、`accounts.*`、`tools.doc` |
333
+ | `openclaw.json` | 结构化配置、版本管理、多人协作、`bindings` |
334
+ | `env.vars` / 系统环境变量 | Secret、代理、不同环境下的覆盖项 |
184
335
 
185
336
  ## 快速开始
186
337
 
@@ -239,6 +390,26 @@ openclaw plugins install @dingxiang-me/openclaw-wechat
239
390
  }
240
391
  ```
241
392
 
393
+ #### Bot 长连接最小可用(无需公网 Bot 回调)
394
+
395
+ ```json
396
+ {
397
+ "channels": {
398
+ "wecom": {
399
+ "enabled": true,
400
+ "bot": {
401
+ "enabled": true,
402
+ "longConnection": {
403
+ "enabled": true,
404
+ "botId": "your-bot-id",
405
+ "secret": "your-bot-secret"
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ ```
412
+
242
413
  ### 3) 启动与验证
243
414
 
244
415
  ```bash
@@ -261,6 +432,127 @@ node ./scripts/wecom-selfcheck.mjs --help
261
432
  node ./scripts/wecom-bot-selfcheck.mjs --help
262
433
  ```
263
434
 
435
+ ## 文档工具(WeCom Doc)
436
+
437
+ 插件现在内置了 `wecom_doc` 工具,不需要额外安装第二个插件。它复用当前 `OpenClaw-Wechat` 的账号、代理和多账户配置。
438
+
439
+ 当前 `wecom_doc` 重点覆盖创建、权限、分享、收集表和诊断能力;**不包含富文本正文编辑器式的文档内容编辑**。如果需要改正文,请先在产品描述里明确这是后续能力,不要按“已支持编辑”对外承诺。
440
+
441
+ ### 支持的动作
442
+
443
+ | action | 说明 | 关键参数 |
444
+ |---|---|---|
445
+ | `create` | 新建文档/表格,可创建后立即授权 | `docName` `docType` `viewers?` `collaborators?` |
446
+ | `rename` | 重命名文档 | `docId` `newName` |
447
+ | `get_info` | 获取文档基础信息 | `docId` |
448
+ | `share` | 获取文档分享信息 | `docId` |
449
+ | `get_auth` | 获取文档权限信息 | `docId` |
450
+ | `diagnose_auth` | 诊断为什么打不开文档/链接 | `docId` |
451
+ | `validate_share_link` | 校验分享链接对 guest/外部访问是否可用 | `shareUrl` |
452
+ | `delete` | 删除文档或收集表 | `docId` 或 `formId` |
453
+ | `grant_access` | 批量增删查看人/协作者 | `docId` `viewers?` `collaborators?` `remove*?` |
454
+ | `add_collaborators` | 快速添加协作者 | `docId` `collaborators` |
455
+ | `set_join_rule` | 修改文档可见范围/加入规则 | `docId` `request` |
456
+ | `set_member_auth` | 修改文档通知成员与权限 | `docId` `request` |
457
+ | `set_safety_setting` | 修改文档安全设置 | `docId` `request` |
458
+ | `create_collect` | 创建收集表 | `formInfo` `spaceId?` `fatherId?` |
459
+ | `modify_collect` | 修改收集表 | `oper` `formId` `formInfo` |
460
+ | `get_form_info` | 获取收集表定义 | `formId` |
461
+ | `get_form_answer` | 获取收集表答案 | `repeatedId` `answerIds?` |
462
+ | `get_form_statistic` | 获取收集表统计 | `requests` |
463
+ | `get_sheet_properties` | 获取在线表格属性 | `docId` |
464
+
465
+ ### 启用方式
466
+
467
+ 默认启用。你也可以显式配置:
468
+
469
+ ```json
470
+ {
471
+ "channels": {
472
+ "wecom": {
473
+ "defaultAccount": "docs",
474
+ "tools": {
475
+ "doc": true,
476
+ "docAutoGrantRequesterCollaborator": true
477
+ },
478
+ "accounts": {
479
+ "docs": {
480
+ "corpId": "wwxxxx",
481
+ "corpSecret": "xxxx",
482
+ "agentId": 1000008,
483
+ "tools": {
484
+ "doc": true
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ ```
492
+
493
+ ### 账号选择规则
494
+
495
+ `wecom_doc` 在执行时按下面顺序选择账号:
496
+
497
+ 1. 工具参数里的 `accountId`
498
+ 2. 当前 agent 绑定账号
499
+ 3. `channels.wecom.defaultAccount`
500
+ 4. 第一个启用了文档工具的可用账号
501
+
502
+ ### 创建后自动授权
503
+
504
+ 默认开启:如果 `wecom_doc` 是在企业微信会话里被调用,插件会把当前发送者自动加成文档协作者,避免“文档已创建但发起人无权限查看”。
505
+
506
+ `create` / `share` 结果现在会明确返回真实 `docId`,后续做权限、分享和诊断时应优先使用这个 `docId`,不要直接拿分享链接路径里的片段代替。
507
+
508
+ 可关闭:
509
+
510
+ ```json
511
+ {
512
+ "channels": {
513
+ "wecom": {
514
+ "tools": {
515
+ "doc": true,
516
+ "docAutoGrantRequesterCollaborator": false
517
+ }
518
+ }
519
+ }
520
+ }
521
+ ```
522
+
523
+ ### 使用示例
524
+
525
+ - “帮我新建一个企微文档,标题是《周会纪要》”
526
+ - “把这个文档改名为《Q2 Roadmap》”
527
+ - “查询文档 `docxxxx` 的权限信息”
528
+ - “诊断为什么这个企微文档链接打不开”
529
+ - “校验这个企微文档分享链接为什么对外打不开”
530
+ - “创建一个企微文档,并把我加成协作者”
531
+ - “给文档 `docxxxx` 添加协作者 `dingxiang`”
532
+ - “把文档 `docxxxx` 授权给 `alice` 查看,给 `bob` 协作”
533
+ - “把文档 `docxxxx` 的查看规则改成仅企业内部可见”
534
+ - “创建一个收集表,标题是《报名表》”
535
+ - “查询收集表 `formxxxx` 的定义和题目”
536
+ - “读取这份收集表最近一次提交答案”
537
+ - “获取这个表格的 sheet 属性”
538
+
539
+ ### 推荐工作流
540
+
541
+ | 目标 | 推荐动作顺序 |
542
+ |---|---|
543
+ | 创建后立刻给业务同事协作 | `create` -> `grant_access` / `add_collaborators` |
544
+ | 判断“为什么别人打不开这个文档” | `diagnose_auth` -> `validate_share_link` |
545
+ | 给外部链接排障 | 先看 `validate_share_link`,再决定是否执行 `set_join_rule` |
546
+ | 后续继续操作同一文档 | 始终使用 `create/share` 返回的真实 `docId`,不要直接复制分享链接路径片段 |
547
+
548
+ ### 常见误区
549
+
550
+ | 误区 | 正确做法 |
551
+ |---|---|
552
+ | 分享链接路径里的 ID 就是 `docId` | 不一定。以后续工具返回的真实 `docId` 为准 |
553
+ | “加了协作者”就等于任何浏览器都能打开 | 不是。协作者权限、企业内访问、企业外访问、外部分享是不同层级 |
554
+ | 链接能在企业微信里打开,就代表外部环境也能打开 | 不成立。`guest` 视角可能仍然是 `blankpage` |
555
+
264
556
  ## 配置参考
265
557
 
266
558
  ### 主配置键(`channels.wecom`)
@@ -276,6 +568,8 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
276
568
  | `webhookPath` | string | `/wecom/callback` | Agent 回调路径(非 default 账户未配置时自动生成 `/wecom/<accountId>/callback`) |
277
569
  | `agent` | object | - | 兼容旧配置:`agent.corpId/corpSecret/agentId`(与顶层 Agent 字段等价) |
278
570
  | `outboundProxy` | string | - | WeCom 出站代理 |
571
+ | `defaultAccount` | string | - | 多账号下的默认账号 ID(文档工具等优先使用) |
572
+ | `tools.doc` | boolean | `true` | 是否启用 `wecom_doc` 文档工具 |
279
573
  | `webhooks` | object | - | 命名 Webhook 目标映射(如 `{ "ops": "https://...key=xxx" }`) |
280
574
  | `accounts` | object | - | 多账户配置(支持 `accounts.<id>.bot` 独立 Bot 配置) |
281
575
 
@@ -297,11 +591,31 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
297
591
  | `replyTimeoutMs` | integer | `90000` | Bot 等待模型回包超时(15s~10m) |
298
592
  | `lateReplyWatchMs` | integer | `180000` | Bot 超时后异步补发观察窗口(30s~10m) |
299
593
  | `lateReplyPollMs` | integer | `2000` | Bot 异步补发轮询间隔(500ms~10s) |
594
+ | `longConnection` | object | - | 企业微信智能机器人长连接(WebSocket)配置 |
300
595
  | `card` | object | 见下方 | Bot 卡片回包策略(`response_url` / `webhook_bot`) |
301
596
 
302
597
  > 重要限制:企业微信官方 Bot 在群聊里通常仅对 `@机器人` 消息触发回调。
303
598
  > 因此 Bot 模式下即使配置 `groupChat.triggerMode=direct/keyword`,也会按 `mention` 处理(插件会输出告警)。
304
599
 
600
+ #### Bot 长连接配置(`channels.wecom.bot.longConnection`)
601
+
602
+ | 键 | 类型 | 默认 | 说明 |
603
+ |---|---|---|---|
604
+ | `enabled` | boolean | `false` | 启用企业微信智能机器人长连接 |
605
+ | `botId` | string | - | 企业微信智能机器人 BotID |
606
+ | `secret` | string | - | 企业微信智能机器人 Secret(敏感) |
607
+ | `url` | string | `wss://openws.work.weixin.qq.com` | 官方长连接地址 |
608
+ | `pingIntervalMs` | integer | `30000` | 心跳 `ping` 间隔 |
609
+ | `reconnectDelayMs` | integer | `5000` | 首次重连延迟 |
610
+ | `maxReconnectDelayMs` | integer | `60000` | 指数退避最大重连延迟 |
611
+
612
+ 说明:
613
+
614
+ - 长连接模式下不需要暴露公网 Bot 回调地址。
615
+ - 插件会在网关启动后主动连接 `wss://openws.work.weixin.qq.com`,并自动发送 `aibot_subscribe`。
616
+ - 入站消息与事件分别使用 `aibot_msg_callback` / `aibot_event_callback`,统一接入现有 Bot 处理链路。
617
+ - 模型 block 输出会直接通过长连接发送 `aibot_respond_msg`,不是被动等待 `stream-refresh` 拉取。
618
+
305
619
  #### Bot 卡片配置(`channels.wecom.bot.card`)
306
620
 
307
621
  | 键 | 类型 | 默认 | 说明 |
@@ -330,7 +644,14 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
330
644
  | `replyTimeoutMs` | integer | `90000` | Bot 等待模型回包超时 |
331
645
  | `lateReplyWatchMs` | integer | `180000` | 超时后异步补发观察窗口 |
332
646
  | `lateReplyPollMs` | integer | `2000` | 异步补发轮询间隔 |
647
+ | `longConnection` | object | - | 该账户专用长连接配置(覆盖全局 `bot.longConnection`) |
333
648
  | `card` | object | - | 该账户专用卡片回包配置(覆盖全局 `bot.card`) |
649
+
650
+ ### 多账户文档工具覆盖(`channels.wecom.accounts.<id>.tools`)
651
+
652
+ | 键 | 类型 | 默认 | 说明 |
653
+ |---|---|---|---|
654
+ | `doc` | boolean | `true` | 是否启用该账户的 `wecom_doc` 工具 |
334
655
  | `outboundProxy` / `proxyUrl` / `proxy` | string | - | 该账户 Bot 专用代理(优先于全局) |
335
656
 
336
657
  ### 授权与指令策略
@@ -413,6 +734,35 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
413
734
  }
414
735
  ```
415
736
 
737
+ ### 使用 OpenClaw `bindings` 做账号级 Agent 路由
738
+
739
+ `OpenClaw-Wechat` 不自己实现第二套路由规则;账号到 Agent 的稳定绑定,直接走 OpenClaw 核心 `bindings`。插件会把 `channel=wecom` 和 `accountId=<id>` 传给核心路由层。
740
+
741
+ 示例:
742
+
743
+ ```json
744
+ {
745
+ "bindings": [
746
+ {
747
+ "match": {
748
+ "channel": "wecom",
749
+ "accountId": "sales"
750
+ },
751
+ "agentId": "sales"
752
+ },
753
+ {
754
+ "match": {
755
+ "channel": "wecom",
756
+ "accountId": "support"
757
+ },
758
+ "agentId": "support"
759
+ }
760
+ ]
761
+ }
762
+ ```
763
+
764
+ 这套绑定优先级高于插件里的动态账号猜测,适合多账号、多业务线、同一 OpenClaw 上挂多个 WeCom 入口的场景。
765
+
416
766
  ## 消息能力矩阵
417
767
 
418
768
  ### Agent 模式
@@ -452,7 +802,8 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
452
802
 
453
803
  ### 会话策略
454
804
 
455
- - 默认一用户一会话:`wecom:<userid>`
805
+ - 默认账号一用户一会话:`wecom:<userid>`
806
+ - 非默认账号一用户一会话:`wecom:<accountId>:<userid>`
456
807
  - 群聊可配置“仅 @ 才触发”,避免误触发
457
808
 
458
809
  ### 出站目标格式
@@ -532,6 +883,219 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
532
883
  | `WECOM_VOICE_TRANSCRIBE_FFMPEG_ENABLED` | 是否允许 ffmpeg 转码 |
533
884
  | `WECOM_VOICE_TRANSCRIBE_TRANSCODE_TO_WAV` | 是否优先转 WAV |
534
885
 
886
+ ## 公网回调与 Gateway Auth
887
+
888
+ ### 目标
889
+
890
+ 企业微信访问你的回调地址时,必须直接命中 OpenClaw 网关的 webhook 路由。
891
+ 不能被这些中间层拦住:
892
+
893
+ - Gateway Auth / Token 鉴权
894
+ - 反向代理登录页 / SSO
895
+ - 前端 WebUI 路由
896
+ - 另一台静态站点或错误 upstream
897
+
898
+ ### 推荐架构
899
+
900
+ | 场景 | 推荐做法 |
901
+ |---|---|
902
+ | 单域名 | 将 `/wecom/*`、legacy `/webhooks/app*`、`/webhooks/wecom*` 单独反代到 OpenClaw 网关端口 |
903
+ | 有 Gateway Auth / Zero Trust | 对上述 webhook 路径做认证豁免,不要求 Authorization/Cookie |
904
+ | 前端与网关共用域名 | 前端只接管 `/ui`、静态资源等路径,不要吞掉 `/wecom/*` |
905
+ | 最稳妥 | 单独给企微回调使用一个子域名,只代理到 OpenClaw |
906
+
907
+ ### 最小验证
908
+
909
+ | 探测 | 预期 |
910
+ |---|---|
911
+ | `curl -i http://127.0.0.1:8885/wecom/callback` | `200` + `wecom webhook ok` |
912
+ | `curl -i http://127.0.0.1:8885/wecom/bot/callback` | `200` + `wecom bot webhook ok` |
913
+ | `curl -i https://你的域名/wecom/callback` | 与本机一致,不应返回 HTML、401/403 或跳转 |
914
+ | `curl -i https://你的域名/wecom/bot/callback` | 与本机一致,不应返回 HTML、401/403 或跳转 |
915
+
916
+ ### 常见返回值的含义
917
+
918
+ | 现象 | 结论 | 处理 |
919
+ |---|---|---|
920
+ | `200` + `wecom webhook ok` / `wecom bot webhook ok` | 路由命中正常 | 继续做 URL 验证与企业微信后台配置 |
921
+ | `200` + HTML | 请求被前端/WebUI 接走 | 单独为 `/wecom/*` 配反代,不要落到前端 |
922
+ | `401/403` | 被 Gateway Auth / Zero Trust / 反代鉴权拦截 | 为 webhook 路径放行认证 |
923
+ | `301/302/307/308` | 被登录页、SSO 或前端路由重定向 | 取消 webhook 路径重定向,直接代理到网关 |
924
+ | `502/503/504` | OpenClaw 网关端口不可达 | 先修网关存活与 upstream |
925
+ | `404` | 路径写错或插件路由没注册 | 核对 `webhookPath`、插件启用状态和 legacy alias |
926
+
927
+ ### 反代示例(Nginx)
928
+
929
+ ```nginx
930
+ server {
931
+ listen 443 ssl http2;
932
+ server_name wecom.example.com;
933
+
934
+ location /wecom/ {
935
+ proxy_pass http://127.0.0.1:8885;
936
+ proxy_http_version 1.1;
937
+ proxy_set_header Host $host;
938
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
939
+ proxy_set_header X-Forwarded-Proto $scheme;
940
+ }
941
+
942
+ location /webhooks/app {
943
+ proxy_pass http://127.0.0.1:8885;
944
+ }
945
+
946
+ location /webhooks/wecom {
947
+ proxy_pass http://127.0.0.1:8885;
948
+ }
949
+ }
950
+ ```
951
+
952
+ ### Cloudflare Tunnel 示例
953
+
954
+ ```yaml
955
+ ingress:
956
+ - hostname: wecom.example.com
957
+ service: http://127.0.0.1:8885
958
+ - service: http_status:404
959
+ ```
960
+
961
+ 建议把企微回调放到单独子域名,不要和前端登录页共用同一套路由规则。
962
+
963
+ ### 自检建议
964
+
965
+ ```bash
966
+ npm run wecom:selfcheck -- --all-accounts
967
+ npm run wecom:agent:selfcheck -- --all-accounts
968
+ npm run wecom:bot:selfcheck -- --all-accounts
969
+ npm run wecom:callback:matrix -- --agent-url https://你的域名/wecom/callback --bot-url https://你的域名/wecom/bot/callback
970
+ ```
971
+
972
+ 现在自检会明确提示这些原因:
973
+
974
+ - `route-not-found`
975
+ - `html-fallback`
976
+ - `gateway-auth`
977
+ - `redirect-auth`
978
+ - `gateway-unreachable`
979
+
980
+ 如果你要把新路径和 legacy alias 一次跑完,直接用:
981
+
982
+ ```bash
983
+ npm run wecom:callback:matrix -- \
984
+ --agent-url https://你的域名/wecom/callback \
985
+ --bot-url https://你的域名/wecom/bot/callback \
986
+ --agent-legacy-url https://你的域名/webhooks/app \
987
+ --bot-legacy-url https://你的域名/webhooks/wecom
988
+ ```
989
+
990
+ ## Webhook 与 Heartbeat 运维
991
+
992
+ ### 适用场景
993
+
994
+ | 需求 | 推荐方式 |
995
+ |---|---|
996
+ | 手工发一条群通知 | `openclaw message send --channel wecom --target webhook:<name>` |
997
+ | 让 agent 处理后发到群 | `openclaw agent --deliver --reply-channel wecom --reply-to webhook:<name>` |
998
+ | 固定周期发摘要/巡检结果 | OpenClaw `agents.defaults.heartbeat` + `target: "wecom"` + `to: "webhook:<name>"` |
999
+
1000
+ ### 先配置命名 Webhook
1001
+
1002
+ ```json
1003
+ {
1004
+ "channels": {
1005
+ "wecom": {
1006
+ "webhooks": {
1007
+ "ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx",
1008
+ "dev": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy"
1009
+ }
1010
+ }
1011
+ }
1012
+ }
1013
+ ```
1014
+
1015
+ 多账号时,也可以挂到 `channels.wecom.accounts.<id>.webhooks`。
1016
+
1017
+ ### 直接发送
1018
+
1019
+ ```bash
1020
+ openclaw message send --channel wecom --target webhook:ops --message "服务已恢复正常"
1021
+ ```
1022
+
1023
+ ### 让 Agent 结果投递到群
1024
+
1025
+ ```bash
1026
+ openclaw agent \
1027
+ --message "整理今天的告警摘要" \
1028
+ --deliver \
1029
+ --reply-channel wecom \
1030
+ --reply-to webhook:ops
1031
+ ```
1032
+
1033
+ ### 用 Heartbeat 定时投递到群
1034
+
1035
+ 当前机器上的 OpenClaw `2026.3.2` 支持把 heartbeat 直接投递到指定渠道和目标。
1036
+ 对 WeCom Webhook 的推荐写法是:
1037
+
1038
+ ```json
1039
+ {
1040
+ "channels": {
1041
+ "wecom": {
1042
+ "webhooks": {
1043
+ "ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
1044
+ }
1045
+ }
1046
+ },
1047
+ "agents": {
1048
+ "defaults": {
1049
+ "heartbeat": {
1050
+ "every": "30m",
1051
+ "target": "wecom",
1052
+ "to": "webhook:ops",
1053
+ "prompt": "检查网关状态、最近告警和企业微信通道健康;如果一切正常,以三行内摘要输出。",
1054
+ "ackMaxChars": 300
1055
+ }
1056
+ }
1057
+ }
1058
+ }
1059
+ ```
1060
+
1061
+ 多账号 webhook 场景可以再加:
1062
+
1063
+ ```json
1064
+ {
1065
+ "agents": {
1066
+ "defaults": {
1067
+ "heartbeat": {
1068
+ "target": "wecom",
1069
+ "to": "webhook:ops",
1070
+ "accountId": "sales"
1071
+ }
1072
+ }
1073
+ }
1074
+ }
1075
+ ```
1076
+
1077
+ 说明:
1078
+
1079
+ - `target: "wecom"` 指定投递到 WeCom 渠道
1080
+ - `to: "webhook:ops"` 指定 WeCom 渠道里的命名 webhook 目标
1081
+ - `accountId` 只在多账号场景需要
1082
+ - 如果不设 `target`,heartbeat 默认运行但不会向外发送消息
1083
+
1084
+ ### 运维常用命令
1085
+
1086
+ ```bash
1087
+ openclaw system heartbeat last
1088
+ openclaw config get agents.defaults.heartbeat
1089
+ openclaw status --deep
1090
+ openclaw logs --follow
1091
+ ```
1092
+
1093
+ 需要手工触发一次立即执行:
1094
+
1095
+ ```bash
1096
+ openclaw system event --mode now --text "立即执行下一轮运维心跳"
1097
+ ```
1098
+
535
1099
  ## 与其他渠道并存建议
536
1100
 
537
1101
  建议固定以下三点,减少“偶发无回复/冲突”风险:
@@ -549,11 +1113,16 @@ node ./scripts/wecom-bot-selfcheck.mjs --help
549
1113
  | 现象 | 先看什么 | 常见原因 | 处理建议 |
550
1114
  |---|---|---|---|
551
1115
  | 回调验证失败 | `curl https://域名/wecom/callback` | URL 不通、Token/AESKey 不一致 | 先通公网,再核对配置 |
1116
+ | `curl` 到公网回调是 `200`,但企业微信后台仍提示 `openapi回调地址请求不通过` | 企业微信后台校验 | 临时隧道域名、不受信任公网域名、企业侧域名策略或回调链路仍被中间层改写 | 优先换成稳定公网域名;不要把 `trycloudflare.com` 之类临时域名当正式 Agent 回调地址 |
552
1117
  | `curl /wecom/callback` 返回 WebUI 页面 | 反向代理路由与回调路径 | 域名把 `/wecom/callback` 转发到了前端/静态站点 | 单独为 `/wecom/*` 配置反向代理到 OpenClaw 网关端口 |
1118
+ | `curl https://域名/wecom/callback` 返回 `401/403` | Gateway Auth / Zero Trust / 反代鉴权 | webhook 路径被要求登录或带 Token | 对 `/wecom/*`、`/webhooks/app*`、`/webhooks/wecom*` 做认证豁免 |
1119
+ | `curl https://域名/wecom/callback` 返回 `301/302/307/308` | 登录跳转 / SSO / 前端路由 | webhook 被重定向到登录页或前端 | 让 webhook 路径直接反代到 OpenClaw 网关 |
553
1120
  | 能收到消息但不回复 | `openclaw gateway status` + `openclaw logs --follow` | 模型超时、会话排队、权限策略拦截 | 查看 dispatch/allowFrom/commands 日志 |
1121
+ | 能收到消息但不回复(已确认本地日志正常) | 企业微信自建应用后台 -> 开发设置 | 未配置“可信 IP”,企业微信拒绝部分回调/发送链路 | 在应用里补充 OpenClaw 出网 IP 到可信 IP 列表(保存后重试) |
554
1122
  | Bot 图片识别失败 | `wecom(bot): failed to fetch image url` | URL 失效、返回非图像流 | 已支持 octet-stream+解密兜底,先升级到最新版本 |
555
1123
  | 语音转写失败 | `wecom: voice transcription failed` | 本地命令或模型路径错误 | 检查 `command`、`modelPath`、`ffmpeg` |
556
1124
  | 启动出现账号体检告警 | `wecom: account diagnosis ...` | 多账号 Token/Agent/路径存在冲突风险 | 按日志 `code` 与账户列表调整配置,优先处理 `warn` 级别 |
1125
+ | `wecom:selfcheck -- --all-accounts` 提示 `account '<id>' not found or incomplete` | 账号配置结构 | 旧版本自检脚本没完全识别 `agent` 子块、legacy inline 账户,或账号字段确实缺失 | 升级到最新版本后重跑;再核对 `channels.wecom.accounts.<id>` 是否包含完整 Agent 凭据 |
557
1126
  | gettoken 失败 | 企业微信 API 返回码 | CorpId/Secret 错或网络受限 | 检查凭据/配置代理 |
558
1127
 
559
1128
  ### 推荐检查命令
@@ -563,7 +1132,7 @@ openclaw gateway status
563
1132
  openclaw status --deep
564
1133
  openclaw logs --follow
565
1134
  npm run wecom:selfcheck -- --all-accounts
566
- npm run wecom:agent:selfcheck -- --account default
1135
+ npm run wecom:agent:selfcheck -- --all-accounts
567
1136
  npm run wecom:bot:selfcheck -- --all-accounts
568
1137
  ```
569
1138
 
@@ -579,12 +1148,15 @@ npm run wecom:bot:selfcheck -- --all-accounts
579
1148
  | `npm run test:e2e:prepare-browser` | 远程浏览器沙箱就绪检查(可选自动安装 Chromium) |
580
1149
  | `npm run test:e2e:collect-pdf` | 收集远端浏览器沙箱中的 PDF 产物到本地 |
581
1150
  | `npm run wecom:selfcheck -- --all-accounts` | 配置+网络体检 |
582
- | `npm run wecom:agent:selfcheck -- --account <id>` | Agent 端到端链路体检(URL 验证 + 加密 POST) |
1151
+ | `npm run wecom:agent:selfcheck -- --account <id>` | Agent 单账号端到端链路体检(URL 验证 + 加密 POST) |
1152
+ | `npm run wecom:agent:selfcheck -- --all-accounts` | Agent 多账号端到端链路体检(逐账号跑 URL 验证 + 加密 POST) |
583
1153
  | `npm run wecom:bot:selfcheck -- --account <id>` | Bot 端到端链路体检(URL 验证/签名/加密/stream-refresh,支持多账户) |
1154
+ | `npm run wecom:callback:matrix -- --agent-url <公网Agent回调> --bot-url <公网Bot回调>` | 公网回调矩阵体检(可附带 legacy alias URL) |
584
1155
  | `npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调>` | 远端矩阵验证(Agent+Bot) |
585
1156
  | `npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调> --prepare-browser --collect-pdf` | 远端矩阵验证(含浏览器沙箱检查与 PDF 回收) |
586
1157
  | `WECOM_E2E_BOT_URL=<...> WECOM_E2E_AGENT_URL=<...> npm run wecom:remote:e2e -- --mode all` | 用环境变量驱动远端 E2E(兼容旧 `E2E_WECOM_*`) |
587
1158
  | `npm run wecom:e2e:scenario -- --scenario full-smoke --agent-url <公网Agent回调> --bot-url <公网Bot回调>` | 场景化 E2E(预置 smoke/queue 场景) |
1159
+ | `npm run wecom:e2e:scenario -- --scenario callback-matrix --agent-url <公网Agent回调> --bot-url <公网Bot回调>` | 只做公网回调矩阵检查 |
588
1160
  | `npm run wecom:e2e:scenario -- --scenario compat-smoke --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调>` | 兼容矩阵验证(新旧回调地址都跑一遍) |
589
1161
  | `npm run wecom:e2e:scenario -- --scenario matrix-smoke --bot-url <公网Bot回调>` | Bot 协议矩阵验证(验签/异常请求/stream-refresh/去重;需 `WECOM_BOT_TOKEN/WECOM_BOT_ENCODING_AES_KEY`) |
590
1162
  | `npm run wecom:e2e:compat -- --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调>` | 兼容矩阵快捷命令(等价 `--scenario compat-smoke`) |
@@ -609,10 +1181,15 @@ npm run wecom:bot:selfcheck -- --all-accounts
609
1181
  ### Q2:为什么图片偶发识别失败?
610
1182
  企业微信可能返回非标准 `content-type` 或加密媒体流。插件已增加类型识别与解密兜底;仍失败时请查看日志中的 header/下载错误。
611
1183
 
612
- ### Q3:Telegram 和 WeCom 会互相影响吗?
1184
+ ### Q3:能收消息但一直不回复,日志看起来也正常?
1185
+ 优先检查企业微信自建应用后台是否配置了**可信 IP**。如果可信 IP 缺失,企业微信可能在发送/回调链路上做安全拦截,表现为“能收到但不回”。
1186
+
1187
+ 建议:把 OpenClaw 网关实际出网 IP 加入该应用的可信 IP 列表,保存后重试。
1188
+
1189
+ ### Q4:Telegram 和 WeCom 会互相影响吗?
613
1190
  理论上独立;实战中若复用 webhook 路径、多进程抢占、或 `plugins.allow` 未收紧,会出现干扰。按“并存建议”配置可大幅降低风险。
614
1191
 
615
- ### Q4:支持个人微信吗?
1192
+ ### Q5:支持个人微信吗?
616
1193
  支持企业微信场景下的“微信插件入口”(个人微信扫码进入企业应用对话),不等同于“个人微信网页版协议”。
617
1194
 
618
1195
  ### Q4.1:为什么 Bot 模式在“微信插件入口”里看不到机器人联系人?
@@ -634,6 +1211,20 @@ npm run wecom:bot:selfcheck -- --all-accounts
634
1211
  2. 公网验证:`curl -i https://你的域名/wecom/callback`
635
1212
  3. 代理配置:为 `/wecom/*` 单独反代到 OpenClaw 网关端口,不要落到 WebUI 路由
636
1213
 
1214
+ ### Q5.1:为什么本机和公网 `curl` 都是 `200 wecom webhook ok`,企业微信后台仍提示 `openapi回调地址请求不通过`?
1215
+ 这说明“你的路由打通了”,但**还不能证明企业微信后台会接受这条回调地址**。
1216
+
1217
+ 常见根因:
1218
+ 1. 用了临时公网域名,例如 `trycloudflare.com`
1219
+ 2. 企业侧要求更稳定/更受信任的公网域名
1220
+ 3. 你的回调链路虽然 `curl` 是 `200`,但企业微信实际校验时仍遇到了中间层改写
1221
+
1222
+ 明确建议:
1223
+ 1. 自建应用正式回调地址优先用你自己的稳定公网域名
1224
+ 2. 不要把 `trycloudflare.com` 这类临时隧道域名当正式 Agent 回调地址
1225
+ 3. 继续确认该域名的 `/wecom/callback` 没有鉴权、跳转、前端兜底和缓存层干扰
1226
+ 4. 如果只是想快速群聊验证,Bot/Webhook 路径通常比自建应用回调更容易先跑通
1227
+
637
1228
  ### Q6:自建应用群聊怎么开?为什么群里不 @ 就不触发?
638
1229
  先区分两种通道能力:
639
1230
  1. **群机器人(Webhook Bot)**:可直接添加到企微群,天然适合群聊收发;但群聊通常仅 `@机器人` 时才会回调。
@@ -662,6 +1253,23 @@ npm run wecom:bot:selfcheck -- --all-accounts
662
1253
 
663
1254
  若你在企微侧只能给群添加“机器人”而不能添加“自建应用”,这不是插件配置问题,属于企微产品形态差异;建议走 Bot 模式承载群聊,自建应用用于私聊/应用会话/主动推送。
664
1255
 
1256
+ ### Q7:多账号创建了两个 agent,但只有一个回复,或者会话串了?
1257
+
1258
+ 这是多账号隔离问题,不是“企微互相干扰”。
1259
+
1260
+ 从当前版本开始:
1261
+
1262
+ 1. Agent 会话 key 已按账号隔离
1263
+ 2. `wecom:selfcheck -- --all-accounts` 会识别 `accounts.<id>`、`agent` 子块、legacy inline 账户
1264
+ 3. `bindings.match.channel=wecom + accountId=<id>` 可以把不同账号稳定路由到不同 Agent
1265
+
1266
+ 建议排查顺序:
1267
+
1268
+ 1. 跑 `npm run wecom:selfcheck -- --all-accounts`
1269
+ 2. 确认每个账号 `config.account` 都是 `OK`
1270
+ 3. 在 `openclaw.json` 中为多账号配置 `bindings`
1271
+ 4. 确认会话 key 形态符合预期:默认账号为 `wecom:<userid>`;非默认账号为 `wecom:<accountId>:<userid>`
1272
+
665
1273
  ## 版本与贡献
666
1274
 
667
1275
  - 版本记录:[`CHANGELOG.md`](./CHANGELOG.md)