@creatoraris/openclaw-wecom 0.3.1 → 0.4.1

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 (3) hide show
  1. package/README.md +73 -242
  2. package/index.js +43 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,300 +5,131 @@
5
5
  [![npm version](https://img.shields.io/npm/v/@creatoraris/openclaw-wecom.svg)](https://www.npmjs.com/package/@creatoraris/openclaw-wecom)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- ## 特性
8
+ ## 特性
9
9
 
10
- - 支持流式回复(分段发送,体验更流畅)
11
- - 支持消息加密(符合企微安全规范)
12
- - 支持单聊和群聊
13
- - 自动消息去重
14
- - 生产环境验证
10
+ - 支持流式回复(分段发送,体验更流畅)
11
+ - 支持消息加密(符合企微安全规范)
12
+ - 支持单聊和群聊
13
+ - 支持图片消息(自动解密 WeCom 加密图片)
14
+ - 支持上下文重置(发送 `/reset` 或 `/重置`)
15
+ - 自动消息去重
16
+ - 作为 OpenClaw 插件运行,随 OpenClaw Gateway 自动启停
15
17
 
16
- ## 📋 前置条件
18
+ ## 前置条件
17
19
 
18
20
  - OpenClaw 已安装并运行
19
21
  - Node.js >= 18.0.0
20
22
  - 企业微信账号(个人也可注册企业版,1-9 人免费)
21
- - 一台可部署 Webhook 服务的机器(或使用 ngrok 本地开发)
23
+ - 一台可部署 Webhook 服务的机器(或使用 ngrok / Tailscale 进行内网穿透)
22
24
 
23
- ## 🚀 快速开始
25
+ ## 快速开始
24
26
 
25
- ### 总耗时:约 20 分钟
26
-
27
- ### 步骤 1:安装插件(2 分钟)
27
+ ### 步骤 1:安装插件
28
28
 
29
29
  ```bash
30
30
  openclaw plugins install @creatoraris/openclaw-wecom
31
31
  ```
32
32
 
33
- ### 步骤 2:申请企微机器人(10 分钟)
34
-
35
- #### 2.1 注册企业微信
36
-
37
- 如果还没有企业微信账号:
38
-
39
- 1. 访问 [企业微信官网](https://work.weixin.qq.com/)
40
- 2. 点击「注册企业」
41
- 3. 填写信息(可以用个人身份注册)
42
- 4. 验证手机号
43
-
44
- #### 2.2 创建智能助手机器人
33
+ ### 步骤 2:创建企微智能助手机器人
45
34
 
46
35
  1. 登录 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/)
47
- 2. 左侧菜单:「应用管理」→「应用」
36
+ 2. 左侧菜单:「应用管理」 -> 「应用」
48
37
  3. 找到「智能助手」,点击进入
49
- 4. 点击「创建智能助手」
50
- 5. 填写名称(如:OpenClaw AI 助手)
51
- 6. 点击「创建」
52
-
53
- #### 2.3 配置回调
54
-
55
- 1. 在智能助手详情页,点击「接收消息」标签
56
- 2. 设置回调 URL:
57
- ```
58
- https://your-domain.com/wecom/callback
59
- ```
60
- > 💡 本地开发可以用 [ngrok](https://ngrok.com/):`https://xxx.ngrok.io/wecom/callback`
61
-
62
- 3. 点击「生成 Token 和 EncodingAESKey」
63
- 4. **保存这三个值**(下一步要用):
64
- - Token: `abc123...`
65
- - EncodingAESKey: `xyz789...`
66
- - Webhook URL: `https://your-domain.com/wecom/callback`
67
-
68
- 5. 点击「保存」
38
+ 4. 点击「创建智能助手」,填写名称(如:OpenClaw AI 助手)
39
+ 5. 在智能助手详情页,点击「接收消息」标签
40
+ 6. 设置回调 URL:`https://your-domain.com/callback`
41
+ 7. 点击「生成 Token 和 EncodingAESKey」
42
+ 8. 记录 Token 和 EncodingAESKey(下一步配置要用)
43
+ 9. 点击「保存」
69
44
 
70
- 机器人申请完成!
45
+ > 本地开发可以用 ngrok:`ngrok http 8788`,将生成的 URL 填入回调
71
46
 
72
- ### 步骤 3:配置 OpenClaw(5 分钟)
47
+ ### 步骤 3:配置插件
73
48
 
74
- #### 3.1 编辑配置文件
75
-
76
- 编辑 `~/.openclaw/openclaw.json`:
49
+ 编辑 `~/.openclaw/openclaw.json`,在 `plugins.entries` 中添加:
77
50
 
78
51
  ```json
79
52
  {
80
- "channels": {
81
- "wecom": {
82
- "enabled": true,
83
- "webhookUrl": "https://your-domain.com/wecom/callback",
84
- "token": "你的 Token",
85
- "encodingAESKey": "你的 EncodingAESKey",
86
- "port": 8788
53
+ "plugins": {
54
+ "entries": {
55
+ "openclaw-wecom": {
56
+ "enabled": true,
57
+ "config": {
58
+ "token": "你的 Token",
59
+ "encodingAESKey": "你的 EncodingAESKey",
60
+ "corpId": "你的企业 ID",
61
+ "port": 8788
62
+ }
63
+ }
87
64
  }
88
65
  }
89
66
  }
90
67
  ```
91
68
 
92
- #### 3.2 配置环境变量
69
+ 企业 ID (corpId) 可在企业微信管理后台「我的企业」页面底部找到。
93
70
 
94
- 创建 `.env` 文件(或直接在启动脚本中设置):
71
+ ### 步骤 4:重启 OpenClaw
95
72
 
96
73
  ```bash
97
- WECOM_TOKEN=你的Token
98
- WECOM_ENCODING_AES_KEY=你的EncodingAESKey
99
- OPENCLAW_API=http://localhost:18789/v1/chat/completions
100
- OPENCLAW_TOKEN=你的OpenClaw_Gateway_Token
101
- PORT=8788
74
+ systemctl --user restart openclaw-gateway
102
75
  ```
103
76
 
104
- #### 3.3 部署 Webhook 服务
77
+ ### 步骤 5:测试
105
78
 
106
- **方式 A:使用 systemd(推荐)**
79
+ 在企业微信中找到你创建的智能助手机器人,发送消息,应该会收到 AI 回复。
107
80
 
108
- 创建 `/etc/systemd/system/wecom-bridge.service`:
81
+ ## 配置说明
109
82
 
110
- ```ini
111
- [Unit]
112
- Description=OpenClaw WeCom Bridge
113
- After=network.target
83
+ | 参数 | 必填 | 默认值 | 说明 |
84
+ |------|------|--------|------|
85
+ | `token` | 是 | - | 企微回调 Token |
86
+ | `encodingAESKey` | 是 | - | 企微回调 EncodingAESKey |
87
+ | `corpId` | 否 | `""` | 企业 ID,图片功能需要 |
88
+ | `corpSecret` | 否 | `""` | 应用 Secret(智能助手机器人通常不需要) |
89
+ | `port` | 否 | `8788` | 本地监听端口 |
114
90
 
115
- [Service]
116
- Type=simple
117
- User=your-user
118
- WorkingDirectory=/path/to/openclaw-wecom-plugin
119
- EnvironmentFile=/path/to/.env
120
- ExecStart=/usr/bin/node index.js
121
- Restart=always
122
- RestartSec=10
91
+ ## 内置命令
123
92
 
124
- [Install]
125
- WantedBy=multi-user.target
126
- ```
93
+ 在企微聊天窗口中发送以下命令:
127
94
 
128
- 启动服务:
95
+ | 命令 | 说明 |
96
+ |------|------|
97
+ | `/reset` | 重置当前对话上下文 |
98
+ | `/重置` | 同上(中文别名) |
129
99
 
130
- ```bash
131
- sudo systemctl daemon-reload
132
- sudo systemctl enable wecom-bridge
133
- sudo systemctl start wecom-bridge
134
- sudo systemctl status wecom-bridge
135
- ```
100
+ 上下文被污染或需要开始新话题时,发送重置命令即可清除历史对话。
136
101
 
137
- **方式 B:使用 PM2**
102
+ ## 架构说明
138
103
 
139
- ```bash
140
- pm2 start index.js --name wecom-bridge
141
- pm2 save
142
- pm2 startup
143
104
  ```
144
-
145
- **方式 C:本地开发(ngrok)**
146
-
147
- ```bash
148
- # 终端 1:启动 webhook 服务
149
- node index.js
150
-
151
- # 终端 2:启动 ngrok
152
- ngrok http 8788
153
- # 复制 ngrok 生成的 https URL,配置到企微回调中
105
+ 企微客户端 -> 企微服务器 -> 本插件 (HTTP Server) -> OpenClaw Gateway -> AI 模型
106
+ |
107
+ 加密/解密、去重、流式处理、图片解密
154
108
  ```
155
109
 
156
- ### 步骤 4:测试(1 分钟)
157
-
158
- 1. 在企业微信中找到你创建的机器人
159
- 2. 发送消息:`你好`
160
- 3. 应该会收到 AI 回复
161
-
162
- 🎉 恭喜!配置完成!
110
+ 本插件作为 OpenClaw 的内置服务运行,随 OpenClaw Gateway 自动启停,无需单独部署。
163
111
 
164
- ## 📖 配置说明
112
+ ## 安全性
165
113
 
166
- ### 完整配置选项
114
+ - 使用 AES-256-CBC 加密通信
115
+ - 消息签名验证
116
+ - 自动消息去重(防止重放攻击)
117
+ - 敏感信息通过 OpenClaw 配置文件管理,不使用环境变量
167
118
 
168
- ```json
169
- {
170
- "channels": {
171
- "wecom": {
172
- "enabled": true, // 是否启用
173
- "webhookUrl": "https://...", // 回调 URL(必填)
174
- "token": "...", // Token(必填)
175
- "encodingAESKey": "...", // EncodingAESKey(必填)
176
- "port": 8788, // 监听端口(可选,默认 8788)
177
- "streamDelay": 2000 // 流式回复延迟(毫秒,可选)
178
- }
179
- }
180
- }
181
- ```
119
+ ## 故障排查
182
120
 
183
- ### OpenClaw Gateway 配置
184
-
185
- 确保 OpenClaw Gateway 配置了正确的认证:
186
-
187
- ```json
188
- {
189
- "gateway": {
190
- "auth": {
191
- "mode": "token",
192
- "token": "your-gateway-token"
193
- }
194
- }
195
- }
196
- ```
121
+ 查看日志:
197
122
 
198
- ## 🔧 故障排查
199
-
200
- ### 问题:消息发送后没有回复
201
-
202
- **检查清单:**
203
-
204
- 1. Webhook 服务器是否正常运行?
205
- ```bash
206
- curl http://localhost:8788/health
207
- ```
208
-
209
- 2. 查看日志:
210
- ```bash
211
- # systemd
212
- sudo journalctl -u wecom-bridge -f
213
-
214
- # pm2
215
- pm2 logs wecom-bridge
216
- ```
217
-
218
- 3. 验证 OpenClaw Gateway 连接:
219
- ```bash
220
- curl http://localhost:18789/v1/status \
221
- -H "Authorization: Bearer your-token"
222
- ```
223
-
224
- ### 问题:消息乱码
225
-
226
- 检查 `encodingAESKey` 是否正确配置。
227
-
228
- ### 问题:回复速度慢
229
-
230
- 流式回复会分段发送。可以调整 `streamDelay` 参数:
231
-
232
- ```json
233
- {
234
- "wecom": {
235
- "streamDelay": 1000 // 减小延迟(毫秒)
236
- }
237
- }
238
- ```
239
-
240
- ### 问题:Webhook 服务启动失败
241
-
242
- 1. 检查端口是否被占用:
243
- ```bash
244
- lsof -i :8788
245
- ```
246
-
247
- 2. 检查环境变量是否正确:
248
- ```bash
249
- echo $WECOM_TOKEN
250
- echo $WECOM_ENCODING_AES_KEY
251
- ```
252
-
253
- ## 🏗️ 架构说明
254
-
255
- ```
256
- 企微客户端 → 企微服务器 → Webhook 服务器 → OpenClaw Gateway → AI 模型
257
-
258
- 加密/解密、去重、流式处理
123
+ ```bash
124
+ journalctl --user -u openclaw-gateway -f
259
125
  ```
260
126
 
261
- ### 消息流程
262
-
263
- 1. 用户在企微发送消息
264
- 2. 企微服务器加密后推送到 Webhook
265
- 3. Webhook 服务解密、验证、去重
266
- 4. 转发到 OpenClaw Gateway
267
- 5. AI 生成回复(流式)
268
- 6. Webhook 服务分段加密发送到企微
269
- 7. 用户收到 AI 回复
270
-
271
- ## 🔒 安全性
272
-
273
- - ✅ 使用 AES-256-CBC 加密
274
- - ✅ 消息签名验证
275
- - ✅ 自动消息去重(防止重放攻击)
276
- - ✅ 环境变量存储敏感信息
127
+ 常见问题:
277
128
 
278
- ## 🤝 贡献
129
+ - **端口被占用**:检查 `lsof -i :8788`,修改配置中的 port 或停止冲突进程
130
+ - **消息无回复**:确认 OpenClaw Gateway 正常运行,检查日志中的错误信息
131
+ - **回调验证失败**:确认 token 和 encodingAESKey 与企微后台一致
279
132
 
280
- 欢迎贡献代码、报告问题或提出建议!
281
-
282
- 1. Fork 本仓库
283
- 2. 创建特性分支:`git checkout -b feature/amazing-feature`
284
- 3. 提交更改:`git commit -m 'Add amazing feature'`
285
- 4. 推送分支:`git push origin feature/amazing-feature`
286
- 5. 提交 Pull Request
287
-
288
- ## 📄 License
133
+ ## License
289
134
 
290
135
  MIT License - 详见 [LICENSE](LICENSE) 文件
291
-
292
- ## 🙏 致谢
293
-
294
- - [OpenClaw](https://openclaw.ai) - 强大的 AI 助手框架
295
- - [企业微信](https://work.weixin.qq.com/) - 提供企业级通讯平台
296
-
297
- ## 📞 支持
298
-
299
- - 提交 Issue:[GitHub Issues](https://github.com/CreatorAris/openclaw-wecom-plugin/issues)
300
- - 查看文档:[OpenClaw 文档](https://docs.openclaw.ai)
301
-
302
- ---
303
-
304
- **注意:** 本项目为 beta 版本,欢迎反馈和建议!
package/index.js CHANGED
@@ -28,6 +28,11 @@ const plugin = {
28
28
  const botCrypto = new WeComCrypto(token, encodingAESKey, corpId);
29
29
  const log = api.logger;
30
30
 
31
+ // ── Sessions directory (for context reset) ──
32
+ const openclawDir = path.dirname(api.config?.agents?.defaults?.workspace || path.join(process.env.HOME, '.openclaw', 'workspace'));
33
+ const sessionsDir = path.join(openclawDir, 'agents', 'main', 'sessions');
34
+ const RESET_COMMANDS = ['/reset', '/重置'];
35
+
31
36
  // ── Stream state management ──
32
37
  const streams = new Map();
33
38
 
@@ -429,6 +434,44 @@ const plugin = {
429
434
  return;
430
435
  }
431
436
 
437
+ // ── Context reset command ──
438
+ if (RESET_COMMANDS.includes(text.trim().toLowerCase())) {
439
+ const rawSessionId = chattype === 'group' ? `wecom_group_${chatid}` : `wecom_bot_${from?.userid}`;
440
+ // OpenClaw lowercases user IDs internally, so we must match that
441
+ const sessionKey = `agent:main:openresponses-user:${rawSessionId.toLowerCase()}`;
442
+ let resetMsg = '上下文已重置,开始新的对话。';
443
+
444
+ try {
445
+ const sessionsFile = path.join(sessionsDir, 'sessions.json');
446
+ const sessionsData = JSON.parse(await fs.readFile(sessionsFile, 'utf8'));
447
+ const session = sessionsData[sessionKey];
448
+ if (session?.sessionId) {
449
+ const sessionFile = path.join(sessionsDir, `${session.sessionId}.jsonl`);
450
+ await fs.rename(sessionFile, `${sessionFile}.reset.${Date.now()}`).catch(() => {});
451
+ delete sessionsData[sessionKey];
452
+ await fs.writeFile(sessionsFile, JSON.stringify(sessionsData, null, 2));
453
+ log.info(`[Reset] session ${sessionKey} cleared`);
454
+ } else {
455
+ log.info(`[Reset] no session found for ${sessionKey}`);
456
+ resetMsg = '当前没有活跃的对话上下文。';
457
+ }
458
+ } catch (err) {
459
+ log.error(`[Reset] error: ${err.message}`);
460
+ resetMsg = '重置失败,请稍后重试。';
461
+ }
462
+
463
+ const resetStreamId = makeStreamId();
464
+ streams.set(resetStreamId, { content: resetMsg, finished: true, createdAt: Date.now() });
465
+ const replyObj = {
466
+ msgtype: 'stream',
467
+ stream: { id: resetStreamId, finish: true, content: resetMsg },
468
+ };
469
+ const encrypted = encryptReply(replyObj, nonce);
470
+ res.writeHead(200, { 'Content-Type': 'application/json' });
471
+ res.end(encrypted);
472
+ return;
473
+ }
474
+
432
475
  // Create stream state and start OpenClaw request
433
476
  const streamId = makeStreamId();
434
477
  const sessionId = chattype === 'group' ? `wecom_group_${chatid}` : `wecom_bot_${from?.userid}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@creatoraris/openclaw-wecom",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Enterprise WeChat (WeCom) channel plugin for OpenClaw - 企业微信智能助手机器人桥接",
5
5
  "main": "index.js",
6
6
  "type": "module",