@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 CHANGED
@@ -24,6 +24,18 @@ openclaw plugins install @invago/mixin
24
24
 
25
25
  `@invago/mixin` is the published npm package name. The OpenClaw runtime/plugin name remains `mixin`.
26
26
 
27
+ If the plugin is already installed, upgrade it with the plugin id:
28
+
29
+ ```bash
30
+ openclaw plugins update mixin
31
+ ```
32
+
33
+ To install a specific version for the first time:
34
+
35
+ ```bash
36
+ openclaw plugins install @invago/mixin@<version>
37
+ ```
38
+
27
39
  Then confirm the plugin is installed:
28
40
 
29
41
  ```bash
@@ -64,7 +76,6 @@ Edit your `openclaw.json` file manually and add both the channel configuration a
64
76
  {
65
77
  "channels": {
66
78
  "mixin": {
67
- "enabled": true,
68
79
  "defaultAccount": "default",
69
80
  "appId": "YOUR_APP_ID",
70
81
  "sessionId": "YOUR_SESSION_ID",
@@ -78,6 +89,16 @@ Edit your `openclaw.json` file manually and add both the channel configuration a
78
89
  "audioSendAsVoiceByDefault": true,
79
90
  "audioAutoDetectDuration": true,
80
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
+ },
81
102
  "proxy": {
82
103
  "enabled": true,
83
104
  "url": "socks5://127.0.0.1:10808",
@@ -143,11 +164,105 @@ Recommended configuration:
143
164
 
144
165
  Use `per-account-channel-peer` instead if you run multiple Mixin accounts and want direct-message sessions isolated by both channel and account.
145
166
 
167
+ ## Multi-Agent Routing Per Bot Account
168
+
169
+ OpenClaw supports routing different channel accounts to different agents through `bindings[].match.accountId`.
170
+
171
+ Recommended pattern:
172
+
173
+ - One Mixin bot account = one `accountId`
174
+ - One `accountId` = one agent binding
175
+ - Keep session isolation at `per-account-channel-peer` when you run multiple bot accounts
176
+
177
+ Example:
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
+ Notes:
256
+
257
+ - `match.accountId` binds one Mixin bot account to one agent.
258
+ - If `accountId` is omitted in a binding, OpenClaw treats it as the default account only.
259
+ - Use `accountId: "*"` only when you want one fallback agent for all Mixin accounts.
260
+ - If you need one specific group or DM to override the account-level routing, add a more specific `match.peer` binding. Peer matches win over `accountId` matches.
261
+
146
262
  ## Configuration Reference
147
263
 
148
264
  | Parameter | Required | Default | Description |
149
265
  |-----------|----------|---------|-------------|
150
- | `enabled` | No | `true` | Enable or disable this channel account |
151
266
  | `defaultAccount` | No | `default` | Default account ID used when `accounts` is configured |
152
267
  | `appId` | Yes | - | Mixin App UUID |
153
268
  | `sessionId` | Yes | - | Session UUID |
@@ -157,12 +272,21 @@ Use `per-account-channel-peer` instead if you run multiple Mixin accounts and wa
157
272
  | `allowFrom` | No | `[]` | Authorized user UUID whitelist |
158
273
  | `groupPolicy` | No | OpenClaw default | Group-message policy: `open`, `allowlist`, or `disabled` |
159
274
  | `groupAllowFrom` | No | `[]` | Authorized sender UUID whitelist for group messages when `groupPolicy` uses allowlisting |
160
- | `requireMentionInGroup` | No | `true` | Require trigger words in group chats |
275
+ | `requireMentionInGroup` | No | `true` | Apply plugin-side trigger-word filtering to group messages that have already been delivered to the bot |
161
276
  | `mediaBypassMentionInGroup` | No | `true` | Allow inbound group file/audio messages through even without trigger text |
162
277
  | `mediaMaxMb` | No | `30` | Max inbound and outbound media size in MB |
163
278
  | `audioSendAsVoiceByDefault` | No | `true` | Send OpenClaw native outbound audio as Mixin voice when possible |
164
279
  | `audioAutoDetectDuration` | No | `true` | Detect native outbound audio duration with `ffprobe` before sending voice |
165
280
  | `audioRequireFfprobe` | No | `false` | Fail native outbound audio instead of falling back to file when duration detection is unavailable |
281
+ | `mixpay.enabled` | No | `false` | Enable MixPay collect support for this Mixin account |
282
+ | `mixpay.payeeId` | Required when enabled | - | MixPay merchant/payee ID used to create one-time payment orders |
283
+ | `mixpay.defaultQuoteAssetId` | No | - | Default quote asset ID for collect templates or future collect commands |
284
+ | `mixpay.defaultSettlementAssetId` | No | - | Default settlement asset ID for MixPay orders |
285
+ | `mixpay.expireMinutes` | No | `15` | Default MixPay order expiration time in minutes |
286
+ | `mixpay.pollIntervalSec` | No | `30` | Poll interval in seconds for pending MixPay orders |
287
+ | `mixpay.allowedCreators` | No | `[]` | Optional sender UUID allowlist for creating MixPay collect orders |
288
+ | `mixpay.notifyOnPending` | No | `false` | Notify the chat when MixPay reports `pending` |
289
+ | `mixpay.notifyOnPaidLess` | No | `true` | Notify the chat when MixPay indicates an underpayment |
166
290
  | `conversations.<conversationId>.enabled` | No | `true` | Enable or disable a specific group conversation |
167
291
  | `conversations.<conversationId>.requireMention` | No | Inherit account | Override group trigger-word requirement for a specific conversation |
168
292
  | `conversations.<conversationId>.allowFrom` | No | Inherit account | Override group sender allowlist for a specific conversation |
@@ -189,6 +313,13 @@ Mixin now supports formal group access controls in addition to direct-message `d
189
313
  - `groupPolicy: "disabled"` blocks the entire conversation.
