From 0e56036d0aed4c1763017642243b4a9a7cf8a60f Mon Sep 17 00:00:00 2001 From: EdgeMLHacker <126883848+Apageoflove@users.noreply.github.com> Date: Sun, 1 Nov 2026 23:30:05 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(minimax-bot):=20=E9=98=9F=E5=88=97?= =?UTF-8?q?=E5=8F=AA=E4=BB=8E=E6=88=90=E5=91=98=E8=A1=A8=E5=87=BA=EF=BC=8C?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E4=B8=8D=E5=9C=A8=E8=A1=A8=E9=87=8C?= =?UTF-8?q?=E4=B9=9F=E6=9C=89=E6=88=90=E5=91=98=E6=8E=A5=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../minimax-bot/miniapp/node/engine.mjs | 5 +- .../minimax-bot/tests/group-queue.test.mjs | 63 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 plugins/minimax-ai/minimax-bot/tests/group-queue.test.mjs diff --git a/plugins/minimax-ai/minimax-bot/miniapp/node/engine.mjs b/plugins/minimax-ai/minimax-bot/miniapp/node/engine.mjs index 2f43222..a89d2cb 100644 --- a/plugins/minimax-ai/minimax-bot/miniapp/node/engine.mjs +++ b/plugins/minimax-ai/minimax-bot/miniapp/node/engine.mjs @@ -1203,8 +1203,11 @@ export class Engine { groupQueue(group, text) { const mentioned = this.mentionsIn(text, group); if (mentioned.length) return mentioned; + // Groups written before 0.7.8 can hold an adminId that is not on the member list; queueing + // such an admin hands the drive a speaker it silently skips, so the whole group goes quiet. + const admin = group.memberIds.includes(group.adminId) ? [group.adminId] : []; const others = group.memberIds.filter((id) => id !== group.adminId); - return group.replyMode === 'all' ? [group.adminId, ...others] : [group.adminId ?? group.memberIds[0]]; + return group.replyMode === 'all' ? [...admin, ...others] : admin.length ? admin : others.slice(0, 1); } /** diff --git a/plugins/minimax-ai/minimax-bot/tests/group-queue.test.mjs b/plugins/minimax-ai/minimax-bot/tests/group-queue.test.mjs new file mode 100644 index 0000000..d096664 --- /dev/null +++ b/plugins/minimax-ai/minimax-bot/tests/group-queue.test.mjs @@ -0,0 +1,63 @@ +// @ts-check +// Who speaks first on a new group message, read the way old groups still write it. +// +// The point of this file: a group's queue is built from its member list, and only from it. +// Groups created before 0.7.8 can hold an adminId that is not on memberIds (the state was +// written before the member list carried the admin); queueing that admin hands driveGroup a +// speaker it silently skips, so with the reply mode "admin" every un-@'d message went quiet +// (issues #63, #65). These assertions pin the rule: only a member queues, an off-list admin +// falls back to the first member, and an @mention still beats every reply mode. + +import assert from 'node:assert/strict'; +import { test } from 'node:test'; + +import { Engine } from '../miniapp/node/engine.mjs'; + +const bots = [ + { id: 'chief', name: 'Chief' }, + { id: 'alice', name: 'Alice' }, + { id: 'bob', name: 'Bob' }, +]; + +/** A bare engine: groupQueue is a pure selector, it only reads this.mentionsIn and this.store. */ +function engine() { + const bare = /** @type {any} */ (Object.create(Engine.prototype)); + bare.store = { getBot: (id) => bots.find((bot) => bot.id === id) }; + return bare; +} + +function group(overrides = {}) { + return { adminId: 'chief', memberIds: ['chief', 'alice', 'bob'], replyMode: 'admin', ...overrides }; +} + +test('an admin on the member list opens the queue, the way it always did', () => { + const app = engine(); + assert.deepEqual(app.groupQueue(group(), 'any message'), ['chief']); + // "all" keeps the admin first and the rest in member order. + assert.deepEqual(app.groupQueue(group({ replyMode: 'all' }), 'any message'), ['chief', 'alice', 'bob']); +}); + +test('an admin off the member list falls back to the first member', () => { + const app = engine(); + // The stored state of an old group: the admin is gone from the members it rules. + assert.deepEqual(app.groupQueue(group({ adminId: 'ghost' }), 'any message'), ['chief']); + assert.deepEqual(app.groupQueue(group({ adminId: undefined }), 'any message'), ['chief']); + // And in "all" the ghost admin is not queued at all — only members speak, in member order. + assert.deepEqual(app.groupQueue(group({ adminId: 'ghost', replyMode: 'all' }), 'any message'), ['chief', 'alice', 'bob']); +}); + +test('a memberless group queues nobody', () => { + const app = engine(); + assert.deepEqual(app.groupQueue(group({ memberIds: [] }), 'any message'), []); + assert.deepEqual(app.groupQueue(group({ memberIds: [], replyMode: 'all' }), 'any message'), []); +}); + +test('an @mention still beats the reply mode', () => { + const app = engine(); + assert.deepEqual(app.groupQueue(group(), '@alice what do you think?'), ['alice']); + assert.deepEqual(app.groupQueue(group({ replyMode: 'all' }), '@bob please review'), ['bob']); + // Several mentions keep their order, and an off-list admin mentioned by name is not a member + // so mentionsIn never matches it in the first place. + assert.deepEqual(app.groupQueue(group(), '@bob and @alice'), ['bob', 'alice']); + assert.deepEqual(app.groupQueue(group({ adminId: 'ghost' }), 'no one addressed'), ['chief']); +}); From f0c18207256f971aee28f6737f12fe4263c47fa4 Mon Sep 17 00:00:00 2001 From: EdgeMLHacker <126883848+Apageoflove@users.noreply.github.com> Date: Mon, 2 Nov 2026 10:14:48 +0800 Subject: [PATCH 2/2] Bump the version and document the group queue rule --- plugins/minimax-ai/minimax-bot/.minimax-plugin/plugin.json | 2 +- plugins/minimax-ai/minimax-bot/README.md | 4 ++++ plugins/minimax-ai/minimax-bot/miniapp/node/mcp.mjs | 2 +- plugins/minimax-ai/minimax-bot/package.json | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/minimax-ai/minimax-bot/.minimax-plugin/plugin.json b/plugins/minimax-ai/minimax-bot/.minimax-plugin/plugin.json index 95c15d0..3b34468 100644 --- a/plugins/minimax-ai/minimax-bot/.minimax-plugin/plugin.json +++ b/plugins/minimax-ai/minimax-bot/.minimax-plugin/plugin.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "name": "minimax-bot", "displayName": "MiniMax Bot", - "version": "0.7.16", + "version": "0.7.20", "description": "Turn MiniMax Code into an always-on team of Bots. A Chief Bot helps you build the team; in group chats the admin answers and @mentions hand work to other members. Every Bot has its own octopus avatar and memory, with scheduled tasks and usage stats.", "author": "MiniMax Code", "icon": "icon.png", diff --git a/plugins/minimax-ai/minimax-bot/README.md b/plugins/minimax-ai/minimax-bot/README.md index 8934bda..4672fc5 100644 --- a/plugins/minimax-ai/minimax-bot/README.md +++ b/plugins/minimax-ai/minimax-bot/README.md @@ -44,6 +44,10 @@ The MCP tools check the arguments they declare before they run. A value of the w An avatar may come from the avatar library or from an image uploaded in the page only. A path on the computer is refused, the plugin reads no file outside its own `dataDir` for one, and the refused path is not echoed back — so the field cannot be used to ask what exists on the disk. +## 0.7.20 The queue of a group is built from its member list + +A group created before 0.7.8 can hold an admin that is not on its member list. Queueing that admin hands the group a speaker it then skips, so every message without an `@` went quiet: the reply was marked cancelled and nothing explained it. The queue is now built from the member list only — the admin speaks first when it is on the list, the first member takes over when it is not, and in the `all` mode only real members are queued. An `@` still beats every reply mode. + ## 0.7.10 Optional group notes - A group can keep a note of what it said. After every round the group records the closing lines of the replies, and every Bot of the group gets that record in its standing brief. diff --git a/plugins/minimax-ai/minimax-bot/miniapp/node/mcp.mjs b/plugins/minimax-ai/minimax-bot/miniapp/node/mcp.mjs index f91de64..864face 100644 --- a/plugins/minimax-ai/minimax-bot/miniapp/node/mcp.mjs +++ b/plugins/minimax-ai/minimax-bot/miniapp/node/mcp.mjs @@ -662,7 +662,7 @@ export function createMcpHandler({ team, engine }) { result = { protocolVersion: PROTOCOL_VERSIONS.includes(requested) ? requested : PROTOCOL_VERSIONS[0], capabilities: { tools: { listChanged: false } }, - serverInfo: { name: 'minimax-bot', version: '0.7.16' }, + serverInfo: { name: 'minimax-bot', version: '0.7.20' }, instructions: t('mcp.instructions'), }; break; diff --git a/plugins/minimax-ai/minimax-bot/package.json b/plugins/minimax-ai/minimax-bot/package.json index 0675509..e215a67 100644 --- a/plugins/minimax-ai/minimax-bot/package.json +++ b/plugins/minimax-ai/minimax-bot/package.json @@ -1,6 +1,6 @@ { "name": "minimax-bot", - "version": "0.7.16", + "version": "0.7.20", "private": true, "type": "module", "mcode": {