@yanhaidao/wecom 2.3.260 → 2.4.120
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.
- package/MENU_EVENT_CONF.md +500 -0
- package/MENU_EVENT_PLAN.md +440 -0
- package/README.md +90 -8
- package/UPSTREAM_CONFIG.md +170 -0
- package/UPSTREAM_PLAN.md +175 -0
- package/changelog/v2.3.27.md +33 -0
- package/changelog/v2.4.12.md +37 -0
- package/index.test.ts +5 -1
- package/package.json +17 -17
- package/scripts/wecom/README.md +123 -0
- package/scripts/wecom/menu-click-help.js +59 -0
- package/scripts/wecom/menu-click-help.py +55 -0
- package/src/agent/event-router.test.ts +421 -0
- package/src/agent/event-router.ts +272 -0
- package/src/agent/handler.event-filter.test.ts +65 -1
- package/src/agent/handler.ts +375 -21
- package/src/agent/script-runner.ts +186 -0
- package/src/agent/test-fixtures/invalid-json-script.mjs +1 -0
- package/src/agent/test-fixtures/reply-event-script.mjs +29 -0
- package/src/agent/test-fixtures/reply-event-script.py +17 -0
- package/src/app/account-runtime.ts +1 -1
- package/src/app/index.ts +6 -3
- package/src/capability/agent/upstream-delivery-service.ts +96 -0
- package/src/capability/bot/sandbox-media.test.ts +221 -0
- package/src/capability/bot/sandbox-media.ts +176 -0
- package/src/capability/bot/stream-orchestrator.ts +19 -0
- package/src/capability/mcp/tool.ts +7 -3
- package/src/channel.config.test.ts +33 -0
- package/src/channel.meta.test.ts +14 -0
- package/src/channel.ts +33 -60
- package/src/config/accounts.ts +16 -0
- package/src/config/schema.ts +58 -0
- package/src/context-store.ts +41 -8
- package/src/onboarding.test.ts +42 -24
- package/src/onboarding.ts +598 -553
- package/src/outbound.test.ts +211 -2
- package/src/outbound.ts +340 -81
- package/src/runtime/session-manager.test.ts +39 -0
- package/src/runtime/session-manager.ts +17 -0
- package/src/runtime/source-registry.ts +5 -0
- package/src/shared/media-asset.ts +78 -0
- package/src/shared/media-service.test.ts +111 -0
- package/src/shared/media-service.ts +42 -14
- package/src/target.ts +40 -0
- package/src/transport/agent-api/client.ts +233 -0
- package/src/transport/agent-api/core.ts +101 -5
- package/src/transport/agent-api/upstream-delivery.ts +45 -0
- package/src/transport/agent-api/upstream-media-upload.ts +70 -0
- package/src/transport/agent-api/upstream-reply.ts +43 -0
- package/src/transport/bot-ws/media.test.ts +8 -8
- package/src/transport/bot-ws/media.ts +51 -2
- package/src/transport/bot-ws/sdk-adapter.ts +6 -6
- package/src/types/account.ts +2 -0
- package/src/types/config.ts +74 -0
- package/src/types/message.ts +2 -0
- package/src/upstream/index.ts +150 -0
- package/src/upstream.test.ts +84 -0
- package/vitest.config.ts +15 -4
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# WeCom 菜单事件可配置回调功能规划(PLAN)
|
|
2
|
+
|
|
3
|
+
## 1. 背景与目标
|
|
4
|
+
|
|
5
|
+
当前插件对 Agent 入站 `event` 使用固定白名单,未覆盖企业微信“菜单事件”全量场景(如 `click`、`view`、`scancode_push`、`location_select` 等)。
|
|
6
|
+
|
|
7
|
+
目标是把“是否放行 event、放行哪些 eventType、由谁处理”从代码硬编码改为可配置:
|
|
8
|
+
|
|
9
|
+
1. 支持在 OpenClaw 配置中声明是否启用 `event` 处理。
|
|
10
|
+
2. 在 `event` 内支持按 `eventType` 白名单(例如只放行 `click`、`scancode_push`)。
|
|
11
|
+
3. 每个事件可绑定处理器(内置 handler / 外部 TS/JS / 外部 Python)。
|
|
12
|
+
4. 默认安全:不配置即保持现有行为兼容,不自动放通新增事件。
|
|
13
|
+
|
|
14
|
+
## 2. 需求范围
|
|
15
|
+
|
|
16
|
+
### 2.1 本期(MVP)
|
|
17
|
+
|
|
18
|
+
1. 菜单点击类事件可配置放通:
|
|
19
|
+
- `click`
|
|
20
|
+
- `view`
|
|
21
|
+
- `view_miniprogram`
|
|
22
|
+
- `scancode_push`
|
|
23
|
+
- `scancode_waitmsg`
|
|
24
|
+
- `pic_sysphoto`
|
|
25
|
+
- `pic_photo_or_album`
|
|
26
|
+
- `pic_weixin`
|
|
27
|
+
- `location_select`
|
|
28
|
+
2. 配置驱动白名单:`eventEnabled` + `eventType`。
|
|
29
|
+
3. 事件分发器:按匹配规则将事件交给指定处理器。
|
|
30
|
+
4. 脚本处理器能力:
|
|
31
|
+
- Node 脚本(TS/JS,先支持 JS,TS 通过 tsx/ts-node 作为可选)
|
|
32
|
+
- Python 脚本
|
|
33
|
+
5. 统一执行输入输出协议(JSON stdin/stdout),并把接收到的 event 参数透传给外部脚本。
|
|
34
|
+
6. 最小可观测能力:审计日志、超时、退出码、错误摘要。
|
|
35
|
+
|
|
36
|
+
### 2.2 后续增强(非 MVP)
|
|
37
|
+
|
|
38
|
+
1. 脚本热更新和缓存。
|
|
39
|
+
2. 并发/速率限制(按事件类型或账号维度)。
|
|
40
|
+
3. 幂等增强(事件去重键可配置)。
|
|
41
|
+
4. 回调重试策略(指数退避 + 死信)。
|
|
42
|
+
5. handler 沙箱隔离(容器/受限用户执行)。
|
|
43
|
+
|
|
44
|
+
## 3. 设计原则
|
|
45
|
+
|
|
46
|
+
1. 兼容优先:未新增配置时,行为与当前版本一致。
|
|
47
|
+
2. 显式放通:只处理配置明确允许的类型。
|
|
48
|
+
3. 最小权限:外部脚本执行能力默认关闭或仅允许受信目录。
|
|
49
|
+
4. 可追踪:每次分发都可在日志中定位“为什么放通/为什么拒绝/由谁处理”。
|
|
50
|
+
5. 可替换:处理器接口稳定,后续可新增 webhook/queue 等执行后端。
|
|
51
|
+
|
|
52
|
+
## 3.1 事件格式盘点(基于文档 90240)
|
|
53
|
+
|
|
54
|
+
按文档事件目录统计,建议全部纳入“可配置支持范围”,默认采用 deny by default(不放通)。
|
|
55
|
+
|
|
56
|
+
### A. 一级事件格式数量
|
|
57
|
+
|
|
58
|
+
共 17 类一级事件格式:
|
|
59
|
+
|
|
60
|
+
1. 成员关注及取消关注事件
|
|
61
|
+
2. 进入应用
|
|
62
|
+
3. 上报地理位置
|
|
63
|
+
4. 异步任务完成事件推送
|
|
64
|
+
5. 通讯录变更事件
|
|
65
|
+
6. 菜单事件
|
|
66
|
+
7. 审批状态通知事件
|
|
67
|
+
8. 企业互联共享应用事件回调
|
|
68
|
+
9. 上下游共享应用事件回调
|
|
69
|
+
10. 模板卡片事件推送
|
|
70
|
+
11. 通用模板卡片右上角菜单事件推送
|
|
71
|
+
12. 长期未使用应用停用预警事件
|
|
72
|
+
13. 长期未使用应用临时停用事件
|
|
73
|
+
14. 长期未使用应用重新启用事件
|
|
74
|
+
15. 应用低活跃预警事件
|
|
75
|
+
16. 低活跃应用事件
|
|
76
|
+
17. 低活跃应用活跃恢复事件
|
|
77
|
+
|
|
78
|
+
### B. Event 字段可枚举值数量
|
|
79
|
+
|
|
80
|
+
共 26 个 Event 值(建议全部支持配置):
|
|
81
|
+
|
|
82
|
+
1. subscribe
|
|
83
|
+
2. unsubscribe
|
|
84
|
+
3. enter_agent
|
|
85
|
+
4. LOCATION
|
|
86
|
+
5. batch_job_result
|
|
87
|
+
6. change_contact
|
|
88
|
+
7. click
|
|
89
|
+
8. view
|
|
90
|
+
9. view_miniprogram
|
|
91
|
+
10. scancode_push
|
|
92
|
+
11. scancode_waitmsg
|
|
93
|
+
12. pic_sysphoto
|
|
94
|
+
13. pic_photo_or_album
|
|
95
|
+
14. pic_weixin
|
|
96
|
+
15. location_select
|
|
97
|
+
16. open_approval_change
|
|
98
|
+
17. share_agent_change
|
|
99
|
+
18. share_chain_change
|
|
100
|
+
19. template_card_event
|
|
101
|
+
20. template_card_menu_event
|
|
102
|
+
21. inactive_alert
|
|
103
|
+
22. close_inactive_agent
|
|
104
|
+
23. reopen_inactive_agent
|
|
105
|
+
24. low_active_alert
|
|
106
|
+
25. low_active
|
|
107
|
+
26. active_restored
|
|
108
|
+
|
|
109
|
+
### C. 含 ChangeType 的展开数量
|
|
110
|
+
|
|
111
|
+
如果把 `change_contact` 按 `ChangeType` 展开,建议按“二级事件”管理,共 7 种:
|
|
112
|
+
|
|
113
|
+
1. create_user
|
|
114
|
+
2. update_user
|
|
115
|
+
3. delete_user
|
|
116
|
+
4. create_party
|
|
117
|
+
5. update_party
|
|
118
|
+
6. delete_party
|
|
119
|
+
7. update_tag
|
|
120
|
+
|
|
121
|
+
因此,配置层可支持的“可路由事件项”建议按 32 项预算:
|
|
122
|
+
|
|
123
|
+
1. 26 个 Event 值
|
|
124
|
+
2. 其中 change_contact 再细分 7 个 ChangeType(路由维度)
|
|
125
|
+
|
|
126
|
+
### D. 配置建议(用于实现)
|
|
127
|
+
|
|
128
|
+
1. 第一层:`eventEnabled`(开关,先解决“支持 event”)。
|
|
129
|
+
2. 第二层:`eventType`(即 Event,用于主白名单和主路由)。
|
|
130
|
+
3. 第三层:`changeType` 或 `eventKey`。
|
|
131
|
+
- `changeType`:仅当 `eventType=change_contact` 时启用。
|
|
132
|
+
- `eventKey`:菜单事件精细路由,支持精确值/前缀/正则。
|
|
133
|
+
4. `messageType` 级别白名单作为后续扩展,不纳入本期 MVP 必选项。
|
|
134
|
+
|
|
135
|
+
## 4. 配置模型草案
|
|
136
|
+
|
|
137
|
+
建议在 `channels.wecom.accounts.<accountId>.agent` 下新增:
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
channels:
|
|
141
|
+
wecom:
|
|
142
|
+
accounts:
|
|
143
|
+
default:
|
|
144
|
+
agent:
|
|
145
|
+
# 1) event 入站白名单配置(MVP)
|
|
146
|
+
inboundPolicy:
|
|
147
|
+
eventEnabled: true
|
|
148
|
+
eventPolicy:
|
|
149
|
+
mode: allowlist
|
|
150
|
+
allowedEventTypes:
|
|
151
|
+
- subscribe
|
|
152
|
+
- enter_agent
|
|
153
|
+
- click
|
|
154
|
+
- view
|
|
155
|
+
- view_miniprogram
|
|
156
|
+
- scancode_push
|
|
157
|
+
- scancode_waitmsg
|
|
158
|
+
- pic_sysphoto
|
|
159
|
+
- pic_photo_or_album
|
|
160
|
+
- pic_weixin
|
|
161
|
+
- location_select
|
|
162
|
+
|
|
163
|
+
# 2) 事件分发配置
|
|
164
|
+
eventRouting:
|
|
165
|
+
unmatchedAction: ignore # ignore | forwardToAgent
|
|
166
|
+
routes:
|
|
167
|
+
- when:
|
|
168
|
+
eventType: click
|
|
169
|
+
eventKey: "MENU_HELP"
|
|
170
|
+
handler:
|
|
171
|
+
type: node_script
|
|
172
|
+
entry: "./scripts/wecom/menu-click-help.js"
|
|
173
|
+
timeoutMs: 5000
|
|
174
|
+
- when:
|
|
175
|
+
eventType: scancode_push
|
|
176
|
+
handler:
|
|
177
|
+
type: python_script
|
|
178
|
+
entry: "./scripts/wecom/scancode_handler.py"
|
|
179
|
+
timeoutMs: 8000
|
|
180
|
+
|
|
181
|
+
# 3) 脚本执行安全设置
|
|
182
|
+
scriptRuntime:
|
|
183
|
+
enabled: true
|
|
184
|
+
allowPaths:
|
|
185
|
+
- "./scripts/wecom"
|
|
186
|
+
maxStdoutBytes: 262144
|
|
187
|
+
maxStderrBytes: 131072
|
|
188
|
+
defaultTimeoutMs: 5000
|
|
189
|
+
pythonCommand: "python3"
|
|
190
|
+
nodeCommand: "node"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 5. 分发与执行架构
|
|
194
|
+
|
|
195
|
+
### 5.1 处理链路
|
|
196
|
+
|
|
197
|
+
1. 接收并解析 XML(现有能力)。
|
|
198
|
+
2. 生成标准入站上下文 `InboundEventContext`。
|
|
199
|
+
3. 先走 `inboundPolicy` 判定:
|
|
200
|
+
- 非 `event` 消息保持现状(按现有逻辑处理)。
|
|
201
|
+
- `eventEnabled=false` => 拒绝 event。
|
|
202
|
+
- `eventType` 不允许 => 拒绝。
|
|
203
|
+
4. 命中后进入 `eventRouting`:
|
|
204
|
+
- 按 routes 顺序匹配(首个命中即执行)。
|
|
205
|
+
- 未命中走 `unmatchedAction`。
|
|
206
|
+
5. 执行 handler:
|
|
207
|
+
- `builtin`:调用内置函数。
|
|
208
|
+
- `node_script`:子进程执行 Node 脚本。
|
|
209
|
+
- `python_script`:子进程执行 Python 脚本。
|
|
210
|
+
6. 汇总 handler 结果,决定:
|
|
211
|
+
- 是否回复用户。
|
|
212
|
+
- 是否继续默认消息流水线。
|
|
213
|
+
- 是否仅记录审计并结束。
|
|
214
|
+
|
|
215
|
+
### 5.2 统一处理器返回协议(建议)
|
|
216
|
+
|
|
217
|
+
外部脚本输入(stdin)必须包含完整事件参数,至少包括标准字段 + 原始字段:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"version": "1.0",
|
|
222
|
+
"channel": "wecom",
|
|
223
|
+
"accountId": "default",
|
|
224
|
+
"receivedAt": 1760000000000,
|
|
225
|
+
"message": {
|
|
226
|
+
"msgType": "event",
|
|
227
|
+
"eventType": "click",
|
|
228
|
+
"eventKey": "MENU_HELP",
|
|
229
|
+
"changeType": null,
|
|
230
|
+
"fromUser": "zhangsan",
|
|
231
|
+
"toUser": "wwxxxx",
|
|
232
|
+
"chatId": null,
|
|
233
|
+
"agentId": 1000002,
|
|
234
|
+
"createTime": 1760000000,
|
|
235
|
+
"msgId": null,
|
|
236
|
+
"raw": {
|
|
237
|
+
"ToUserName": "wwxxxx",
|
|
238
|
+
"FromUserName": "zhangsan",
|
|
239
|
+
"MsgType": "event",
|
|
240
|
+
"Event": "click",
|
|
241
|
+
"EventKey": "MENU_HELP",
|
|
242
|
+
"AgentID": "1000002"
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"route": {
|
|
246
|
+
"matchedRuleId": "menu_help_click",
|
|
247
|
+
"handlerType": "node_script"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
说明:
|
|
253
|
+
|
|
254
|
+
1. `message.raw` 为原始 XML 解析结果(扁平对象),用于外部脚本读取任意参数。
|
|
255
|
+
2. `message` 顶层为标准化字段,降低脚本解析成本。
|
|
256
|
+
3. 对菜单事件扩展字段(如 `ScanCodeInfo`、`SendPicsInfo`、`SendLocationInfo`)需原样放入 `message.raw`。
|
|
257
|
+
4. 后续新增事件字段无需改协议版本,直接在 `message.raw` 增量透传。
|
|
258
|
+
|
|
259
|
+
外部脚本从 stdout 返回 JSON:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"ok": true,
|
|
264
|
+
"action": "reply_text",
|
|
265
|
+
"reply": {
|
|
266
|
+
"text": "已收到菜单点击: MENU_HELP"
|
|
267
|
+
},
|
|
268
|
+
"chainToAgent": false,
|
|
269
|
+
"audit": {
|
|
270
|
+
"tags": ["menu", "click"]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
字段建议:
|
|
276
|
+
|
|
277
|
+
1. `ok`: boolean,处理是否成功。
|
|
278
|
+
2. `action`: `none | reply_text | reply_markdown | call_internal`。
|
|
279
|
+
3. `reply`: 回复负载。
|
|
280
|
+
4. `chainToAgent`: 是否继续走默认 AI 会话。
|
|
281
|
+
5. `audit`: 附加审计标签。
|
|
282
|
+
6. `error`: 失败时错误消息。
|
|
283
|
+
|
|
284
|
+
### 5.3 参数透传要求(强约束)
|
|
285
|
+
|
|
286
|
+
1. 所有外部 handler(Node/Python)都必须收到完整 event 参数,不允许只传 `eventType/eventKey`。
|
|
287
|
+
2. 参数透传应包含:基础字段、事件字段、扩展子结构、原始解析对象。
|
|
288
|
+
3. 当字段缺失时保留 `null` 或空对象,不要静默删除键,避免脚本分支判断失效。
|
|
289
|
+
4. 当入站不是 `event` 时,仍保持统一 envelope 结构,便于未来复用。
|
|
290
|
+
|
|
291
|
+
## 6. 代码改造建议
|
|
292
|
+
|
|
293
|
+
### 6.1 配置与类型
|
|
294
|
+
|
|
295
|
+
1. 扩展配置类型:
|
|
296
|
+
- `src/types/config.ts`
|
|
297
|
+
- `src/config/schema.ts`
|
|
298
|
+
2. 增加默认值与兼容合并逻辑:
|
|
299
|
+
- `src/config/runtime-config.ts`
|
|
300
|
+
|
|
301
|
+
### 6.2 入站过滤改造
|
|
302
|
+
|
|
303
|
+
1. 将当前 `shouldProcessAgentInboundMessage` 的硬编码白名单改为:
|
|
304
|
+
- 先判断 `inboundPolicy.eventEnabled`
|
|
305
|
+
- 对 `event` 再读 `eventPolicy.allowedEventTypes`
|
|
306
|
+
2. 保留现有关键保护逻辑:
|
|
307
|
+
- `sys` 发送者保护
|
|
308
|
+
- 缺失 sender 保护
|
|
309
|
+
- 已有去重保护
|
|
310
|
+
|
|
311
|
+
### 6.3 新增事件分发器
|
|
312
|
+
|
|
313
|
+
建议新增模块:
|
|
314
|
+
|
|
315
|
+
1. `src/agent/event-router.ts`
|
|
316
|
+
- 路由匹配
|
|
317
|
+
- handler 选择
|
|
318
|
+
2. `src/agent/handler-runner.ts`
|
|
319
|
+
- builtin / node / python 统一执行
|
|
320
|
+
- 超时、stdout/stderr 限流
|
|
321
|
+
- stdin 注入标准 envelope(含完整 event 参数)
|
|
322
|
+
3. `src/agent/handler-protocol.ts`
|
|
323
|
+
- 输入输出协议定义
|
|
324
|
+
|
|
325
|
+
### 6.4 在主处理流程接入
|
|
326
|
+
|
|
327
|
+
在 `src/agent/handler.ts` 的 `event` 分支:
|
|
328
|
+
|
|
329
|
+
1. 在放通后优先调用事件分发器。
|
|
330
|
+
2. 分发器返回 `handled=true` 且 `chainToAgent=false` 时,终止默认 AI 流程。
|
|
331
|
+
3. 需要默认流程时继续原有 `processAgentMessage`。
|
|
332
|
+
|
|
333
|
+
## 7. 安全与风险控制
|
|
334
|
+
|
|
335
|
+
1. 默认关闭脚本执行,需显式 `scriptRuntime.enabled=true`。
|
|
336
|
+
2. 仅允许执行 `allowPaths` 下脚本,防止任意路径执行。
|
|
337
|
+
3. 进程级超时,超时强制 kill。
|
|
338
|
+
4. 限制 stdout/stderr 最大字节,防止日志/内存膨胀。
|
|
339
|
+
5. 子进程不继承敏感环境变量(可配置白名单透传)。
|
|
340
|
+
6. 记录审计:账号、eventType、eventKey、handler、耗时、退出码。
|
|
341
|
+
|
|
342
|
+
## 8. 测试计划
|
|
343
|
+
|
|
344
|
+
### 8.1 单元测试
|
|
345
|
+
|
|
346
|
+
1. `inboundPolicy` 判定测试:
|
|
347
|
+
- eventEnabled/eventType allow/deny 组合。
|
|
348
|
+
2. `eventRouting` 匹配测试:
|
|
349
|
+
- eventType + changeType/eventKey 优先级。
|
|
350
|
+
3. handler runner 测试:
|
|
351
|
+
- 正常输出
|
|
352
|
+
- 非法 JSON
|
|
353
|
+
- 超时
|
|
354
|
+
- 非 0 退出码
|
|
355
|
+
- stdin 中包含完整 event 参数与 raw 字段
|
|
356
|
+
|
|
357
|
+
### 8.2 集成测试
|
|
358
|
+
|
|
359
|
+
1. 构造 `click`、`view`、`scancode_push` XML 回调,验证完整链路。
|
|
360
|
+
2. 验证 `unmatchedAction` 两种模式。
|
|
361
|
+
3. 验证配置缺失时与当前版本行为一致。
|
|
362
|
+
4. 验证外部脚本可读取 `ScanCodeInfo/SendPicsInfo/SendLocationInfo` 等扩展参数。
|
|
363
|
+
|
|
364
|
+
### 8.3 回归测试
|
|
365
|
+
|
|
366
|
+
1. `subscribe` / `enter_agent` 现有行为不回归。
|
|
367
|
+
2. 文档/日程等现有 `doc_*`、`wedoc_*`、`smartsheet_*` 事件不回归。
|
|
368
|
+
|
|
369
|
+
## 9. 里程碑与交付
|
|
370
|
+
|
|
371
|
+
### M1:配置化放通(1~2 天)
|
|
372
|
+
|
|
373
|
+
1. 完成配置 schema/type 扩展。
|
|
374
|
+
2. `shouldProcessAgentInboundMessage` 改为 `eventEnabled + eventType` 配置驱动。
|
|
375
|
+
3. 增加单元测试。
|
|
376
|
+
|
|
377
|
+
### M2:事件分发器(2~3 天)
|
|
378
|
+
|
|
379
|
+
1. 实现 route 匹配和 builtin handler。
|
|
380
|
+
2. 接入主处理流程。
|
|
381
|
+
3. 增加集成测试。
|
|
382
|
+
|
|
383
|
+
### M3:外部脚本执行(2~3 天)
|
|
384
|
+
|
|
385
|
+
1. Node/Python runner。
|
|
386
|
+
2. 超时和输出限制。
|
|
387
|
+
3. 审计字段补齐。
|
|
388
|
+
|
|
389
|
+
### M4:文档与示例(1 天)
|
|
390
|
+
|
|
391
|
+
1. README 增加配置示例与安全建议。
|
|
392
|
+
2. 增加 `scripts/wecom` 示例脚本。
|
|
393
|
+
|
|
394
|
+
#### M4 已落地内容(2026-04-10)
|
|
395
|
+
|
|
396
|
+
1. 已在 README 增加 Agent 事件路由章节,包含:
|
|
397
|
+
- 三层配置示例(`eventEnabled -> eventType -> changeType/eventKey`)
|
|
398
|
+
- Node/Python handler 配置样例
|
|
399
|
+
- stdin/stdout 协议说明
|
|
400
|
+
- 安全建议
|
|
401
|
+
2. 已新增可运行示例脚本:
|
|
402
|
+
- `scripts/wecom/menu-click-help.js`
|
|
403
|
+
- `scripts/wecom/menu-click-help.py`
|
|
404
|
+
- `scripts/wecom/README.md`
|
|
405
|
+
3. 现状说明:
|
|
406
|
+
- M1 已完成:event 配置化放通
|
|
407
|
+
- M2 已完成:事件路由与 builtin handler
|
|
408
|
+
- M3 已完成:Node/Python runner + 超时/输出限制 + 审计
|
|
409
|
+
- M4 已完成:文档和示例交付
|
|
410
|
+
|
|
411
|
+
## 10. 首批内置 handler 建议
|
|
412
|
+
|
|
413
|
+
1. `menu_click_echo`:回显 `eventType` + `eventKey`,用于联调。
|
|
414
|
+
2. `menu_click_route_to_prompt`:将菜单键映射成固定提示词进入默认 pipeline。
|
|
415
|
+
3. `menu_click_call_script`:作为脚本执行桥接器。
|
|
416
|
+
|
|
417
|
+
## 11. 兼容性策略
|
|
418
|
+
|
|
419
|
+
1. 旧配置无 `inboundPolicy` 时,使用“兼容默认白名单”(与当前一致)。
|
|
420
|
+
2. 新配置启用后,按配置优先生效。
|
|
421
|
+
3. 对未识别配置字段仅告警不崩溃。
|
|
422
|
+
|
|
423
|
+
## 11.1 为什么先不做 messageType 白名单
|
|
424
|
+
|
|
425
|
+
1. 当前痛点集中在 `event` 被整体过滤,最小改动是先引入 `eventEnabled`。
|
|
426
|
+
2. 现有 `text/image/file/...` 已在当前链路可处理,本期不需要额外开关干预。
|
|
427
|
+
3. 先做 event 维度可显著降低配置复杂度与回归风险。
|
|
428
|
+
4. 后续若出现“非 event 类型也需要细粒度开关”的需求,再增补 messageType 白名单。
|
|
429
|
+
|
|
430
|
+
## 12. 开放问题(需确认)
|
|
431
|
+
|
|
432
|
+
1. 菜单事件 `view/view_miniprogram` 是否默认只审计不触发回复?
|
|
433
|
+
2. 脚本 handler 是否允许访问网络,是否需要开关控制?
|
|
434
|
+
3. 是否需要在每个 route 上支持 `retryPolicy`?
|
|
435
|
+
4. 是否需要支持 webhook handler(HTTP 回调)作为第三类外部处理器?
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
该规划优先保证“可配置放通 + 可扩展处理 + 安全默认值”。
|
|
440
|
+
如果确认此方案,可按 M1 开始先落地配置化白名单,再逐步引入路由与脚本执行能力。
|
package/README.md
CHANGED
|
@@ -163,6 +163,17 @@
|
|
|
163
163
|
> 项目保持高频迭代,全面对齐甚至超越企业真实业务诉求。
|
|
164
164
|
> **为保持精简,以下仅展示近期 5 次重要更新,完整历史版本(含全部 `v2.2.x`)请前往 [changelog/ 目录](./changelog/) 查阅。**
|
|
165
165
|
|
|
166
|
+
#### 📌 v2.4.12(2026-04-12)
|
|
167
|
+
- **[新增优化] 自建应用菜单事件可路由到本地脚本** ⚙️ 企业微信自建应用收到 `click` 等 `event` 事件后,现在可以按 `eventType`、`eventKey`、`changeType` 等规则命中本地 `Node.js` / `Python` 脚本,不再只能一律进入默认 Agent 流程。
|
|
168
|
+
- **[新增优化] 脚本既能直接回复,也能继续链到 Agent** 🔀 脚本返回结果里可以控制是否继续进入 AI 流程,适合把“菜单先走固定逻辑,复杂问题再交给 Agent”的模式真正落地。
|
|
169
|
+
- **[新增能力] 上下游企业现在可通过 Agent 渠道互通** 🏢 如果你的自建应用已经共享给上下游企业,现在插件可以根据下游 `CorpID` 和 `agent.upstreamCorps` 把回复准确发回对应企业,图片和语音等常见媒体链路也一起补稳了。
|
|
170
|
+
- **[重要修复] Webhook 入站文件不再被固定 5MB 限制误拦** 📎 之前有些企业微信附件虽然在实际配置允许范围内,但进入会话工作区前仍会被旧的固定阈值挡住。这一版已经改成按当前 WeCom 配置解析后的大小限制执行,入站文件接入更稳。
|
|
171
|
+
|
|
172
|
+
#### 📌 v2.3.27(2026-03-27)
|
|
173
|
+
- **[重要修复] `channel add` 重新支持 WeCom guided setup** 🧭 之前有些环境下,`wecom` 虽然已经安装,却仍会在 OpenClaw 里显示成 “does not support guided setup yet”,导致无法直接通过交互式向导添加。现在插件已经对齐 OpenClaw 当前的 `setupWizard` 接口,`openclaw channels add` 会重新正常识别和进入配置流程。
|
|
174
|
+
- **[重要修复] 修复 `installedCatalogById is not defined`** 🔧 部分用户在渠道添加或选择阶段会直接遇到 `ReferenceError: installedCatalogById is not defined`,表现上像是“选了渠道就报错”或“添加流程突然失效”。这一版已经修复对应的目录访问逻辑,添加流程恢复稳定。
|
|
175
|
+
- **[升级兼容] 清理 OpenClaw 新版下失效的 SDK 旧入口** 📦 这次同步迁移了 `wecom` 插件里几处已经不再建议继续从 `openclaw/plugin-sdk` 根入口直接拿的旧接口,重点覆盖工具上下文、outbound 适配器和 Bot WS 媒体发送链路,升级 OpenClaw 后更不容易再出现“有的地方能跑、有的地方直接炸”的兼容问题。
|
|
176
|
+
|
|
166
177
|
#### 📌 v2.3.26(2026-03-26)
|
|
167
178
|
- **[重要修复] 升级 OpenClaw 后不再乱报错** 🔧 修复了新版 OpenClaw 下 `wecom` 插件容易出现的 `is not a function` 一类启动/运行错误。
|
|
168
179
|
- **[回复更稳] Agent 和 Bot WS 不再乱串** ↔️ 现在是谁收到消息,就尽量由谁来回复,不再容易出现“在 Agent 里说话,结果 Bot WS 回你”的情况。
|
|
@@ -179,13 +190,6 @@
|
|
|
179
190
|
- **[多账号硬隔离]** 彻底重构 MCP 缓存池实现 `accountId + category` 的二次硬维隔离,无论您的矩阵挂载了多少家企业的助手,上下文及鉴权缓存绝不会交叉重叠。
|
|
180
191
|
- **[媒体通道重构]** 补齐 Bot WS 本地的媒体上传链,同时设立了严格的 `5秒熔断机制`,若 WebSocket 长通道大文件卡死将无感静默降级到 Agent 私信发送。
|
|
181
192
|
|
|
182
|
-
#### 📌 v2.3.16(2026-03-16)
|
|
183
|
-
- **[解析增强] 混合消息媒体正确接管** 🛠 重点修复在 `Bot WS` 通道下,用户如果发了“一张截图 + 一段文字指示”,以前容易丢掉截图或者 AI 只能看到无法查看的腾讯云临时链接。新版底层引擎将自动扫过所有的媒体节点摘取 URL 与解密 AES Key,还大模型一双慧眼。
|
|
184
|
-
|
|
185
|
-
#### 📌 v2.3.15(2026-03-14)
|
|
186
|
-
- **[原生资产稳定写入]** 📄 深度强化大模型创建企微相关原生存根文档/表格时的写入稳定性。执行 `init_content` 有了更强的前置图片上传清洗能力;极大程度杜绝了混发段落/文本/图片触发的企微官方 `Validator` 异常。
|
|
187
|
-
- **[复杂分发目标解包]** 💬 补齐所有关于企业微信“群聊、部门、标签组”作为 `To` 目标的精确指令解析算法,保障向全公司的组织架构层级呼气 AI 报告不再报出 `81013 target invalid`。
|
|
188
|
-
|
|
189
193
|
*(查看更早期关于“超时熔断代投、动态扩容矩阵”等功能的更新日志,请移步 [changelog/ 目录](./changelog/))*
|
|
190
194
|
|
|
191
195
|
---
|
|
@@ -204,7 +208,7 @@ openclaw plugins enable wecom
|
|
|
204
208
|
|
|
205
209
|
### 1.2 互动向导式初配 (适合个人开发者与极客)
|
|
206
210
|
|
|
207
|
-
如果您不想手写繁杂的 JSON 配置文件,可以通过交互式向导快速完成最轻量的 WebSocket
|
|
211
|
+
如果您不想手写繁杂的 JSON 配置文件,可以通过交互式向导快速完成最轻量的 WebSocket 长连接部署。`v2.3.27` 起,`wecom` 已重新对齐 OpenClaw 当前的 guided setup 流程,`openclaw channels add` 可以直接识别并进入配置:
|
|
208
212
|
|
|
209
213
|
1. 确保已启用本插件。
|
|
210
214
|
2. 在终端运行添加渠道指令:
|
|
@@ -214,6 +218,10 @@ openclaw plugins enable wecom
|
|
|
214
218
|
3. 选择下拉列表中第一顺位的:**企业微信 (WeCom)**
|
|
215
219
|
4. 根据终端亮色指引,填入企微机器人对应的 `Bot ID` 及 `Secret`,机器人即可完成握手并进入可用状态。
|
|
216
220
|
|
|
221
|
+
> **如果您最近刚升级 OpenClaw:**
|
|
222
|
+
> - 若之前在添加渠道时看到 `wecom does not support guided setup yet`,请更新到当前版本后重试。
|
|
223
|
+
> - 若之前在渠道添加阶段见过 `ReferenceError: installedCatalogById is not defined`,这一版也已一并修复。
|
|
224
|
+
|
|
217
225
|
### 1.3 生产环境顶配架构示范(Bot WS 流式交互 + Agent 私有通道兜底发送)
|
|
218
226
|
|
|
219
227
|
如果您的目标不是“接进来能聊两句”,而是让团队在企业微信里长期稳定使用 AI,这套组合更接近生产环境的推荐形态:
|
|
@@ -257,6 +265,12 @@ openclaw plugins enable wecom
|
|
|
257
265
|
"dm": {
|
|
258
266
|
"policy": "open",
|
|
259
267
|
"allowFrom": []
|
|
268
|
+
},
|
|
269
|
+
"upstreamCorps": { // 可选:给上下游企业用户发消息时使用
|
|
270
|
+
"ww_partner_corp": {
|
|
271
|
+
"corpId": "ww_partner_corp",
|
|
272
|
+
"agentId": 1000002
|
|
273
|
+
}
|
|
260
274
|
}
|
|
261
275
|
}
|
|
262
276
|
}
|
|
@@ -291,6 +305,7 @@ openclaw plugins enable wecom
|
|
|
291
305
|
- 旧的 `channels.wecom.media.maxBytes` 仍然兼容,但仅作为向后兼容兜底;新配置建议统一改成 `mediaMaxMb`。
|
|
292
306
|
- 这些目录会和 OpenClaw 默认允许的媒体目录一起生效,不会覆盖默认白名单。
|
|
293
307
|
- 也就是说,像 `~/Downloads/01.png` 这类本机文件现在默认就可以直接发到企微,不需要再单独配置。
|
|
308
|
+
- 如果你需要给上下游企业用户回消息,可以在 `agent` 下追加 `upstreamCorps`;下面的 `1.6` 会单独展开说明。
|
|
294
309
|
|
|
295
310
|
> **注意:** 历史配置里的 `agent.corpSecret` 引擎依然能够向后兼容拾起,但后续的新项目推荐采用标准的 `agentSecret` 作为对齐键。
|
|
296
311
|
|
|
@@ -380,6 +395,73 @@ openclaw plugins enable wecom
|
|
|
380
395
|
|
|
381
396
|
一句话:`localRoots` 管“能不能读这个本地路径”,`mediaMaxMb` 管“最多读多大”。
|
|
382
397
|
|
|
398
|
+
### 1.6 上下游企业配置:如何给上下游企业用户发消息
|
|
399
|
+
|
|
400
|
+
如果你的企业微信应用已经共享给上下游企业,插件现在可以根据下游企业的 `CorpID` 和 `AgentID`,把回复准确发回对应的上下游用户。
|
|
401
|
+
|
|
402
|
+
这件事适合的场景很明确:
|
|
403
|
+
|
|
404
|
+
- 你的主企业已经把自建应用共享给经销商、供应商或合作方
|
|
405
|
+
- 这些上下游企业用户会从不同 `CorpID` 进入同一个 Agent 通道
|
|
406
|
+
- 你希望插件能自动识别“这是下游企业用户”,并走对应企业的应用身份发消息
|
|
407
|
+
|
|
408
|
+
最小配置示例如下:
|
|
409
|
+
|
|
410
|
+
```jsonc
|
|
411
|
+
{
|
|
412
|
+
"channels": {
|
|
413
|
+
"wecom": {
|
|
414
|
+
"accounts": {
|
|
415
|
+
"default": {
|
|
416
|
+
"agent": {
|
|
417
|
+
"corpId": "ww_primary_corp",
|
|
418
|
+
"agentId": 1000001,
|
|
419
|
+
"agentSecret": "PRIMARY_AGENT_SECRET",
|
|
420
|
+
"token": "PRIMARY_CALLBACK_TOKEN",
|
|
421
|
+
"encodingAESKey": "PRIMARY_ENCODING_AES_KEY",
|
|
422
|
+
"upstreamCorps": {
|
|
423
|
+
"ww_partner_corp": {
|
|
424
|
+
"corpId": "ww_partner_corp",
|
|
425
|
+
"agentId": 1000002
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
可以这样理解这组配置:
|
|
437
|
+
|
|
438
|
+
- `agent.corpId` / `agent.agentId` 是上游主企业自己的应用配置
|
|
439
|
+
- `upstreamCorps.<key>.corpId` 是某个下游企业的 `CorpID`
|
|
440
|
+
- `upstreamCorps.<key>.agentId` 是这个下游企业里共享应用对应的 `AgentID`
|
|
441
|
+
- 下游企业不需要单独配置 `agentSecret`;仍然使用主企业应用的鉴权链路
|
|
442
|
+
|
|
443
|
+
这些参数通常可以从两条路拿到:
|
|
444
|
+
|
|
445
|
+
- 直接从企业微信管理后台查看下游企业的 `CorpID` 和共享应用的 `AgentID`
|
|
446
|
+
- 通过企业微信“获取应用共享信息”接口批量拉取
|
|
447
|
+
|
|
448
|
+
如果你打算走自动拉取,最关键的信息只有两个:
|
|
449
|
+
|
|
450
|
+
- 官方文档:`https://developer.work.weixin.qq.com/document/path/95813`
|
|
451
|
+
- 你需要把返回里的 `corp_list[].corpid` 映射到 `upstreamCorps.<key>.corpId`,把 `corp_list[].agentid` 映射到 `upstreamCorps.<key>.agentId`
|
|
452
|
+
|
|
453
|
+
插件内部的工作逻辑是:
|
|
454
|
+
|
|
455
|
+
- 收到消息时,会先看回调里的 `ToUserName`
|
|
456
|
+
- 如果这个 `CorpID` 和主企业 `corpId` 不一致,就把它识别成上下游企业用户
|
|
457
|
+
- 回复时会自动走对应的上下游 target 和下游企业配置,而不是误发回主企业通道
|
|
458
|
+
|
|
459
|
+
需要特别注意三点:
|
|
460
|
+
|
|
461
|
+
- `upstreamCorps` 只解决“发给哪个下游企业”的问题,不替代主企业应用本身的授权配置
|
|
462
|
+
- 上下游企业需要先在企业微信后台完成应用共享,并确保应用已加入“可调用接口的应用”
|
|
463
|
+
- 如果你只是想快速看完整字段说明、接口映射和日志样例,可以直接看 [UPSTREAM_CONFIG.md](./UPSTREAM_CONFIG.md)
|
|
464
|
+
|
|
383
465
|
---
|
|
384
466
|
|
|
385
467
|
## 二、🏢 企业微信后台回调挂载指南 (针对使用了 Webhook 或 Agent Callback 的重度用户)
|