190
314
  - `conversations.<conversationId>` overrides account-level group settings for that single conversation.
191
315
 
316
+ Important delivery boundary:
317
+
318
+ - In practice, Mixin group bots reliably receive messages when the bot is explicitly mentioned.
319
+ - `requireMentionInGroup: false` only disables this plugin's own post-delivery filtering.
320
+ - It does not guarantee that Mixin will deliver every non-mention group message to the bot.
321
+ - If a non-mention group message produces no read receipt and no inbound log, the message most likely was not delivered to the plugin by Mixin in the first place.
322
+
192
323
  Example:
193
324
 
194
325
  ```json
@@ -212,6 +343,34 @@ Example:
212
343
  }
213
344
  ```
214
345
 
346
+ How to get these values:
347
+
348
+ - `conversations.<conversationId>`: use the group's `conversation_id`. In practice, the easiest way is to let the group send a message to the bot once, then read the `conversationId` from the plugin logs or inbound event context. Mixin's conversation APIs also use the same `conversation_id` field for group conversations.
349
+ - `groupAllowFrom` or `conversations.<conversationId>.allowFrom`: use the sender's Mixin `user_id` UUID. Mixin user IDs can be learned when the user messages the bot, adds the bot as a contact, or authorizes the application.
350
+ - If you manage the group through Mixin APIs, the returned conversation payload also includes group participants with their `user_id` fields.
351
+
352
+ Recommended operational approach:
353
+
354
+ - Let the target group send one message to the bot
355
+ - Copy the logged `conversationId`
356
+ - Let the target member send one message, then copy that sender's `user_id`
357
+ - Put those values into `conversations.<conversationId>` and `groupAllowFrom` / `allowFrom`
358
+
359
+ Pairing-style group authorization:
360
+
361
+ - An unauthorized user can send `/mixin-group-auth` in the target group
362
+ - The plugin replies with a temporary approval code for that `conversationId`
363
+ - An operator must approve it in the OpenClaw terminal with `openclaw pairing approve mixin <code>`
364
+ - For non-default accounts, use `openclaw pairing approve --account <accountId> mixin <code>`
365
+ - Once approved, that entire group conversation is allowed without changing `openclaw.json`
366
+ - Repeated `/mixin-group-auth` requests from the same unauthorized group are rate-limited to avoid spam
367
+
368
+ Where to look in logs:
369
+
370
+ - The plugin logs route resolution like `peer.kind=group, peer.id=<conversationId>`, which gives you the group `conversationId`
371
+ - Unauthorized or filtered group logs include `group sender <user_id>` and `conversationId=<conversationId>`
372
+ - If needed, temporarily enable a stricter group policy and let one member send a message once; the rejection log is often the fastest way to collect both values
373
+
215
374
  ## Usage
