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