@invago/mixin 1.0.7 → 1.0.9

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.md CHANGED
@@ -65,11 +65,19 @@ Edit your `openclaw.json` file manually and add both the channel configuration a
65
65
  "channels": {
66
66
  "mixin": {
67
67
  "enabled": true,
68
+ "defaultAccount": "default",
68
69
  "appId": "YOUR_APP_ID",
69
70
  "sessionId": "YOUR_SESSION_ID",
70
71
  "serverPublicKey": "YOUR_SERVER_PUBLIC_KEY_BASE64",
71
72
  "sessionPrivateKey": "YOUR_SESSION_PRIVATE_KEY_BASE64",
73
+ "dmPolicy": "pairing",
72
74
  "allowFrom": ["AUTHORIZED_USER_UUID"],
75
+ "requireMentionInGroup": true,
76
+ "mediaBypassMentionInGroup": true,
77
+ "mediaMaxMb": 30,
78
+ "audioSendAsVoiceByDefault": true,
79
+ "audioAutoDetectDuration": true,
80
+ "audioRequireFfprobe": false,
73
81
  "proxy": {
74
82
  "enabled": true,
75
83
  "url": "socks5://127.0.0.1:10808",
@@ -93,9 +101,32 @@ Notes:
93
101
 
94
102
  - `channels.mixin` configures the channel itself.
95
103
  - `plugins.allow` and `plugins.entries.mixin.enabled` are also required so OpenClaw loads this plugin.
96
- - This plugin currently uses `allowFrom` as its sender allowlist. Do not assume other generic OpenClaw DM policy fields apply here unless the plugin explicitly supports them.
104
+ - Mixin supports the standard OpenClaw direct-message policies. The recommended setting is `dmPolicy: "pairing"`.
105
+ - `allowFrom` remains useful for pre-authorized users or manual overrides. Pairing approvals are stored in OpenClaw's pairing allowlist store.
97
106
  - If `proxy.url` already contains credentials, `proxy.username` and `proxy.password` can be omitted.
98
107
 
108
+ ## Pairing
109
+
110
+ For private chats, the recommended mode is:
111
+
112
+ ```json
113
+ {
114
+ "channels": {
115
+ "mixin": {
116
+ "dmPolicy": "pairing"
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ Behavior:
123
+
124
+ - A new, unauthorized Mixin user gets an 8-character pairing code in the DM.
125
+ - Approve that user with `openclaw pairing approve mixin <code>`.
126
+ - Use `openclaw pairing list mixin` to inspect pending pairing requests.
127
+ - Once approved, the user is added to OpenClaw's pairing allowlist store for the `mixin` channel.
128
+ - `allowFrom` is still honored and can be used alongside pairing for users you want to pre-authorize.
129
+
99
130
  ## Avoid Cross-Channel Session Mixing
100
131
 
101
132
  Mixin group chats already stay isolated by channel, but direct-message sessions follow the OpenClaw `session.dmScope` policy. If you keep the default `main` scope, Mixin direct messages can share the same main session with other channels such as Feishu.
@@ -117,12 +148,26 @@ Use `per-account-channel-peer` instead if you run multiple Mixin accounts and wa
117
148
  | Parameter | Required | Default | Description |
118
149
  |-----------|----------|---------|-------------|
119
150
  | `enabled` | No | `true` | Enable or disable this channel account |
151
+ | `defaultAccount` | No | `default` | Default account ID used when `accounts` is configured |
120
152
  | `appId` | Yes | - | Mixin App UUID |
121
153
  | `sessionId` | Yes | - | Session UUID |
122
154
  | `serverPublicKey` | Yes | - | Server Public Key (Base64) |
123
155
  | `sessionPrivateKey` | Yes | - | Session Private Key (Ed25519 Base64) |
156
+ | `dmPolicy` | No | `pairing` | Direct-message policy: `pairing`, `allowlist`, `open`, or `disabled` |
124
157
  | `allowFrom` | No | `[]` | Authorized user UUID whitelist |
158
+ | `groupPolicy` | No | OpenClaw default | Group-message policy: `open`, `allowlist`, or `disabled` |
159
+ | `groupAllowFrom` | No | `[]` | Authorized sender UUID whitelist for group messages when `groupPolicy` uses allowlisting |
125
160
  | `requireMentionInGroup` | No | `true` | Require trigger words in group chats |
161
+ | `mediaBypassMentionInGroup` | No | `true` | Allow inbound group file/audio messages through even without trigger text |
162
+ | `mediaMaxMb` | No | `30` | Max inbound and outbound media size in MB |
163
+ | `audioSendAsVoiceByDefault` | No | `true` | Send OpenClaw native outbound audio as Mixin voice when possible |
164
+ | `audioAutoDetectDuration` | No | `true` | Detect native outbound audio duration with `ffprobe` before sending voice |
165
+ | `audioRequireFfprobe` | No | `false` | Fail native outbound audio instead of falling back to file when duration detection is unavailable |
166
+ | `conversations.<conversationId>.enabled` | No | `true` | Enable or disable a specific group conversation |
167
+ | `conversations.<conversationId>.requireMention` | No | Inherit account | Override group trigger-word requirement for a specific conversation |
168
+ | `conversations.<conversationId>.allowFrom` | No | Inherit account | Override group sender allowlist for a specific conversation |
169
+ | `conversations.<conversationId>.mediaBypassMention` | No | Inherit account | Override whether file/audio messages bypass mention filtering |
170
+ | `conversations.<conversationId>.groupPolicy` | No | Inherit account | Override group policy for a specific conversation |
126
171
  | `debug` | No | `false` | Debug mode |
127
172
  | `proxy.enabled` | No | `false` | Enable per-plugin proxy |
128
173
  | `proxy.url` | Required when enabled | - | Proxy URL such as `http://127.0.0.1:7890` or `socks5://127.0.0.1:10808` |
@@ -135,6 +180,38 @@ Use `per-account-channel-peer` instead if you run multiple Mixin accounts and wa
135
180
  - Supported proxy URL styles depend on the underlying proxy agent stack; typical values are `http://...`, `https://...`, and `socks5://...`.
136
181
  - You must provide your own proxy software or proxy server. The plugin only consumes a proxy, it does not create one.
137
182
 
183
+ ## Group Access Control
184
+
185
+ Mixin now supports formal group access controls in addition to direct-message `dmPolicy`.
186
+
187
+ - `groupPolicy: "open"` allows any sender in a group conversation.
188
+ - `groupPolicy: "allowlist"` requires the sender UUID to appear in `groupAllowFrom`.
189
+ - `groupPolicy: "disabled"` blocks the entire conversation.
190
+ - `conversations.<conversationId>` overrides account-level group settings for that single conversation.
191
+
192
+ Example:
193
+
194
+ ```json
195
+ {
196
+ "channels": {
197
+ "mixin": {
198
+ "groupPolicy": "allowlist",
199
+ "groupAllowFrom": ["USER_A_UUID"],
200
+ "conversations": {
201
+ "70000000-0000-0000-0000-000000000001": {
202
+ "requireMention": false,
203
+ "allowFrom": ["USER_B_UUID"],
204
+ "mediaBypassMention": false
205
+ },
206
+ "70000000-0000-0000-0000-000000000002": {
207
+ "enabled": false
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+ ```
214
+
138
215
  ## Usage
139
216
 
140
217
  - Direct message: `/status` or `Hello`
@@ -156,6 +233,18 @@ Plugin-specific command:
156
233
  - Send `/mixin-outbox` to inspect the current pending queue size, next retry time, and latest error.
157
234
  - Send `/mixin-outbox purge-invalid` to remove old `APP_CARD` / `APP_BUTTON_GROUP` entries that are stuck on permanent invalid-field errors.
158
235
 
236
+ Companion onboarding CLI:
237
+
238
+ - This repository also includes a companion CLI at [tools/mixin-plugin-onboard/README.md](/E:/AI/mixin-claw/tools/mixin-plugin-onboard/README.md).
239
+ - It is bundled into the same npm package, `@invago/mixin`.
240
+ - It currently provides `info`, `doctor`, `install`, and `update` commands for local OpenClaw + Mixin plugin maintenance.
241
+ - Local examples:
242
+ - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts info`
243
+ - `node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts doctor`
244
+ - Installed package examples:
245
+ - `npx -y @invago/mixin info`
246
+ - `npx -y @invago/mixin doctor`
247
+
159
248
  ## Delivery and Retry Behavior
160
249
 
161
250
  - Outbound messages are persisted to a local outbox before send attempts.
@@ -163,6 +252,32 @@ Plugin-specific command:
163
252
  - Pending messages survive plugin restarts.
164
253
  - Inbound Blaze messages are acknowledged before dispatch so Mixin receives a read receipt as early as possible.
165
254
 
255
+ ## Media Support
256
+
257
+ Current media behavior is split into outbound and inbound support:
258
+
259
+ - OpenClaw native outbound media is enabled through the channel `sendMedia` path.
260
+ - OpenClaw native `sendPayload` now uses the same Mixin outbound planner as buffered agent replies, so text/post/buttons/card/file/audio selection is consistent.
261
+ - The plugin sends outbound audio as `PLAIN_AUDIO` when it can resolve the media as audio and detect duration.
262
+ - If audio duration cannot be detected, the plugin falls back to regular file attachment sending.
263
+ - Non-audio outbound media is sent as Mixin file attachments.
264
+ - If OpenClaw sends both caption text and media, the plugin sends the text first and then the file.
265
+ - Voice-bubble style outbound audio is currently intended for the explicit `mixin-audio` template path.
266
+ - Inbound `PLAIN_DATA` and `PLAIN_AUDIO` messages are downloaded, saved locally, and attached to the OpenClaw inbound context through `MediaPath` / `MediaType`.
267
+ - Group attachment messages are allowed through even when `requireMentionInGroup` is enabled, unless `mediaBypassMentionInGroup` is set to `false`.
268
+
269
+ Current limits:
270
+
271
+ - Outbound audio does not transcode automatically.
272
+ - `mixin-audio` still requires a prepared local file, explicit `duration`, and optional `waveForm`.
273
+ - OpenClaw native outbound audio depends on local `ffprobe` availability to detect duration.
274
+ - OpenClaw native `sendMedia` still does not generate `waveForm`, so explicit `mixin-audio` remains the most deterministic path for polished voice-message output.
275
+ - Whether the agent can summarize, transcribe, or reason over inbound files/audio depends on your OpenClaw media-understanding configuration.
276
+
277
+ Manual test guide:
278
+
279
+ - See [docs/media-testing.md](docs/media-testing.md) for ready-to-run prompts and expected results.
280
+
166
281
  ## Explicit Reply Templates
167
282
 
168
283
  When you want deterministic Mixin output instead of heuristic auto-selection, have the agent reply with exactly one fenced template block.
@@ -214,11 +329,40 @@ Card:
214
329
  ```
215
330
  ```
216
331
 
332
+ File:
333
+
334
+ ```text
335
+ ```mixin-file
336
+ {
337
+ "filePath": "/absolute/path/to/report.pdf",
338
+ "fileName": "report.pdf",
339
+ "mimeType": "application/pdf"
340
+ }
341
+ ```
342
+ ```
343
+
344
+ Audio:
345
+
346
+ ```text
347
+ ```mixin-audio
348
+ {
349
+ "filePath": "/absolute/path/to/voice.ogg",
350
+ "mimeType": "audio/ogg",
351
+ "duration": 12,
352
+ "waveForm": "AAMMQQ=="
353
+ }
354
+ ```
355
+ ```
356
+
217
357
  Rules:
218
358
 
219
359
  - Explicit templates take priority over automatic detection.
220
360
  - Replies containing tables or fenced code blocks are sent as `mixin-post` by default.
221
361
  - `mixin-buttons` and `mixin-card` accept JSON only.
362
+ - `mixin-file` and `mixin-audio` also accept JSON only.
363
+ - `mixin-audio` requires `duration` in seconds. `waveForm` is optional.
364
+ - `mixin-file` and `mixin-audio` require absolute local file paths on the machine where OpenClaw runs.
365
+ - Invalid explicit `mixin-*` templates are no longer dropped silently; the plugin now sends a visible `Mixin template error: ...` message instead.
222
366
  - Button and card links must use `http://` or `https://`.
223
367
  - Mixin clients may require your target domains to be present in the bot app's `Resource Patterns` allowlist.
224
368
 
@@ -235,6 +379,7 @@ Rules:
235
379
  "sessionId": "...",
236
380
  "serverPublicKey": "...",
237
381
  "sessionPrivateKey": "...",
382
+ "dmPolicy": "pairing",
238
383
  "allowFrom": ["..."]
239
384
  },
240
385
  "bot2": {
@@ -260,14 +405,14 @@ Rules:
260
405
  |---------|---------------|
261
406
  | Plugin not loaded | Run `openclaw plugins list` and `openclaw plugins info mixin` |
262
407
  | Channel not starting | Verify `channels.mixin` exists and credentials are complete |
263
- | Not receiving messages | Check `allowFrom`, trigger words, and Blaze connectivity |
408
+ | Not receiving messages | Check pairing approval or `allowFrom`, trigger words, and Blaze connectivity |
264
409
  | Messages not sending | Check proxy reachability, outbox backlog, and `/mixin-outbox` output |
265
410
  | Repeated inbound pushes | Check Blaze connectivity and confirm ACK logs/behavior |
266
411
 
267
412
  ## Security Notes
268
413
 
269
414
  - Keep `sessionPrivateKey` private.
270
- - Use `allowFrom` in production.
415
+ - Use `dmPolicy: "pairing"` or a strict `allowFrom` list in production.
271
416
  - Outbox files contain pending message bodies, so do not expose the `data/` directory.
272
417
 
273
418
  ## Links
package/README.zh-CN.md CHANGED
@@ -66,11 +66,19 @@ openclaw plugins install .
66
66
  "channels": {
67
67
  "mixin": {
68
68
  "enabled": true,
69
+ "defaultAccount": "default",
69
70
  "appId": "你的 App ID",
70
71
  "sessionId": "你的 Session ID",
71
72
  "serverPublicKey": "服务端公钥 Base64",
72
73
  "sessionPrivateKey": "会话私钥 Base64",
74
+ "dmPolicy": "pairing",
73
75
  "allowFrom": ["授权用户 UUID"],
76
+ "requireMentionInGroup": true,
77
+ "mediaBypassMentionInGroup": true,
78
+ "mediaMaxMb": 30,
79
+ "audioSendAsVoiceByDefault": true,
80
+ "audioAutoDetectDuration": true,
81
+ "audioRequireFfprobe": false,
74
82
  "proxy": {
75
83
  "enabled": true,
76
84
  "url": "socks5://127.0.0.1:10808",
@@ -94,9 +102,32 @@ openclaw plugins install .
94
102
 
95
103
  - `channels.mixin` 负责配置这个频道本身。
96
104
  - `plugins.allow` 和 `plugins.entries.mixin.enabled` 也需要配置,否则 OpenClaw 不会加载这个插件。
97
- - 当前插件使用 `allowFrom` 作为发送者白名单,不要直接套用其他 OpenClaw 通用 DM 策略字段,除非插件明确支持。
105
+ - Mixin 现在支持 OpenClaw 官方的私聊 `dmPolicy`,推荐使用 `dmPolicy: "pairing"`。
106
+ - `allowFrom` 仍然保留,适合预授权用户或人工补充白名单;配对批准结果会写入 OpenClaw 的 pairing allowlist store。
98
107
  - 如果 `proxy.url` 已经包含认证信息,可以不再填写 `proxy.username` 和 `proxy.password`。
99
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
+
100
131
  ## 避免跨通道串会话
101
132
 
102
133
  Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 OpenClaw 的 `session.dmScope` 配置。如果保持默认的 `main`,Mixin 私聊可能会和飞书等其它通道共用同一个主会话。
@@ -118,12 +149,26 @@ Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 O
118
149
  | 参数 | 必填 | 默认值 | 说明 |
119
150
  |------|------|--------|------|
120
151
  | `enabled` | 否 | `true` | 是否启用该频道账号 |
152
+ | `defaultAccount` | 否 | `default` | 配置了 `accounts` 时默认使用的账号 ID |
121
153
  | `appId` | 是 | - | Mixin 应用 UUID |
122
154
  | `sessionId` | 是 | - | 会话 UUID |
123
155
  | `serverPublicKey` | 是 | - | 服务端公钥 Base64 |
124
156
  | `sessionPrivateKey` | 是 | - | 会话私钥 Ed25519 Base64 |
157
+ | `dmPolicy` | 否 | `pairing` | 私聊策略:`pairing`、`allowlist`、`open`、`disabled` |
125
158
  | `allowFrom` | 否 | `[]` | 授权用户 UUID 白名单 |
159
+ | `groupPolicy` | 否 | 跟随 OpenClaw 默认值 | 群消息策略:`open`、`allowlist`、`disabled` |
160
+ | `groupAllowFrom` | 否 | `[]` | 当 `groupPolicy` 走 allowlist 时,允许触发群消息的发送者 UUID 白名单 |
126
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` | 否 | 继承账号级配置 | 覆盖该群会话的群消息策略 |
127
172
  | `debug` | 否 | `false` | 调试模式 |
128
173
  | `proxy.enabled` | 否 | `false` | 是否启用插件级代理 |
129
174
  | `proxy.url` | 启用时必填 | - | 代理地址,例如 `http://127.0.0.1:7890` 或 `socks5://127.0.0.1:10808` |
@@ -136,6 +181,38 @@ Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 O
136
181
  - 常见代理地址格式包括 `http://...`、`https://...`、`socks5://...`。
137
182
  - 代理软件或代理服务器需要你自己提供,插件只负责使用代理。
138
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
+ ```
215
+
139
216
  ## 使用方式
140
217
 
141
218
  - 私聊:`/status` 或 `你好`
@@ -157,6 +234,18 @@ openclaw status
157
234
  - 发送 `/mixin-outbox` 可查看当前待发队列数量、下次重试时间和最近错误。
158
235
  - 发送 `/mixin-outbox purge-invalid` 可删除历史遗留的 `APP_CARD` / `APP_BUTTON_GROUP` 永久无效重试项。
159
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
+
160
249
  ## 投递与重试行为
161
250
 
162
251
  - 回复消息会先写入本地 outbox,再由后台 worker 发送。
@@ -164,6 +253,32 @@ openclaw status
164
253
  - 插件重启后,未完成的消息仍会继续补发。
165
254
  - 入站 Blaze 消息会在分发前尽快 ACK,尽量减少 Mixin 的重复推送。
166
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
+
167
282
  ## 显式回复模板
168
283
 
169
284
  如果你希望 Mixin 回复严格按指定形式发送,而不是依赖自动判断,可以让 agent 只输出一个 fenced code block 模板。
@@ -215,11 +330,40 @@ openclaw status
215
330
  ```
216
331
  ```
217
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
+
218
358
  规则:
219
359
 
220
360
  - 显式模板优先级高于自动识别。
221
361
  - 回复里只要出现表格或 fenced code block,默认就会走 `mixin-post` 长文。
222
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: ...` 文本提示。
223
367
  - 按钮和卡片链接必须使用 `http://` 或 `https://`。
224
368
  - Mixin 客户端可能要求目标域名已加入机器人应用的 `Resource Patterns` 白名单。
225
369
 
@@ -236,6 +380,7 @@ openclaw status
236
380
  "sessionId": "...",
237
381
  "serverPublicKey": "...",
238
382
  "sessionPrivateKey": "...",
383
+ "dmPolicy": "pairing",
239
384
  "allowFrom": ["..."]
240
385
  },
241
386
  "bot2": {
@@ -270,14 +415,14 @@ openclaw status
270
415
  | 插件未加载 | 运行 `openclaw plugins list` 和 `openclaw plugins info mixin` |
271
416
  | 频道未启动 | 检查 `channels.mixin` 是否存在,凭证是否完整 |
272
417
  | 插件未启用 | 检查 `plugins.allow` 和 `plugins.entries.mixin.enabled` |
273
- | 收不到消息 | 检查 `allowFrom`、触发词和 Blaze 连通性 |
418
+ | 收不到消息 | 检查 pairing 是否已批准或 `allowFrom` 是否包含该用户,同时检查触发词和 Blaze 连通性 |
274
419
  | 消息发不出去 | 检查代理是否可达、outbox 堆积情况和 `/mixin-outbox` 输出 |
275
420
  | 入站消息重复推送 | 检查 Blaze 连通性,并确认 ACK 是否正常发送 |
276
421
 
277
422
  ## 安全提示
278
423
 
279
424
  - 妥善保管 `sessionPrivateKey`
280
- - 生产环境务必配置 `allowFrom`
425
+ - 生产环境建议使用 `dmPolicy: "pairing"` 或严格的 `allowFrom`
281
426
  - outbox 文件会保存待发送消息正文,不要暴露 `data/` 目录
282
427
 
283
428
  ## 相关链接
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@invago/mixin","version":"1.0.7","description":"Mixin Messenger channel plugin for OpenClaw","type":"module","main":"index.ts","scripts":{"dev":"nodemon --exec \"node --import jiti/register index.ts\" --ext ts","lint":"eslint src/**/*.ts index.ts","typecheck":"tsc --noEmit"},"peerDependencies":{"openclaw":">=2026.2.0"},"dependencies":{"@mixin.dev/mixin-node-sdk":"^7.4.1","@noble/curves":"^2.0.1","@noble/hashes":"^2.0.1","axios":"^1.6.0","express":"^5.2.1","proxy-agent":"^6.5.0","ws":"^8.18.3","zod":"^4.3.6"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^20.0.0","eslint":"^10.0.3","globals":"^17.4.0","jiti":"^1.21.0","nodemon":"^3.0.0","typescript":"^5.3.0","typescript-eslint":"^8.56.1"},"keywords":["openclaw","mixin","messenger","plugin","channel"],"author":"invagao","license":"MIT","repository":{"type":"git","url":"git+https://github.com/invago/mixinclaw.git"},"openclaw":{"extensions":["./index.ts"],"channel":{"id":"mixin","label":"Mixin Messenger","selectionLabel":"Mixin Messenger (Blaze WebSocket)","docsPath":"/channels/mixin","order":70,"aliases":["mixin-messenger","mixin"],"quickstartAllowFrom":true},"install":{"npmSpec":"@invago/mixin","localPath":"extensions/mixin"}}}
1
+ {"name":"@invago/mixin","version":"1.0.9","description":"Mixin Messenger channel plugin for OpenClaw","type":"module","main":"index.ts","bin":{"mixin-plugin-onboard":"tools/mixin-plugin-onboard/bin/mixin-plugin-onboard.mjs"},"scripts":{"dev":"nodemon --exec \"node --import jiti/register index.ts\" --ext ts","lint":"eslint src/**/*.ts index.ts","typecheck":"tsc --noEmit","tool:info":"node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts info","tool:doctor":"node --import jiti/register.js tools/mixin-plugin-onboard/src/index.ts doctor"},"peerDependencies":{"openclaw":">=2026.2.0"},"dependencies":{"@mixin.dev/mixin-node-sdk":"^7.4.1","@noble/curves":"^2.0.1","@noble/hashes":"^2.0.1","axios":"^1.6.0","express":"^5.2.1","jiti":"^1.21.0","proxy-agent":"^6.5.0","ws":"^8.18.3","zod":"^4.3.6"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^20.0.0","eslint":"^10.0.3","globals":"^17.4.0","nodemon":"^3.0.0","typescript":"^5.3.0","typescript-eslint":"^8.56.1"},"keywords":["openclaw","mixin","messenger","plugin","channel"],"author":"invagao","license":"MIT","repository":{"type":"git","url":"git+https://github.com/invago/mixinclaw.git"},"openclaw":{"extensions":["./index.ts"],"channel":{"id":"mixin","label":"Mixin Messenger","selectionLabel":"Mixin Messenger (Blaze WebSocket)","docsPath":"/channels/mixin","order":70,"aliases":["mixin-messenger","mixin"],"quickstartAllowFrom":true},"install":{"npmSpec":"@invago/mixin","localPath":"extensions/mixin"}}}