216
375
 
217
376
  - Direct message: `/status` or `Hello`
@@ -224,6 +383,7 @@ Useful OpenClaw commands:
224
383
  ```bash
225
384
  openclaw plugins list
226
385
  openclaw plugins info mixin
386
+ openclaw plugins update mixin
227
387
  openclaw channels status --probe
228
388
  openclaw status
229
389
  ```
@@ -232,10 +392,15 @@ Plugin-specific command:
232
392
 
233
393
  - Send `/mixin-outbox` to inspect the current pending queue size, next retry time, and latest error.
234
394
  - Send `/mixin-outbox purge-invalid` to remove old `APP_CARD` / `APP_BUTTON_GROUP` entries that are stuck on permanent invalid-field errors.
395
+ - Send `/mixin-group-auth` in a group to create a pending group-authorization request.
396
+ - Approve a pending group-authorization request in the OpenClaw terminal with `openclaw pairing approve mixin <code>`.
397
+ - For non-default accounts, use `openclaw pairing approve --account <accountId> mixin <code>`.
398
+ - Send `/collect status <orderId>` to refresh and inspect a stored MixPay collect order.
399
+ - Send `/collect recent` or `/collect recent 10` to list recent MixPay collect orders for the current conversation.
235
400
 
236
401
  Companion onboarding CLI:
237
402
 
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).
403
+ - This repository also includes a companion CLI at `tools/mixin-plugin-onboard/README.md`.
239
404
  - It is bundled into the same npm package, `@invago/mixin`.
240
405
  - It currently provides `info`, `doctor`, `install`, and `update` commands for local OpenClaw + Mixin plugin maintenance.
241
406
  - Local examples:
@@ -278,6 +443,99 @@ Manual test guide:
278
443
 
279
444
  - See [docs/media-testing.md](docs/media-testing.md) for ready-to-run prompts and expected results.
280
445
 
