@invago/mixin 1.0.9 → 1.0.11

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/README.zh-CN.md CHANGED
@@ -2,435 +2,697 @@
2
2
 
3
3
  将 [Mixin Messenger](https://mixin.one/messenger) 接入 [OpenClaw](https://openclaw.ai)。
4
4
 
5
- **[English Documentation](README.md)**
6
-
7
- ## 概览
8
-
9
- MixinClaw 是一个 OpenClaw 频道插件。它运行在 OpenClaw Gateway 同一进程中,使用 Mixin Blaze WebSocket 接收消息,并通过 Mixin HTTP API 发送消息。
10
-
11
- 重要说明:
12
-
13
- - 插件需要安装在 OpenClaw Gateway 所在的机器上。
14
- - OpenClaw 配置文件是 `openclaw.json`,需要手动编辑。
15
- - OpenClaw 配置文件是 JSON5 格式,支持注释和尾逗号。
16
- - 这里配置的代理只作用于这个插件,不影响其他插件。
17
-
18
- ## 推荐安装方式
19
-
20
- 优先使用 OpenClaw 官方插件安装命令:
21
-
22
- ```bash
23
- openclaw plugins install @invago/mixin
24
- ```
25
-
26
- `@invago/mixin` 是发布后的 npm 包名,OpenClaw 内部的运行时/插件名称仍然是 `mixin`。
27
-
28
- 安装后可用以下命令确认:
29
-
30
- ```bash
31
- openclaw plugins list
32
- openclaw plugins info mixin
33
- ```
34
-
35
- ## 本地开发安装
36
-
37
- 如果你是在本地开发,先克隆仓库并安装依赖:
38
-
39
- ```bash
40
- git clone https://github.com/invago/mixinclaw.git
41
- cd mixinclaw
42
- npm install
43
- ```
44
-
45
- 然后通过本地路径安装到 OpenClaw:
46
-
47
- ```bash
48
- openclaw plugins install .
49
- ```
50
-
51
- ## 创建 Mixin Bot
52
-
53
- 前往 [Mixin Developers Dashboard](https://developers.mixin.one/dashboard),创建机器人并记录以下凭证:
54
-
55
- - `appId`
56
- - `sessionId`
57
- - `serverPublicKey`
58
- - `sessionPrivateKey`
59
-
60
- ## 配置
61
-
62
- 手动编辑 `openclaw.json`,同时添加频道配置和插件启用配置:
63
-
64
- ```json
65
- {
66
- "channels": {
67
- "mixin": {
68
- "enabled": true,
69
- "defaultAccount": "default",
70
- "appId": "你的 App ID",
71
- "sessionId": "你的 Session ID",
72
- "serverPublicKey": "服务端公钥 Base64",
73
- "sessionPrivateKey": "会话私钥 Base64",
74
- "dmPolicy": "pairing",
75
- "allowFrom": ["授权用户 UUID"],
76
- "requireMentionInGroup": true,
77
- "mediaBypassMentionInGroup": true,
78
- "mediaMaxMb": 30,
79
- "audioSendAsVoiceByDefault": true,
80
- "audioAutoDetectDuration": true,
81
- "audioRequireFfprobe": false,
82
- "proxy": {
83
- "enabled": true,
84
- "url": "socks5://127.0.0.1:10808",
85
- "username": "proxy-user",
86
- "password": "proxy-pass"
87
- }
88
- }
89
- },
90
- "plugins": {
91
- "allow": ["mixin"],
92
- "entries": {
93
- "mixin": {
94
- "enabled": true
95
- }
96
- }
97
- }
98
- }
99
- ```
100
-
101
- 说明:
102
-
103
- - `channels.mixin` 负责配置这个频道本身。
104
- - `plugins.allow` 和 `plugins.entries.mixin.enabled` 也需要配置,否则 OpenClaw 不会加载这个插件。
105
- - Mixin 现在支持 OpenClaw 官方的私聊 `dmPolicy`,推荐使用 `dmPolicy: "pairing"`。
106
- - `allowFrom` 仍然保留,适合预授权用户或人工补充白名单;配对批准结果会写入 OpenClaw 的 pairing allowlist store。
107
- - 如果 `proxy.url` 已经包含认证信息,可以不再填写 `proxy.username` 和 `proxy.password`。
108
-
109
- ## 配对模式
110
-
111
- 私聊推荐配置:
112
-
113
- ```json
114
- {
115
- "channels": {
116
- "mixin": {
117
- "dmPolicy": "pairing"
118
- }
119
- }
120
- }
121
- ```
122
-
123
- 行为说明:
124
-
125
- - 未授权的私聊用户会先收到一个 8 位配对码。
126
- - 管理员使用 `openclaw pairing approve mixin <code>` 完成批准。
127
- - 使用 `openclaw pairing list mixin` 查看待批准的配对请求。
128
- - 批准后,该用户会被加入 OpenClaw 的 `mixin` pairing allowlist store。
129
- - `allowFrom` 仍然生效,可以和 pairing 一起使用。
130
-
131
- ## 避免跨通道串会话
132
-
133
- Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 OpenClaw 的 `session.dmScope` 配置。如果保持默认的 `main`,Mixin 私聊可能会和飞书等其它通道共用同一个主会话。
134
-
135
- 推荐这样配置:
136
-
137
- ```json
138
- {
139
- "session": {
140
- "dmScope": "per-channel-peer"
141
- }
142
- }
143
- ```
144
-
145
- 如果你同时运行多个 Mixin 账号,并且希望私聊按“账号 + 频道”进一步隔离,可以改用 `per-account-channel-peer`。
146
-
147
- ## 配置参数
148
-
149
- | 参数 | 必填 | 默认值 | 说明 |
150
- |------|------|--------|------|
151
- | `enabled` | 否 | `true` | 是否启用该频道账号 |
152
- | `defaultAccount` | 否 | `default` | 配置了 `accounts` 时默认使用的账号 ID |
153
- | `appId` | 是 | - | Mixin 应用 UUID |
154
- | `sessionId` | 是 | - | 会话 UUID |
155
- | `serverPublicKey` | 是 | - | 服务端公钥 Base64 |
156
- | `sessionPrivateKey` | 是 | - | 会话私钥 Ed25519 Base64 |
157
- | `dmPolicy` | 否 | `pairing` | 私聊策略:`pairing`、`allowlist`、`open`、`disabled` |
158
- | `allowFrom` | 否 | `[]` | 授权用户 UUID 白名单 |
159
- | `groupPolicy` | 否 | 跟随 OpenClaw 默认值 | 群消息策略:`open`、`allowlist`、`disabled` |
160
- | `groupAllowFrom` | 否 | `[]` | 当 `groupPolicy` 走 allowlist 时,允许触发群消息的发送者 UUID 白名单 |
161
- | `requireMentionInGroup` | 否 | `true` | 群聊是否要求触发词 |
162
- | `mediaBypassMentionInGroup` | 否 | `true` | 群里的文件/语音消息是否可绕过文本触发词过滤 |
163
- | `mediaMaxMb` | 否 | `30` | 入站和出站媒体大小上限,单位 MB |
164
- | `audioSendAsVoiceByDefault` | 否 | `true` | OpenClaw 原生音频出站时尽量按 Mixin 语音发送 |
165
- | `audioAutoDetectDuration` | 否 | `true` | 发送原生音频前是否用 `ffprobe` 自动探测时长 |
166
- | `audioRequireFfprobe` | 否 | `false` | 时长探测不可用时是否直接失败,而不是降级为文件发送 |
167
- | `conversations.<conversationId>.enabled` | 否 | `true` | 是否启用某个指定群会话 |
168
- | `conversations.<conversationId>.requireMention` | 否 | 继承账号级配置 | 覆盖该群会话的触发词要求 |
169
- | `conversations.<conversationId>.allowFrom` | 否 | 继承账号级配置 | 覆盖该群会话的发送者白名单 |
170
- | `conversations.<conversationId>.mediaBypassMention` | 否 | 继承账号级配置 | 覆盖该群会话中文件/语音是否绕过触发词过滤 |
171
- | `conversations.<conversationId>.groupPolicy` | 否 | 继承账号级配置 | 覆盖该群会话的群消息策略 |
172
- | `debug` | 否 | `false` | 调试模式 |
173
- | `proxy.enabled` | 否 | `false` | 是否启用插件级代理 |
174
- | `proxy.url` | 启用时必填 | - | 代理地址,例如 `http://127.0.0.1:7890` 或 `socks5://127.0.0.1:10808` |
175
- | `proxy.username` | 否 | - | 代理用户名 |
176
- | `proxy.password` | 否 | - | 代理密码 |
177
-
178
- ## 代理
179
-
180
- - Mixin 的 HTTP 请求和 Blaze WebSocket 都会走同一个代理。
181
- - 常见代理地址格式包括 `http://...`、`https://...`、`socks5://...`。
182
- - 代理软件或代理服务器需要你自己提供,插件只负责使用代理。
183
-
184
- ## 群聊访问控制
185
-
186
- 现在除了私聊 `dmPolicy`,Mixin 也支持正式的群聊访问控制:
187
-
188
- - `groupPolicy: "open"` 表示群里任何发送者都可以触发。
189
- - `groupPolicy: "allowlist"` 表示只有 `groupAllowFrom` 里的发送者 UUID 可以触发。
190
- - `groupPolicy: "disabled"` 表示整个群会话被禁用。
191
- - `conversations.<conversationId>` 可以对某一个群会话覆盖账号级配置。
192
-
193
- 示例:
194
-
195
- ```json
196
- {
197
- "channels": {
198
- "mixin": {
199
- "groupPolicy": "allowlist",
200
- "groupAllowFrom": ["USER_A_UUID"],
201
- "conversations": {
202
- "70000000-0000-0000-0000-000000000001": {
203
- "requireMention": false,
204
- "allowFrom": ["USER_B_UUID"],
205
- "mediaBypassMention": false
206
- },
207
- "70000000-0000-0000-0000-000000000002": {
208
- "enabled": false
209
- }
210
- }
211
- }
212
- }
213
- }
214
- ```
5
+ > 已支持 OpenClaw 3.23 最新插件架构。
215
6
 
216
- ## 使用方式
217
-
218
- - 私聊:`/status` 或 `你好`
219
- - 群聊:`@Bot 你的问题`,并带上 `?` 或 `help` 等触发词
220
-
221
- ## 运维
222
-
223
- 常用 OpenClaw 命令:
224
-
225
- ```bash
226
- openclaw plugins list
227
- openclaw plugins info mixin
228
- openclaw channels status --probe
229
- openclaw status
230
- ```
231
-
232
- 插件内诊断命令:
233
-
234
- - 发送 `/mixin-outbox` 可查看当前待发队列数量、下次重试时间和最近错误。
235
- - 发送 `/mixin-outbox purge-invalid` 可删除历史遗留的 `APP_CARD` / `APP_BUTTON_GROUP` 永久无效重试项。
236
-
237
- 配套运维 CLI:
238
-
239
- - 仓库里已经附带了一套配套工具,见 [tools/mixin-plugin-onboard/README.md](/E:/AI/mixin-claw/tools/mixin-plugin-onboard/README.md)。
240
- - 这套工具会和主包 `@invago/mixin` 一起发布,不再是单独第二个 npm 包。
241
- - 当前提供 `info`、`doctor`、`install`、`update` 四个命令,用于本地 OpenClaw + Mixin 插件的安装和诊断。
242
- - 本地运行示例:
243
- - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts info`
244
- - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts doctor`
245
- - 安装后使用示例:
246
- - `npx -y @invago/mixin info`
247
- - `npx -y @invago/mixin doctor`
248
-
249
- ## 投递与重试行为
250
-
251
- - 回复消息会先写入本地 outbox,再由后台 worker 发送。
252
- - 发送失败会自动重试,直到发送成功。
253
- - 插件重启后,未完成的消息仍会继续补发。
254
- - 入站 Blaze 消息会在分发前尽快 ACK,尽量减少 Mixin 的重复推送。
255
-
256
- ## 媒体支持现状
257
-
258
- 当前媒体能力分为发送侧和接收侧:
259
-
260
- - OpenClaw 原生媒体发送已经接入频道 `sendMedia`。
261
- - OpenClaw 原生 `sendPayload` 现在也会复用同一套 Mixin 出站 planner,所以文本、长文、按钮、卡片、文件、语音的选择逻辑和 agent 缓冲回复保持一致。
262
- - 当插件能把媒体识别为音频并成功拿到时长时,会优先按 `PLAIN_AUDIO` 发送。
263
- - 如果拿不到音频时长,会平稳降级为普通文件附件发送。
264
- - 非音频媒体会按 Mixin 文件附件发送。
265
- - 如果 OpenClaw 同时给出文本和媒体,插件会先发文本,再发文件。
266
- - 语音气泡式发送目前仍更适合走显式 `mixin-audio` 模板。
267
- - 入站 `PLAIN_DATA` 和 `PLAIN_AUDIO` 会被下载到本地,并通过 `MediaPath` / `MediaType` 挂到 OpenClaw 入站上下文。
268
- - 即使启用了 `requireMentionInGroup`,群里的附件消息也不会再因为缺少文本触发词被直接过滤;如果你把 `mediaBypassMentionInGroup` 设为 `false`,则会恢复和普通文本相同的群聊触发规则。
269
-
270
- 当前边界:
271
-
272
- - 发送语音时不做自动转码。
273
- - `mixin-audio` 仍要求你提供已经准备好的本地文件,并显式给出 `duration`,`waveForm` 可选。
274
- - OpenClaw 原生音频发送依赖本机可用的 `ffprobe` 来提取时长。
275
- - OpenClaw 原生 `sendMedia` 仍不会自动生成 `waveForm`,所以如果你想更稳定地控制语音消息效果,显式 `mixin-audio` 仍然是最稳妥的路径。
276
- - 是否能自动总结文件、转写语音,取决于你的 OpenClaw 媒体理解配置是否开启。
277
-
278
- 联调手册:
279
-
280
- - 见 [docs/media-testing.zh-CN.md](docs/media-testing.zh-CN.md)。
281
-
282
- ## 显式回复模板
283
-
284
- 如果你希望 Mixin 回复严格按指定形式发送,而不是依赖自动判断,可以让 agent 只输出一个 fenced code block 模板。
285
-
286
- 文本:
287
-
288
- ```text
289
- ```mixin-text
290
- 简短纯文本回复
291
- ```
292
- ```
293
-
294
- 长文:
295
-
296
- ```text
297
- ```mixin-post
298
- # 发布说明
299
-
300
- - 条目 1
301
- - 条目 2
302
- ```
303
- ```
304
-
305
- 按钮组:
306
-
307
- ```text
308
- ```mixin-buttons
309
- {
310
- "intro": "请选择操作",
311
- "buttons": [
312
- { "label": "打开文档", "action": "https://docs.openclaw.ai" },
313
- { "label": "打开 Mixin", "action": "https://developers.mixin.one" }
314
- ]
315
- }
316
- ```
317
- ```
318
-
319
- 卡片:
320
-
321
- ```text
322
- ```mixin-card
323
- {
324
- "title": "OpenClaw 文档",
325
- "description": "打开官方文档站点。",
326
- "action": "https://docs.openclaw.ai",
327
- "coverUrl": "https://example.com/cover.png",
328
- "shareable": true
329
- }
330
- ```
331
- ```
332
-
333
- 文件:
334
-
335
- ```text
336
- ```mixin-file
337
- {
338
- "filePath": "/absolute/path/to/report.pdf",
339
- "fileName": "report.pdf",
340
- "mimeType": "application/pdf"
341
- }
342
- ```
343
- ```
344
-
345
- 语音:
346
-
347
- ```text
348
- ```mixin-audio
349
- {
350
- "filePath": "/absolute/path/to/voice.ogg",
351
- "mimeType": "audio/ogg",
352
- "duration": 12,
353
- "waveForm": "AAMMQQ=="
354
- }
355
- ```
356
- ```
357
-
358
- 规则:
359
-
360
- - 显式模板优先级高于自动识别。
361
- - 回复里只要出现表格或 fenced code block,默认就会走 `mixin-post` 长文。
362
- - `mixin-buttons` 和 `mixin-card` 只接受 JSON。
363
- - `mixin-file` 和 `mixin-audio` 也只接受 JSON。
364
- - `mixin-file` `mixin-audio` 里的 `filePath` 必须是 OpenClaw 所在机器上的绝对路径。
365
- - `mixin-audio` 里的 `duration` 必填,单位为秒,`waveForm` 可选。
366
- - 如果显式 `mixin-*` 模板写错,插件不再静默跳过,而会直接发出可见的 `Mixin template error: ...` 文本提示。
367
- - 按钮和卡片链接必须使用 `http://` 或 `https://`。
368
- - Mixin 客户端可能要求目标域名已加入机器人应用的 `Resource Patterns` 白名单。
369
-
370
- ## 多账号示例
371
-
372
- ```json
373
- {
374
- "channels": {
375
- "mixin": {
376
- "accounts": {
377
- "bot1": {
378
- "name": "客服机器人",
379
- "appId": "...",
380
- "sessionId": "...",
381
- "serverPublicKey": "...",
382
- "sessionPrivateKey": "...",
383
- "dmPolicy": "pairing",
384
- "allowFrom": ["..."]
385
- },
386
- "bot2": {
387
- "name": "技术支持机器人",
388
- "appId": "...",
389
- "sessionId": "...",
390
- "serverPublicKey": "...",
391
- "sessionPrivateKey": "...",
392
- "proxy": {
393
- "enabled": true,
394
- "url": "http://127.0.0.1:7890"
395
- }
396
- }
397
- }
398
- }
399
- },
400
- "plugins": {
401
- "allow": ["mixin"],
402
- "entries": {
403
- "mixin": {
404
- "enabled": true
405
- }
406
- }
407
- }
408
- }
409
- ```
410
-
411
- ## 故障排查
412
-
413
- | 问题 | 检查项 |
414
- |------|--------|
415
- | 插件未加载 | 运行 `openclaw plugins list` 和 `openclaw plugins info mixin` |
416
- | 频道未启动 | 检查 `channels.mixin` 是否存在,凭证是否完整 |
417
- | 插件未启用 | 检查 `plugins.allow` 和 `plugins.entries.mixin.enabled` |
418
- | 收不到消息 | 检查 pairing 是否已批准或 `allowFrom` 是否包含该用户,同时检查触发词和 Blaze 连通性 |
419
- | 消息发不出去 | 检查代理是否可达、outbox 堆积情况和 `/mixin-outbox` 输出 |
420
- | 入站消息重复推送 | 检查 Blaze 连通性,并确认 ACK 是否正常发送 |
421
-
422
- ## 安全提示
423
-
424
- - 妥善保管 `sessionPrivateKey`
425
- - 生产环境建议使用 `dmPolicy: "pairing"` 或严格的 `allowFrom`
426
- - outbox 文件会保存待发送消息正文,不要暴露 `data/` 目录
427
-
428
- ## 相关链接
429
-
430
- - [OpenClaw 文档](https://openclaw.ai)
431
- - [OpenClaw 插件文档](https://docs.openclaw.ai/tools/plugin)
432
- - [OpenClaw 插件 CLI](https://docs.openclaw.ai/cli/plugins)
433
- - [OpenClaw 配置说明](https://docs.openclaw.ai/gateway/configuration)
434
- - [OpenClaw 配置参考](https://docs.openclaw.ai/gateway/configuration-reference)
435
- - [Mixin Developers Dashboard](https://developers.mixin.one/dashboard)
436
- - [Mixin Bot API 文档](https://developers.mixin.one/docs/bot-api)
7
+ **[English Documentation](README.md)**
8
+
9
+ ## 概览
10
+
11
+ MixinClaw 是一个 OpenClaw 频道插件。它运行在 OpenClaw Gateway 同一进程中,使用 Mixin Blaze WebSocket 接收入站消息,并通过 Mixin HTTP API 发送出站消息。
12
+
13
+ 重要说明:
14
+
15
+ - 插件需要安装在 OpenClaw Gateway 所在的机器上。
16
+ - OpenClaw 配置文件使用 JSON5,支持注释和尾逗号。
17
+ - 这里配置的代理只作用于这个插件,不影响其他插件。
18
+
19
+ ## 推荐安装方式
20
+
21
+ 优先使用 OpenClaw 官方插件安装命令:
22
+
23
+ ```bash
24
+ openclaw plugins install @invago/mixin
25
+ ```
26
+
27
+ `@invago/mixin` 是发布后的 npm 包名,OpenClaw 内部的运行时/插件名称仍然是 `mixin`。
28
+
29
+ 如果插件已经安装过,后续升级请直接使用插件 ID:
30
+
31
+ ```bash
32
+ openclaw plugins update mixin
33
+ ```
34
+
35
+ 如果你要首次安装指定版本,也可以直接带版本号:
36
+
37
+ ```bash
38
+ openclaw plugins install @invago/mixin@<version>
39
+ ```
40
+
41
+ 安装后可用以下命令确认:
42
+
43
+ ```bash
44
+ openclaw plugins list
45
+ openclaw plugins info mixin
46
+ ```
47
+
48
+ ## 本地开发安装
49
+
50
+ 如果你是在本地开发,先克隆仓库并安装依赖:
51
+
52
+ ```bash
53
+ git clone https://github.com/invago/mixinclaw.git
54
+ cd mixinclaw
55
+ npm install
56
+ ```
57
+
58
+ 然后通过本地路径安装到 OpenClaw
59
+
60
+ ```bash
61
+ openclaw plugins install .
62
+ ```
63
+
64
+ ## 创建 Mixin Bot
65
+
66
+ 前往 [Mixin Developers Dashboard](https://developers.mixin.one/dashboard),创建机器人并记录以下凭证:
67
+
68
+ - `appId`
69
+ - `sessionId`
70
+ - `serverPublicKey`
71
+ - `sessionPrivateKey`
72
+
73
+ ## 配置
74
+
75
+ 手动编辑 `openclaw.json`,同时添加频道配置和插件启用配置:
76
+
77
+ ```json
78
+ {
79
+ "channels": {
80
+ "mixin": {
81
+ "defaultAccount": "default",
82
+ "appId": "YOUR_APP_ID",
83
+ "sessionId": "YOUR_SESSION_ID",
84
+ "serverPublicKey": "YOUR_SERVER_PUBLIC_KEY_BASE64",
85
+ "sessionPrivateKey": "YOUR_SESSION_PRIVATE_KEY_BASE64",
86
+ "dmPolicy": "pairing",
87
+ "allowFrom": ["AUTHORIZED_USER_UUID"],
88
+ "requireMentionInGroup": true,
89
+ "mediaBypassMentionInGroup": true,
90
+ "mediaMaxMb": 30,
91
+ "audioSendAsVoiceByDefault": true,
92
+ "audioAutoDetectDuration": true,
93
+ "audioRequireFfprobe": false,
94
+ "mixpay": {
95
+ "enabled": true,
96
+ "payeeId": "YOUR_MIXPAY_PAYEE_ID",
97
+ "defaultSettlementAssetId": "YOUR_SETTLEMENT_ASSET_ID",
98
+ "expireMinutes": 15,
99
+ "pollIntervalSec": 30,
100
+ "allowedCreators": ["AUTHORIZED_USER_UUID"],
101
+ "notifyOnPending": false,
102
+ "notifyOnPaidLess": true
103
+ },
104
+ "proxy": {
105
+ "enabled": true,
106
+ "url": "socks5://127.0.0.1:10808",
107
+ "username": "proxy-user",
108
+ "password": "proxy-pass"
109
+ }
110
+ }
111
+ },
112
+ "plugins": {
113
+ "allow": ["mixin"],
114
+ "entries": {
115
+ "mixin": {
116
+ "enabled": true
117
+ }
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ 说明:
124
+
125
+ - `channels.mixin` 负责配置这个频道本身。
126
+ - `plugins.allow` 和 `plugins.entries.mixin.enabled` 也必须配置,否则 OpenClaw 不会加载这个插件。
127
+ - Mixin 支持 OpenClaw 标准私聊策略,推荐使用 `dmPolicy: "pairing"`。
128
+ - `allowFrom` 仍然适合预授权用户或人工补充白名单;配对批准结果会写入 OpenClaw 的 pairing allowlist store。
129
+ - 如果 `proxy.url` 已经包含认证信息,可以不再填写 `proxy.username` 和 `proxy.password`。
130
+
131
+ ## 配对模式
132
+
133
+ 私聊推荐这样配置:
134
+
135
+ ```json
136
+ {
137
+ "channels": {
138
+ "mixin": {
139
+ "dmPolicy": "pairing"
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ 行为说明:
146
+
147
+ - 未授权的私聊用户会先收到一个 8 位配对码。
148
+ - 管理员使用 `openclaw pairing approve mixin <code>` 完成批准。
149
+ - 使用 `openclaw pairing list mixin` 查看待批准的配对请求。
150
+ - 批准后,该用户会被加入 OpenClaw 的 `mixin` pairing allowlist store。
151
+ - `allowFrom` 仍然生效,可以和 pairing 一起使用。
152
+
153
+ ## 避免跨频道串会话
154
+
155
+ Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 OpenClaw `session.dmScope` 配置。如果保持默认的 `main`,Mixin 私聊可能会和飞书等其他频道共用同一个主会话。
156
+
157
+ 推荐这样配置:
158
+
159
+ ```json
160
+ {
161
+ "session": {
162
+ "dmScope": "per-channel-peer"
163
+ }
164
+ }
165
+ ```
166
+
167
+ 如果你同时运行多个 Mixin 账号,并且希望私聊按“账号 + 频道”进一步隔离,可以改用 `per-account-channel-peer`。
168
+
169
+ ## 多机器人直绑不同 Agent
170
+
171
+ OpenClaw 支持通过 `bindings[].match.accountId` 把不同的频道账号直接路由到不同 agent。
172
+
173
+ 推荐做法:
174
+
175
+ - 一套 Mixin 机器人账号对应一个 `accountId`
176
+ - 一个 `accountId` 对应一条 agent 绑定
177
+ - 多账号场景下,`session.dmScope` 建议使用 `per-account-channel-peer`
178
+
179
+ 示例:
180
+
181
+ ```json
182
+ {
183
+ "session": {
184
+ "dmScope": "per-account-channel-peer"
185
+ },
186
+ "agents": {
187
+ "list": [
188
+ {
189
+ "id": "main",
190
+ "workspace": "E:/AI/workspace-main",
191
+ "default": true
192
+ },
193
+ {
194
+ "id": "sales",
195
+ "workspace": "E:/AI/workspace-sales"
196
+ },
197
+ {
198
+ "id": "support",
199
+ "workspace": "E:/AI/workspace-support"
200
+ }
201
+ ]
202
+ },
203
+ "bindings": [
204
+ {
205
+ "agentId": "main",
206
+ "match": {
207
+ "channel": "mixin",
208
+ "accountId": "default"
209
+ }
210
+ },
211
+ {
212
+ "agentId": "sales",
213
+ "match": {
214
+ "channel": "mixin",
215
+ "accountId": "sales"
216
+ }
217
+ },
218
+ {
219
+ "agentId": "support",
220
+ "match": {
221
+ "channel": "mixin",
222
+ "accountId": "support"
223
+ }
224
+ }
225
+ ],
226
+ "channels": {
227
+ "mixin": {
228
+ "defaultAccount": "default",
229
+ "accounts": {
230
+ "default": {
231
+ "name": "Main Bot",
232
+ "appId": "APP_ID_1",
233
+ "sessionId": "SESSION_ID_1",
234
+ "serverPublicKey": "SERVER_PUBLIC_KEY_1",
235
+ "sessionPrivateKey": "SESSION_PRIVATE_KEY_1"
236
+ },
237
+ "sales": {
238
+ "name": "Sales Bot",
239
+ "appId": "APP_ID_2",
240
+ "sessionId": "SESSION_ID_2",
241
+ "serverPublicKey": "SERVER_PUBLIC_KEY_2",
242
+ "sessionPrivateKey": "SESSION_PRIVATE_KEY_2"
243
+ },
244
+ "support": {
245
+ "name": "Support Bot",
246
+ "appId": "APP_ID_3",
247
+ "sessionId": "SESSION_ID_3",
248
+ "serverPublicKey": "SERVER_PUBLIC_KEY_3",
249
+ "sessionPrivateKey": "SESSION_PRIVATE_KEY_3"
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
257
+ 说明:
258
+
259
+ - `match.accountId` 用来把某一套 Mixin 机器人账号绑定到某个 agent。
260
+ - 如果绑定里省略 `accountId`,OpenClaw 会把它当成默认账号的匹配。
261
+ - 只有在你希望所有 Mixin 账号都走同一个兜底 agent 时,才使用 `accountId: "*"`。
262
+ - 如果你还想让某个具体群或某个私聊覆盖账号级路由,可以再补更具体的 `match.peer` 绑定;`peer` 精确匹配优先级高于 `accountId`。
263
+
264
+ ## 配置参数
265
+
266
+ | 参数 | 必填 | 默认值 | 说明 |
267
+ |-----------|----------|---------|-------------|
268
+ | `defaultAccount` | 否 | `default` | 配置了 `accounts` 时默认使用的账号 ID |
269
+ | `appId` | 是 | - | Mixin 应用 UUID |
270
+ | `sessionId` | 是 | - | Session UUID |
271
+ | `serverPublicKey` | 是 | - | 服务端公钥 Base64 |
272
+ | `sessionPrivateKey` | 是 | - | 会话私钥 Ed25519 Base64 |
273
+ | `dmPolicy` | 否 | `pairing` | 私聊策略:`pairing`、`allowlist`、`open`、`disabled` |
274
+ | `allowFrom` | 否 | `[]` | 授权用户 UUID 白名单 |
275
+ | `groupPolicy` | 否 | OpenClaw 默认值 | 群消息策略:`open`、`allowlist`、`disabled` |
276
+ | `groupAllowFrom` | 否 | `[]` | 当 `groupPolicy` 使用 allowlist 时,允许触发群消息的发送者 UUID 白名单 |
277
+ | `requireMentionInGroup` | 否 | `true` | 仅对已经投递到插件的群消息启用插件侧触发词过滤 |
278
+ | `mediaBypassMentionInGroup` | 否 | `true` | 是否允许群里的文件/语音消息绕过文本触发词过滤 |
279
+ | `mediaMaxMb` | 否 | `30` | 入站和出站媒体大小上限,单位 MB |
280
+ | `audioSendAsVoiceByDefault` | 否 | `true` | OpenClaw 原生音频出站时尽量按 Mixin 语音发送 |
281
+ | `audioAutoDetectDuration` | 否 | `true` | 是否在发送原生音频前使用 `ffprobe` 自动探测时长 |
282
+ | `audioRequireFfprobe` | 否 | `false` | 时长探测不可用时是否直接失败,而不是降级为文件发送 |
283
+ | `mixpay.enabled` | 否 | `false` | 是否为当前 Mixin 账号启用 MixPay 收款 |
284
+ | `mixpay.payeeId` | 启用时必填 | - | 用于创建 one-time payment 的 MixPay 收款方 ID |
285
+ | `mixpay.defaultQuoteAssetId` | 否 | - | `mixin-collect` 模板或未来收款命令使用的默认计价资产 ID |
286
+ | `mixpay.defaultSettlementAssetId` | 否 | - | MixPay 订单默认结算资产 ID |
287
+ | `mixpay.expireMinutes` | 否 | `15` | MixPay 订单默认过期时间,单位分钟 |
288
+ | `mixpay.pollIntervalSec` | 否 | `30` | 待支付 MixPay 订单的后台轮询间隔,单位秒 |
289
+ | `mixpay.allowedCreators` | 否 | `[]` | 允许创建 MixPay 收款单的发送者 UUID 白名单 |
290
+ | `mixpay.notifyOnPending` | 否 | `false` | 当 MixPay 返回 `pending` 时是否在会话里通知 |
291
+ | `mixpay.notifyOnPaidLess` | 否 | `true` | 当 MixPay 返回少付状态时是否在会话里通知 |
292
+ | `conversations.<conversationId>.enabled` | 否 | `true` | 是否启用某个指定群会话 |
293
+ | `conversations.<conversationId>.requireMention` | 否 | 继承账号级配置 | 覆盖该群会话的触发词要求 |
294
+ | `conversations.<conversationId>.allowFrom` | 否 | 继承账号级配置 | 覆盖该群会话的发送者白名单 |
295
+ | `conversations.<conversationId>.mediaBypassMention` | 否 | 继承账号级配置 | 覆盖该群会话中文件/语音是否绕过触发词过滤 |
296
+ | `conversations.<conversationId>.groupPolicy` | 否 | 继承账号级配置 | 覆盖该群会话的群消息策略 |
297
+ | `debug` | 否 | `false` | 调试模式 |
298
+ | `proxy.enabled` | 否 | `false` | 是否启用插件级代理 |
299
+ | `proxy.url` | 启用时必填 | - | 代理地址,例如 `http://127.0.0.1:7890` 或 `socks5://127.0.0.1:10808` |
300
+ | `proxy.username` | 否 | - | 代理用户名 |
301
+ | `proxy.password` | 否 | - | 代理密码 |
302
+
303
+ ## 代理
304
+
305
+ - Mixin 的 HTTP 请求和 Blaze WebSocket 都会走同一个代理。
306
+ - 常见代理地址格式包括 `http://...`、`https://...`、`socks5://...`。
307
+ - 代理软件或代理服务器需要你自己提供,插件只负责使用代理。
308
+
309
+ ## 群聊访问控制
310
+
311
+ 现在除了私聊 `dmPolicy`,Mixin 也支持正式的群聊访问控制:
312
+
313
+ - `groupPolicy: "open"` 表示群里任何发送者都可以触发。
314
+ - `groupPolicy: "allowlist"` 表示只有 `groupAllowFrom` 里的发送者 UUID 可以触发。
315
+ - `groupPolicy: "disabled"` 表示整个群会话被禁用。
316
+ - `conversations.<conversationId>` 可以对某一个群会话覆盖账号级配置。
317
+
318
+ 关于群消息投递边界:
319
+
320
+ - 目前从实际联调看,Mixin 群里稳定可用的触发方式仍然是显式 `@bot`。
321
+ - `requireMentionInGroup: false` 只表示关闭插件自身的群消息二次过滤。
322
+ - 它不能保证 Mixin 平台一定把所有未 `@` 的群消息投递给机器人。
323
+ - 如果群里未 `@` 的消息既没有已读,也没有任何入站日志,通常说明这条消息根本没有被 Mixin 投递到插件。
324
+
325
+ 示例:
326
+
327
+ ```json
328
+ {
329
+ "channels": {
330
+ "mixin": {
331
+ "groupPolicy": "allowlist",
332
+ "groupAllowFrom": ["USER_A_UUID"],
333
+ "conversations": {
334
+ "70000000-0000-0000-0000-000000000001": {
335
+ "requireMention": false,
336
+ "allowFrom": ["USER_B_UUID"],
337
+ "mediaBypassMention": false
338
+ },
339
+ "70000000-0000-0000-0000-000000000002": {
340
+ "enabled": false
341
+ }
342
+ }
343
+ }
344
+ }
345
+ }
346
+ ```
347
+
348
+ 这些值怎么获取:
349
+
350
+ - `conversations.<conversationId>`:这里填的是群会话的 `conversation_id`。最简单的方式是先让目标群给 bot 发一条消息,然后从插件日志或入站上下文里读取 `conversationId`。Mixin 的群会话 API 里用的也是同一个 `conversation_id` 字段。
351
+ - `groupAllowFrom` 或 `conversations.<conversationId>.allowFrom`:这里填的是发送者的 Mixin `user_id` UUID。官方说明里,应用可以在用户给 bot 发消息、添加 bot 为联系人、或授权应用后获得这个 `user_id`。
352
+ - 如果你通过 Mixin API 管理群,会话详情返回里也会带参与者列表,其中就包含每个成员的 `user_id`。
353
+
354
+ 推荐操作方式:
355
+
356
+ - 先让目标群给 bot 发一条消息
357
+ - 从日志里抄下 `conversationId`
358
+ - 再让目标成员发一条消息,从日志里抄下该成员的 `user_id`
359
+ - 把这些值填进 `conversations.<conversationId>` 和 `groupAllowFrom` / `allowFrom`
360
+
361
+ 更快的方式:
362
+
363
+
364
+ 类似 pairing 的群授权方式:
365
+
366
+ - 未授权成员可以直接在目标群发送 `/mixin-group-auth`
367
+ - 插件会返回一个针对当前 `conversationId` 的临时批准码
368
+ - 管理员需要在 OpenClaw 终端执行 `openclaw pairing approve mixin <code>` 完成批准
369
+ - 如果使用的是非默认账号,请执行 `openclaw pairing approve --account <accountId> mixin <code>`
370
+ - 批准后,整个群会话都会生效,不需要手改 `openclaw.json`
371
+ - 同一个未授权群反复发送 `/mixin-group-auth` 会被限频,避免刷屏
372
+
373
+ 日志里看哪里:
374
+
375
+ - 插件在路由解析时会打印类似 `peer.kind=group, peer.id=<conversationId>`,这里的 `peer.id` 就是群的 `conversationId`
376
+ - 群消息被拦截或未授权时,日志里会带 `group sender <user_id>` 和 `conversationId=<conversationId>`
377
+ - 如果现场不好拿值,可以临时把群策略收紧一点,让目标成员先发一条消息;拒绝日志通常是最快同时拿到这两个值的方式
378
+
379
+ ## 使用方式
380
+
381
+ - 私聊:`/status` 或 `Hello`
382
+ - 群聊:`@Bot your question`,并带上 `?` 或 `help` 等触发词
383
+
384
+ ## 运维
385
+
386
+ 常用 OpenClaw 命令:
387
+
388
+ ```bash
389
+ openclaw plugins list
390
+ openclaw plugins info mixin
391
+ openclaw plugins update mixin
392
+ openclaw channels status --probe
393
+ openclaw status
394
+ ```
395
+
396
+ 插件内诊断命令:
397
+
398
+ - 发送 `/mixin-outbox` 可查看当前待发队列数量、下次重试时间和最新错误。
399
+ - 发送 `/mixin-outbox purge-invalid` 可删除历史遗留的 `APP_CARD` / `APP_BUTTON_GROUP` 永久无效重试项。
400
+ - 在目标群发送 `/mixin-group-auth`,可创建一条待批准的群授权请求。
401
+ - 在 OpenClaw 终端执行 `openclaw pairing approve mixin <code>`,可批准这条群授权请求。
402
+ - 如果使用的是非默认账号,请执行 `openclaw pairing approve --account <accountId> mixin <code>`。
403
+ - 发送 `/collect status <orderId>` 可刷新并查看某个 MixPay 收款单状态。
404
+ - 发送 `/collect recent` 或 `/collect recent 10` 可查看当前会话最近的 MixPay 收款单。
405
+
406
+ 配套运维 CLI:
407
+
408
+ - 仓库里附带了一套配套工具,见 `tools/mixin-plugin-onboard/README.md`。
409
+ - 这套工具会和主包 `@invago/mixin` 一起发布,不再是单独的第二个 npm 包。
410
+ - 当前提供 `info`、`doctor`、`install`、`update` 四个命令,用于本地 OpenClaw + Mixin 插件的安装和诊断。
411
+ - 本地运行示例:
412
+ - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts info`
413
+ - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts doctor`
414
+ - 安装后使用示例:
415
+ - `npx -y @invago/mixin info`
416
+ - `npx -y @invago/mixin doctor`
417
+
418
+ ## 投递与重试行为
419
+
420
+ - 出站消息会先写入本地 outbox,再进行发送尝试。
421
+ - 发送失败会自动重试,直到成功。
422
+ - 插件重启后,未完成的消息仍会继续补发。
423
+ - 入站 Blaze 消息会在分发前尽快 ACK,尽量让 Mixin 更早收到已读回执。
424
+
425
+ ## 媒体支持
426
+
427
+ 当前媒体能力分为出站和入站两部分:
428
+
429
+ - OpenClaw 原生媒体发送已经接入频道 `sendMedia` 路径。
430
+ - OpenClaw 原生 `sendPayload` 现在和 agent 缓冲回复共用同一套 Mixin outbound planner,所以 text/post/buttons/card/file/audio 的选择逻辑保持一致。
431
+ - 当插件能把媒体识别为音频并成功拿到时长时,会优先按 `PLAIN_AUDIO` 发送。
432
+ - 如果拿不到音频时长,会平稳降级为普通文件附件发送。
433
+ - 非音频媒体会按 Mixin 文件附件发送。
434
+ - 如果 OpenClaw 同时给出文本和媒体,插件会先发文本,再发文件。
435
+ - 语音气泡式发送目前仍然更适合走显式 `mixin-audio` 模板。
436
+ - 入站 `PLAIN_DATA` 和 `PLAIN_AUDIO` 会被下载到本地,并通过 `MediaPath` / `MediaType` 挂到 OpenClaw 入站上下文。
437
+ - 即使启用了 `requireMentionInGroup`,群里的附件消息也不会被直接过滤;如果你把 `mediaBypassMentionInGroup` 设为 `false`,则会恢复和普通文本相同的群聊触发规则。
438
+
439
+ 当前边界:
440
+
441
+ - 发送语音时不做自动转码。
442
+ - `mixin-audio` 仍然要求你提供已经准备好的本地文件、显式 `duration`,以及可选的 `waveForm`。
443
+ - OpenClaw 原生音频发送依赖本机 `ffprobe` 来提取时长。
444
+ - OpenClaw 原生 `sendMedia` 仍然不会自动生成 `waveForm`,所以如果你想更稳定地控制语音消息效果,显式 `mixin-audio` 仍然是更可控的路径。
445
+ - 能否自动总结文件、转写语音,取决于你的 OpenClaw 媒体理解配置。
446
+
447
+ 联调手册:
448
+
449
+ - 见 [docs/media-testing.md](docs/media-testing.md)。
450
+
451
+ ## MixPay 收款
452
+
453
+ Mixin 现在已经支持通过 MixPay one-time payment 做收款。
454
+
455
+ 当前能力:
456
+
457
+ - 显式模板 `mixin-collect` 可以创建一笔 MixPay 收款单
458
+ - 收款单会保存到 OpenClaw state 目录下的本地 store
459
+ - 待支付订单会在后台轮询
460
+ - 成功或终态变化会自动回发到原始会话
461
+ - `/collect status <orderId>` 会在回复前主动去 MixPay 刷新一次状态
462
+ - 如果配置了 `mixpay.defaultQuoteAssetId`,模板里的 `assetId` 可以省略
463
+
464
+ 模板示例:
465
+
466
+ ````text
467
+ ```mixin-collect
468
+ {
469
+ "amount": "1",
470
+ "assetId": "c6d0c728-2624-429b-8e0d-d9d19b6592fa",
471
+ "memo": "Order #1001"
472
+ }
473
+ ```
474
+ ````
475
+
476
+ 规则:
477
+
478
+ - `amount` 必填;如果未配置 `mixpay.defaultQuoteAssetId`,则 `assetId` 也必填
479
+ - `settlementAssetId`、`memo`、`orderId`、`expireMinutes` 都是可选项
480
+ - 支付成功以 MixPay 服务端查询结果为准,不以客户端支付页结果为准
481
+ - `mixpay.allowedCreators` 可以限制谁有权限创建收款单
482
+
483
+ 钱会收到哪里:
484
+
485
+ - 如果 MixPay 账户类型是 `Mixin account`,资金会结算到对应的 Mixin Wallet
486
+ - 如果 MixPay 账户类型是 `Mixin Robot account`,资金会结算到对应的 Mixin Robot Wallet
487
+ - 其他 MixPay 账户类型会结算到各自关联的钱包类型
488
+
489
+ 对这个插件的推荐配置方式:
490
+
491
+ - 优先使用 MixPay 的 `Mixin account` 或 `Mixin Robot account`
492
+ - 将该账户的 UUID 作为 `mixpay.payeeId`
493
+ - 如果你希望模板更短,建议同时配置 `mixpay.defaultQuoteAssetId` 和 `mixpay.defaultSettlementAssetId`
494
+
495
+ 如何获取所需配置:
496
+
497
+ - `mixpay.payeeId`:登录 [MixPay Dashboard](https://dashboard.mixpay.me) 后,在设置页查看 UUID;也可以使用 MixPay 官方入门文档里提到的辅助机器人获取
498
+ - `mixpay.defaultQuoteAssetId`:选择你希望用于报价的资产 ID
499
+ - `mixpay.defaultSettlementAssetId`:选择你希望最终收款结算到的资产 ID
500
+
501
+ 最小推荐配置:
502
+
503
+ ```json
504
+ {
505
+ "channels": {
506
+ "mixin": {
507
+ "mixpay": {
508
+ "enabled": true,
509
+ "payeeId": "YOUR_MIXPAY_UUID",
510
+ "defaultQuoteAssetId": "YOUR_QUOTE_ASSET_ID",
511
+ "defaultSettlementAssetId": "YOUR_SETTLEMENT_ASSET_ID"
512
+ }
513
+ }
514
+ }
515
+ }
516
+ ```
517
+
518
+ 配置放在哪里:
519
+
520
+ - 单账号场景:把 `mixpay` 放在 `channels.mixin.mixpay`
521
+ - 多账号场景:把 `mixpay` 放在 `channels.mixin.accounts.<accountId>.mixpay`
522
+ - `mixpay` 是账号级配置,所以不同的 Mixin 机器人账号可以使用不同的 MixPay 设置
523
+
524
+ 字段说明:
525
+
526
+ - `mixpay.enabled`:是否为当前这套 Mixin 账号启用 MixPay 收款
527
+ - `mixpay.apiBaseUrl`:可选的 MixPay API 基础地址;通常留空即可,默认走官方接口
528
+ - `mixpay.payeeId`:真正收款的 MixPay 收款方 UUID;启用 MixPay 收款时必填
529
+ - `mixpay.defaultQuoteAssetId`:默认报价资产 ID;配置后,`mixin-collect` 模板里的 `assetId` 可以省略
530
+ - `mixpay.defaultSettlementAssetId`:默认结算资产 ID;决定订单优先结算到哪种资产
531
+ - `mixpay.expireMinutes`:新建收款单的默认过期时间,单位分钟
532
+ - `mixpay.pollIntervalSec`:后台轮询待支付订单的间隔,单位秒;越小越快发现支付结果,但会产生更多 MixPay API 请求
533
+ - `mixpay.allowedCreators`:可选的发送者 UUID 白名单;当这个列表非空时,只有这些用户可以在聊天里创建收款单
534
+ - `mixpay.notifyOnPending`:当 MixPay 返回 `pending` 时,是否在会话里发送状态通知
535
+ - `mixpay.notifyOnPaidLess`:当 MixPay 返回少付状态时,是否在会话里发送状态通知
536
+
537
+ 实用建议:
538
+
539
+ - 如果你只想先配出最小可用集,建议至少填写 `enabled`、`payeeId`、`defaultQuoteAssetId`、`defaultSettlementAssetId`
540
+ - 如果你不希望授权会话里的所有人都能创建收款单,就配置 `allowedCreators`
541
+ - 如果你没有自建 MixPay 网关,`apiBaseUrl` 保持留空即可
542
+ - 如果你不想在聊天里看到太多中间态通知,保持 `notifyOnPending: false` 即可
543
+
544
+ ## 显式回复模板
545
+
546
+ 如果你希望 Mixin 回复严格按指定形式发送,而不是依赖自动判断,可以让 agent 只输出一个 fenced code block 模板。
547
+
548
+ 文本:
549
+
550
+ ```text
551
+ ```mixin-text
552
+ 简短纯文本回复
553
+ ```
554
+ ```
555
+
556
+ 长文:
557
+
558
+ ```text
559
+ ```mixin-post
560
+ # 发布说明
561
+
562
+ - 条目 1
563
+ - 条目 2
564
+ ```
565
+ ```
566
+
567
+ 按钮组:
568
+
569
+ ```text
570
+ ```mixin-buttons
571
+ {
572
+ "intro": "请选择操作",
573
+ "buttons": [
574
+ { "label": "打开文档", "action": "https://docs.openclaw.ai" },
575
+ { "label": "打开 Mixin", "action": "https://developers.mixin.one" }
576
+ ]
577
+ }
578
+ ```
579
+ ```
580
+
581
+ 卡片:
582
+
583
+ ```text
584
+ ```mixin-card
585
+ {
586
+ "title": "OpenClaw 文档",
587
+ "description": "打开官方文档站点",
588
+ "action": "https://docs.openclaw.ai",
589
+ "coverUrl": "https://example.com/cover.png",
590
+ "shareable": true
591
+ }
592
+ ```
593
+ ```
594
+
595
+ 文件:
596
+
597
+ ```text
598
+ ```mixin-file
599
+ {
600
+ "filePath": "/absolute/path/to/report.pdf",
601
+ "fileName": "report.pdf",
602
+ "mimeType": "application/pdf"
603
+ }
604
+ ```
605
+ ```
606
+
607
+ 音频:
608
+
609
+ ```text
610
+ ```mixin-audio
611
+ {
612
+ "filePath": "/absolute/path/to/voice.ogg",
613
+ "mimeType": "audio/ogg",
614
+ "duration": 12,
615
+ "waveForm": "AAMMQQ=="
616
+ }
617
+ ```
618
+ ```
619
+
620
+ 规则:
621
+
622
+ - 显式模板优先级高于自动检测。
623
+ - 包含表格或 fenced code block 的回复默认按 `mixin-post` 发送。
624
+ - `mixin-buttons` 和 `mixin-card` 只接受 JSON。
625
+ - `mixin-file`、`mixin-audio`、`mixin-collect` 也只接受 JSON。
626
+ - `mixin-audio` 要求 `duration` 以秒为单位,`waveForm` 可选。
627
+ - `mixin-file` 和 `mixin-audio` 要求使用 OpenClaw 所在机器上的绝对本地路径。
628
+ - 无效的显式 `mixin-*` 模板不会再被静默丢弃,插件会发送可见的 `Mixin template error: ...` 提示。
629
+ - 按钮和卡片链接必须使用 `http://` 或 `https://`。
630
+ - Mixin 客户端可能要求目标域名已经加入 bot 应用的 `Resource Patterns` 白名单。
631
+
632
+ ## 多账号示例
633
+
634
+ ```json
635
+ {
636
+ "channels": {
637
+ "mixin": {
638
+ "accounts": {
639
+ "bot1": {
640
+ "name": "Customer Service Bot",
641
+ "appId": "...",
642
+ "sessionId": "...",
643
+ "serverPublicKey": "...",
644
+ "sessionPrivateKey": "...",
645
+ "dmPolicy": "pairing",
646
+ "allowFrom": ["..."]
647
+ },
648
+ "bot2": {
649
+ "name": "Tech Support Bot",
650
+ "appId": "...",
651
+ "sessionId": "...",
652
+ "serverPublicKey": "...",
653
+ "sessionPrivateKey": "...",
654
+ "proxy": {
655
+ "enabled": true,
656
+ "url": "http://127.0.0.1:7890"
657
+ }
658
+ }
659
+ }
660
+ }
661
+ }
662
+ }
663
+ ```
664
+
665
+ ## 故障排查
666
+
667
+ | 问题 | 检查项 |
668
+ |---------|---------------|
669
+ | 插件未加载 | 运行 `openclaw plugins list` 和 `openclaw plugins info mixin` |
670
+ | 频道未启动 | 确认 `channels.mixin` 存在且凭证完整 |
671
+ | 收不到消息 | 检查 pairing/`allowFrom`、触发词以及 Blaze 连通性 |
672
+ | 消息发不出去 | 检查代理可达性、outbox 堆积以及 `/mixin-outbox` 输出 |
673
+ | 入站重复推送 | 检查 Blaze 连通性以及 ACK 日志/行为 |
674
+
675
+ ## 安全说明
676
+
677
+ - 妥善保管 `sessionPrivateKey`。
678
+ - 生产环境建议使用 `dmPolicy: "pairing"` 或严格的 `allowFrom` 白名单。
679
+ - outbox 文件包含待发送消息内容,不要暴露状态目录中的相关文件。
680
+
681
+ ## 相关链接
682
+
683
+ - [OpenClaw Documentation](https://openclaw.ai)
684
+ - [OpenClaw Plugins](https://docs.openclaw.ai/tools/plugin)
685
+ - [OpenClaw Plugin CLI](https://docs.openclaw.ai/cli/plugins)
686
+ - [OpenClaw Configuration](https://docs.openclaw.ai/gateway/configuration)
687
+ - [OpenClaw Configuration Reference](https://docs.openclaw.ai/gateway/configuration-reference)
688
+ - [Mixin Developers Dashboard](https://developers.mixin.one/dashboard)
689
+ - [Mixin Bot API Documentation](https://developers.mixin.one/docs/bot-api)
690
+
691
+ ## OpenClaw 3.23 说明
692
+
693
+ - 插件清单使用 `openclaw.plugin.json`。
694
+ - 频道配置仍然放在 `channels.mixin` 和 `channels.mixin.accounts.<accountId>` 下。
695
+ - 宿主侧诊断命令为 `/setup`、`/setup single`、`/setup multi`、`/mixin-status`、`/mixin-accounts`、`/mixin-help`。
696
+ - 本地开发建议使用 `openclaw plugins install -l .`。
697
+
698
+ - 使用 `/setup` 进入配置引导流程。