446
+ ## MixPay Collect
447
+
448
+ Mixin now supports MixPay collection through one-time payment orders.
449
+
450
+ Current capabilities:
451
+
452
+ - `mixin-collect` explicit reply template creates a MixPay collect order
453
+ - Collect orders are stored locally under the OpenClaw state directory
454
+ - Pending orders are polled in the background
455
+ - Success and terminal status changes are sent back to the original conversation
456
+ - `/collect status <orderId>` refreshes the order from MixPay before replying
457
+ - `assetId` in the template can be omitted when `mixpay.defaultQuoteAssetId` is configured
458
+
459
+ Template example:
460
+
461
+ ````text
462
+ ```mixin-collect
463
+ {
464
+ "amount": "1",
465
+ "assetId": "c6d0c728-2624-429b-8e0d-d9d19b6592fa",
466
+ "memo": "Order #1001"
467
+ }
468
+ ```
469
+ ````
470
+
471
+ Rules:
472
+
473
+ - `amount` is required; `assetId` is required unless `mixpay.defaultQuoteAssetId` is configured
474
+ - `settlementAssetId`, `memo`, `orderId`, and `expireMinutes` are optional
475
+ - Payment success is confirmed from MixPay server-side query results, not only from the client page
476
+ - `mixpay.allowedCreators` can restrict who is allowed to create collect orders
477
+
478
+ Where funds arrive:
479
+
480
+ - For MixPay `Mixin account`, funds settle into the linked Mixin Wallet
481
+ - For MixPay `Mixin Robot account`, funds settle into the linked Mixin Robot Wallet
482
+ - Other MixPay account types settle into their own linked wallet types
483
+
484
+ Recommended setup for this plugin:
485
+
486
+ - Use a MixPay `Mixin account` or `Mixin Robot account`
487
+ - Use that account's UUID as `mixpay.payeeId`
488
+ - Set both `mixpay.defaultQuoteAssetId` and `mixpay.defaultSettlementAssetId` if you want templates to stay short
489
+
490
+ How to get the required values:
491
+
492
+ - `mixpay.payeeId`: get the UUID from the [MixPay Dashboard](https://dashboard.mixpay.me) settings page, or use the MixPay helper bot described in the official getting-started guide
493
+ - `mixpay.defaultQuoteAssetId`: choose the asset ID you want to quote prices in
494
+ - `mixpay.defaultSettlementAssetId`: choose the asset ID you want funds to settle into
495
+
496
+ Minimal recommended config:
497
+
498
+ ```json
499
+ {
500
+ "channels": {
501
+ "mixin": {
502
+ "mixpay": {
503
+ "enabled": true,
504
+ "payeeId": "YOUR_MIXPAY_UUID",
505
+ "defaultQuoteAssetId": "YOUR_QUOTE_ASSET_ID",
506
+ "defaultSettlementAssetId": "YOUR_SETTLEMENT_ASSET_ID"
507
+ }
508
+ }
509
+ }
510
+ }
511
+ ```
512
+
513
+ Where to put it:
514
+
515
+ - Single-account setup: put `mixpay` under `channels.mixin.mixpay`
516
+ - Multi-account setup: put it under `channels.mixin.accounts.<accountId>.mixpay`
517
+ - `mixpay` is account-scoped, so different Mixin bot accounts can use different MixPay settings
518
+
519
+ Field reference:
520
+
521
+ - `mixpay.enabled`: enable MixPay collect support for this Mixin account
522
+ - `mixpay.apiBaseUrl`: optional custom MixPay API base URL; normally leave it empty and use the default official endpoint
523
+ - `mixpay.payeeId`: the MixPay payee/merchant UUID that actually receives the funds; required when MixPay collect is enabled
524
+ - `mixpay.defaultQuoteAssetId`: default quoted asset ID; when set, `mixin-collect` can omit `assetId`
525
+ - `mixpay.defaultSettlementAssetId`: default settlement asset ID; controls which asset the order prefers to settle into
526
+ - `mixpay.expireMinutes`: default expiration time for newly created collect orders
527
+ - `mixpay.pollIntervalSec`: background polling interval for pending orders; shorter values detect paid orders faster but create more MixPay API traffic
528
+ - `mixpay.allowedCreators`: optional sender UUID allowlist; when non-empty, only these users can create collect orders in chat
529
+ - `mixpay.notifyOnPending`: whether to send a conversation update when MixPay reports the order as `pending`
530
+ - `mixpay.notifyOnPaidLess`: whether to send a conversation update when MixPay reports an underpayment
531
+
532
+ Practical guidance:
533
+
534
+ - If you only want the smallest working setup, configure `enabled`, `payeeId`, `defaultQuoteAssetId`, and `defaultSettlementAssetId`
535
+ - If you do not want everyone in an authorized chat to create collect orders, set `allowedCreators`
536
+ - If you do not run a private MixPay gateway, leave `apiBaseUrl` unset
537
+ - If you want fewer status messages in chat, keep `notifyOnPending: false`
538
+
281
539
  ## Explicit Reply Templates
282
540
 
283
541
  When you want deterministic Mixin output instead of heuristic auto-selection, have the agent reply with exactly one fenced template block.