Skip to content

fix(minimax-bot): fold the background job queue behind one line, separate the reply bubbles - #51

Merged
MyPrototypeWhat merged 6 commits into
MiniMax-AI:mainfrom
July-X:fix/minimax-bot-task-queue-fold-and-bubble-gap
Oct 21, 2026
Merged

MyPrototypeWhat merged 6 commits into
MiniMax-AI:mainfrom
July-X:fix/minimax-bot-task-queue-fold-and-bubble-gap

Conversation

@July-X

@July-X July-X commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

This is the follow-up to #48. The reply actions #48 moved to the bottom-left of a reply and the themed reaction badge stay as they are. What this pull request adds is the piece that was still missing: the strip of background jobs folds a long queue behind one line, and the working messages of one reply keep the official flat layout with a small gap between the bubbles.

The first review round pointed at four rough edges in that fold. They are fixed in the two commits on top of the original ones:

  • The fold button was removed and rebuilt on every render, so the keyboard focus fell back to the body whenever the queue changed or the clock ticked. The same node is kept now, and only its text and its state follow the queue.
  • Which rows stayed in the open was decided by the order the jobs arrived in, so a job that was already working could be the row that folded away, behind a queue of jobs that had not started yet. The rows that stay in the open are chosen by status now, the working one first, while the rows themselves keep the order the official build gives them.
  • An open queue stayed open after it shrank to a few jobs. It ends with the queue now, and the next busy chat starts folded again.
  • The gap between the bubbles of one reply was set on the whole column, which moved the action row, the notes and the event lines as well. The rule names the bubbles alone now, so everything else keeps the spacing the official build gave it.

What changed

  • The rows of the background job strip stay exactly as the official build draws them: one line per job, the official wording, the official stop button, the official order. Only the outer layer is new. A busy chat keeps three rows in the open, the jobs that are already working first, and folds the rest into one line that reads "还有 N 个任务" ("N more tasks"). A small button under the rows opens the whole queue and folds it again. The button sits outside the scroll area of the rows, so it stays reachable however long the queue is, and the strip keeps the height budget the official one had.
  • The fold that fix(minimax-bot): fold the earlier bubbles of a long reply, bottom-left reply actions #48 introduced for the earlier bubbles of a long reply is withdrawn. Every part of a reply keeps its own bubble, in the recorded order and with the official shape, and a 4px gap between the bubbles that follow each other tells them apart instead of letting them read as one block of text. No bubble carries a hover title any more.
  • The version moves from 0.7.5 to 0.7.6.

Test environment and results

  • MiniMax Code 3.1.2 on Windows 10.0.19045, Node.js 22.
  • npm run check in the repository root reports no errors and no warnings, and the 69 contract tests pass.
  • The package test suite passes 201 of 205 tests. The four failures are environmental and reproduce without this change:
    • "restart after questionnaire preserves the next group member before publishing completion" and "restart after dependency verification preserves the next group member before publishing completion" time out after 12 s on this machine. The same two fail on the unmodified baseline.
    • "avatar library persists imports, deduplicates concurrent uploads and reuses them across Bots and restarts" fails the same way on the unmodified baseline: one of the four parallel imports comes back with another status.
    • "HTTP task snapshot and stop endpoint control an admitted MCP delegation" failed with EBUSY: resource busy or locked, rmdir while the test removed its temporary directory. It clears when the file runs on its own.
  • The client reliability suite passes 32 of 32, including the case that keeps the official one-line job rows, folds a long queue behind them, holds the focus on the fold button across a redraw, keeps a running job in the open and ends an open queue with the queue.
  • Measured in a real browser (headless Chrome over CDP) against a seeded chat: 30 queued jobs draw as three rows plus "还有 27 个任务", the strip is 166px tall and the rows are 42px each. Pressing the button keeps the focus on it, draws all 30 rows inside the 248px row area, which then scrolls, and leaves the button in reach at the bottom of the strip; pressing it again folds the queue back to three rows with the focus still on the button. A reply of 13 parts draws 13 bubbles with a 4px gap, a reply of 119 parts draws 119 bubbles with the same gap, the column itself carries no gap any more, and no bubble carries a title.

Unverified

  • The layout was measured in headless Chrome at one window size. Other window sizes and a narrow sidebar were not checked.
  • Only a seeded queue was folded. A queue that grows while it is open was not watched.
  • The two 12 s timeouts above were left alone. They come from the speed of this machine, not from this pull request.

这是 #48 的后续。#48 把回复操作按钮移到左下角、把反应徽章主题化,这两处保持不动。这个 PR 补上的是之前还缺的一块:后台任务条把长队列折成一行,一次回复的过程消息回到官方平铺形态,气泡之间留出小间隔。

第一轮评审指出这个折叠还有四处毛刺,已经在上面两笔提交里修掉:

  • 折叠按钮每次重绘都被删掉重建,队列一变或时钟一跳,键盘焦点就掉回 body。现在复用同一个节点,只有文案和状态跟着队列变。
  • 留在外面的哪几行原先按到达顺序切,正在跑的任务可能正好被折到"还有 N 个任务"后面。现在按状态挑,正在跑的优先,而行本身仍保持官方的顺序。
  • 展开的队列缩到几个任务后仍保持展开。现在它跟着队列一起结束,下一个忙的会话重新从收起开始。
  • 气泡之间的小间隔原先加在整列上,把操作行、提示行和事件行也一起挪了。现在规则只点名气泡,其余元素保持官方给的间距。

改了什么

  • 后台任务条的行保持官方写法:每个任务一行、官方文案、官方停止按钮、官方顺序,新增的只有外面一层。任务多的时候外面留三行,正在跑的优先,其余折成一行"还有 N 个任务"。行下面有一个小按钮,展开是完整队列,再点一次收起。按钮放在行的滚动区外面,所以队列再长也点得到;任务条整体高度仍守住官方的预算。
  • fix(minimax-bot): fold the earlier bubbles of a long reply, bottom-left reply actions #48 给长回复的旧气泡加的折叠撤掉了。回复的每个 part 仍是自己的一个气泡,顺序照旧、形状照官方,相邻气泡之间加 4px 间隔,不再连成一片。气泡不再带 hover 提示。
  • 版本 0.7.5 → 0.7.6。

测试环境与结果

  • MiniMax Code 3.1.2、Windows 10.0.19045、Node.js 22。
  • 仓库根目录 npm run check 无错误无警告,69 条契约用例通过。
  • 包内测试 205 条通过 201 条,4 条失败与本改动无关,未改动的基线同样失败:
    • "restart after questionnaire …" 和 "restart after dependency verification …" 在本机 12 秒超时,基线上同样失败。
    • "avatar library persists imports …" 在未改动的基线上同样失败:四个并发导入里有一个返回了别的状态。
    • "HTTP task snapshot and stop endpoint …" 报临时目录 EBUSY: resource busy or locked, rmdir,单独跑该文件时不会出现。
  • 客户端用例 32 条全过,含"任务条保留官方单行并折叠长队列、重绘后焦点仍在折叠按钮上、正在跑的任务留在外面、展开态随队列结束"那条。
  • 真实浏览器(headless Chrome + CDP)配种子数据实测:30 个排队任务画成 3 行加"还有 27 个任务",任务条高 166px、行高 42px。点按钮后焦点仍在按钮上,30 行画进 248px 的行区里自滚,按钮仍在任务条底部可见;再点一次收回三行,焦点还在按钮上。13 个 part 的回复画 13 个气泡、间隔 4px,119 个 part 的回复画 119 个气泡、间隔同样是 4px,气泡这一列本身不再带 gap,气泡均无 title。

未验证

  • 版式只在 headless Chrome 的一个窗口尺寸下量过,其他窗口尺寸和窄侧栏没查。
  • 只测了种子队列,展开期间队列继续变长的情况没观察。
  • 上面两条 12 秒超时没动,是本机速度问题,不是这个 PR 带来的。

The task strip had no way to shrink a busy queue: the rows kept the
official shape, but thirty jobs filled the whole strip and the last
ones were only reachable by scrolling inside it.

The rows stay the ones the official build draws, in its order. What is
new is a layer on top: the first five rows stay in the open, the rest
fold into one line that says how many jobs are left, and a click brings
them back. The button sits below the rows' own scroll area, so it
stays reachable however long the queue is, and the strip keeps the
height budget the official one had.
Three matches the number the folded reply bubbles keep, and it leaves
the transcript more room when a queue is long.
The task strip fold is a build of its own on top of the merged 0.7.5.
The fold took a long reply's earlier bubbles behind a summary line. The
queue of background jobs was the thing that needed folding, so the
bubbles go back to the flat layout the official build draws: one bubble
per recorded part, in the order it records them.

What was missing there was a gap between them. One reply with many
parts drew its bubbles flush against each other, so they read as one
block of text; a small gap, the one the task rows use, tells them
apart.

@hetaoBackend hetaoBackend left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:可以合并,没有阻塞问题。 按 AGENTS.md 的三条门槛看:manifest 通过 npm run check(plugins/minimax-ai/minimax-bot: OK);改动只涉及前端渲染和版本号,不碰文件、网络或子进程,伤不到 Host 或用户数据;README 基本和实际行为一致,少了一处说明(见第 5 点)。插件自己的 205 个测试全部通过。下面都是建议。

值得修的问题

1. 点折叠按钮后键盘焦点会丢(可访问性)
renderHelpers() 每次都会把 .helper-more 删掉再新建。用户按 Enter / 空格触发后,旧按钮被移除,焦点落回 body,键盘用户没法连续切换展开和收起。30 秒的 setInterval 也会调用 renderHelpers(),焦点停在按钮上时同样会丢。
建议复用已有按钮节点,只更新文字和 aria-expanded;或者重建后如果原来有焦点就重新 focus()。停止按钮也有同样的问题,不过那是之前就有的。

2. 正在运行的任务可能被折叠掉
items = [...state.helpers, ...state.tasks] 之后直接 slice(0, 3)。如果某个 chat 里有 3 个以上排队中的 helper,state.tasks 里正在跑的任务就会被藏到"还有 N 个任务"后面,最需要看到的那一行反而看不见。
建议截取前先按状态排序(running → waiting_for_tasks → queued),或者 running 行永远不折叠。

3. gap: 4px 的影响范围比描述的大
.bubble-wrap 里不只有回复气泡,还有用户消息的附件、投递状态、.msg-tools 操作行、shimmer、事件行,私聊和群聊都用它。加了 gap 后这些元素之间都多出 4px,比如操作行和气泡的距离从 margin-top: 2px 变成实际 6px,附件下方从 4px 变成 8px。
如果只想分开相邻气泡,可以收窄成:

.bubble-wrap > .bubble + .bubble { margin-top: 4px; }

对应的测试断言也要跟着改。

小问题和建议

  1. 展开状态会被带到后面:helpersExpanded 只在 mountChat 时重置。队列缩到 3 行以内、之后又变长时,会直接以展开状态出现。建议在 items.length <= HELPER_ROWS_PREVIEW 时重置为 false。
  2. README 没写任务条折叠:这次只改了 "Working messages" 那条,新的折叠行为没写进 Background work 段落("Running jobs are shown above the chat input…")。建议补一句"超过 3 个任务时折叠,可展开"。
  3. 重复条件:hidden > 0 || (helpersExpanded && items.length > HELPER_ROWS_PREVIEW) 写了两遍,可以提成一个 const foldable。
  4. commit 历史前后矛盾:011c418 写的是 "first five rows",后来 c85ddf8 改成 3,理由是 "matches the number the folded reply bubbles keep",但 045eade 把气泡折叠整个删了,这个理由已不成立。建议 squash 合并或改一下 message。
  5. 硬编码的按钮高度:.helpers.has-fold .helper-rows 的 calc(40vh - 32px) 里 32px 是按钮高度加间距,以后改 .btn.sm 尺寸容易对不上。影响很小。

验证

  • npm run check:通过,minimax-bot 无 error / warning。
  • node --test tests/*.test.mjs(plugins/minimax-ai/minimax-bot):205/205 通过。
  • 未在真实 MiniMax Code 中打开界面验证,第 1、3 点来自读代码。

…tton

The fold of the job queue had three rough edges.

The button was removed and rebuilt on every render, so the keyboard
focus fell back to the body as soon as the queue changed or the clock
ticked. The same node is kept now; only its text and its state follow
the queue.

Which rows stayed in the open was decided by the order the jobs
arrived in, so a job that was already working could be the row that
folded away, behind a queue of jobs that had not started yet. The rows
that stay in the open are chosen by status now, the working one first,
while the rows themselves keep the order the official build gives them.

An open queue stayed open after it shrank to a few jobs. It ends with
the queue now, and the next busy chat starts folded again.

The gap between the bubbles of one reply belongs to the bubbles alone.
The rule names them instead of the whole column, so the action row,
the notes and the event lines keep the spacing the official build gave
them. The height budget of the strip and the row the fold button takes
from it are two variables now.
The README described the working messages of a reply but not the strip
above the composer, so the fold of a long queue was left undocumented.
@July-X

July-X commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

谢谢评审。第 1、2、3、4、5、6、8 点已经在上面两笔提交里改掉,逐条回一下。

1. 折叠按钮的焦点:按钮现在跨重绘复用同一个节点,只有文案和 aria-expanded 跟着队列变。真实浏览器实测:按钮拿到焦点,重绘之后焦点还在同一个节点上,点它收起队列后焦点也还在。

2. 正在跑的任务被折掉:留在外面的三行改成按状态挑,running → waiting_for_tasks → queued。行本身仍保持官方的顺序,所以重排没有发生,变的是"哪三行留在外面"这个选择;正在跑的任务不会再被折到"还有 N 个任务"后面。

3. gap: 4px 的影响范围:同意,间隔只该属于气泡。规则改成 .bubble-wrap > .bubble + .bubble { margin-top: 4px },这一列本身不再带 gap,所以操作行、提示行、事件行都回到官方给的间距。气泡之间的实测间隔仍是 4px(私聊 13 个气泡、群聊 119 个气泡)。

4. 展开状态被带过去:展开的队列跟着队列一起结束,缩到 3 个任务时折叠按钮消失,下一个忙的会话重新从收起开始。

5. README:Background work 那段补上了折叠的说明——超过 3 个任务时,正在跑的留在外面,其余折成一行,行下面一个按钮展开完整队列。

6. 重复条件:收成一个 foldable 标志。

7. commit 历史:说得对,c85ddf8 的理由在气泡折叠撤掉之后就不成立了。#48 是压成一笔合并进 main 的,这几笔中间信息本来也不会进 main;如果希望在合并前就把措辞改掉,说一声我重写。

8. 写死的 32px:任务条的高度预算和折叠按钮占的那一行现在是两个变量(--helper-rows-max、--helper-fold-row),以后改小按钮的尺寸不用再同步第二个数字。

测试:npm run check 无错误无警告,客户端 32 条全过。包内全量在本机 205 条通过 201 条,4 条失败是两条 12 秒超时加两条 Windows 抖动,未改动的基线同样失败,明细写在 PR 描述里。

@MyPrototypeWhat MyPrototypeWhat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround, and thanks @hetaoBackend for the careful review. I re-reviewed 045eade..e030957 (f296610, e030957) against hetaoBackend's points.

Fixes checked

  1. Focus on the fold button. .helper-more is now created once and reused. Each render only updates textContent and aria-expanded, so focus survives a click, the elapsed-time refresh and new jobs arriving. The test focuses the button, re-emits helpers.changed, and asserts both node identity and document.activeElement. The stop buttons are still rebuilt on every render; that was already the case before this PR and is out of scope here.
  2. Running jobs folded away. visibleHelperRows() ranks by status (running → waiting_for_tasks → queued) to pick which three rows stay open, then filters the original items. The visible rows therefore keep the official order; the stable sort only decides the selection, so there is no reordering of rows and the official look holds. The test adds a running task behind four queued helpers and asserts that it is visible and that the queued rows give way.
  3. gap: 4px too broad. The column no longer carries a gap. The new .bubble-wrap > .bubble + .bubble { margin-top: 4px } only affects bubbles that follow each other. The test asserts the column rule has no gap:, that the sibling rule exists, and that the 13-bubble reply has 12 .bubble + .bubble pairs, i.e. the flat bubbles really are adjacent siblings and the rule reaches all of them. The action row, notes and event lines keep their official spacing.
  4. Expanded state carried over. helpersExpanded now resets when the queue drops to three or fewer and when it empties. The test shrinks the queue to three (the button disappears), grows it back, and sees "4 more tasks" again.
  5. README. The Background work paragraph now describes the fold.
  6. Duplicated condition. It is now a single foldable = items.length > HELPER_ROWS_PREVIEW.
  7. Commit history. This is moot under squash merge.
  8. Hard-coded 32px. It now lives in --helper-rows-max / --helper-fold-row on .helpers. The computed values are unchanged (280px, and 248px with the fold).

No regressions found. Strings, theme vars and the rest of the plugin are unchanged.

Tiny wording nit (non-blocking)
README says "when more than three are queued". The fold actually triggers on more than three jobs in total, running or queued. "when more than three jobs are listed" would be exact.

Results

  • npm run check at repo root (Node 22.14.0): pass; plugins/minimax-ai/minimax-bot: OK, contract tests 69/69.
  • node --test tests in plugins/minimax-ai/minimax-bot (Node 20.19.2, Linux): 205/205 pass, including the extended task-strip test and both bubble tests. None of the four Windows failures you mention reproduce here, so there was nothing to compare against main.

Version
The bump to 0.7.6 is fine. #49 also bumps, so whichever of #49 / #51 merges later bumps again.

LGTM, approving.

@MyPrototypeWhat
MyPrototypeWhat merged commit 3124773 into MiniMax-AI:main Oct 21, 2026
1 check passed

@hetaoBackend hetaoBackend left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

行内意见见各条评论,总评见上一条 review。另外一条无法挂到代码行上:

[小问题] commit 历史前后矛盾:011c418 写的是 "first five rows",后来 c85ddf8 改成 3,理由是 "matches the number the folded reply bubbles keep",但 045eade 把气泡折叠整个删了,这个理由已不成立。建议 squash 合并或改一下 message。

ui.helpers.classList.toggle('has-fold', hidden > 0 || (helpersExpanded && items.length > HELPER_ROWS_PREVIEW));
// `replaceChildren` renders a null argument as the text "null", so the fold button is appended
// on its own, and only when there is something to fold.
ui.helpers.querySelector('.helper-more')?.remove();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[建议修] 点折叠按钮后键盘焦点会丢(可访问性)

这里每次都把 .helper-more 删掉再新建。用户按 Enter / 空格触发后,旧按钮被移除,焦点落回 body,键盘用户没法连续切换展开和收起。30 秒的 setInterval 也会调用 renderHelpers(),焦点停在按钮上时同样会丢。

建议复用已有按钮节点,只更新文字和 aria-expanded;或者重建后如果原来有焦点就重新 focus()。(停止按钮也有同样的问题,不过那是之前就有的。)

// The rows are the ones the official build draws, in the order it draws them. A busy chat
// keeps the first few in the open and folds the rest into one line, so the strip never
// grows into a wall of rows.
const preview = helpersExpanded ? items : items.slice(0, HELPER_ROWS_PREVIEW);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[建议修] 正在运行的任务可能被折叠掉

items = [...state.helpers, ...state.tasks] 之后直接 slice(0, 3)。如果某个 chat 里有 3 个以上排队中的 helper,state.tasks 里正在跑的任务就会被藏到"还有 N 个任务"后面,最需要看到的那一行反而看不见。

建议截取前先按状态排序(running → waiting_for_tasks → queued),或者 running 行永远不折叠。

align-items: flex-start;
/* One reply can carry many bubbles, one per recorded part. Without a gap between them they
read as one block of text; a small one tells them apart, the way the task rows do. */
gap: 4px;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[建议修] gap: 4px 的影响范围比描述的大

.bubble-wrap 里不只有回复气泡,还有用户消息的附件、投递状态、.msg-tools 操作行、shimmer、事件行,私聊和群聊都用它。加了 gap 后这些元素之间都多出 4px,比如操作行和气泡的距离从 margin-top: 2px 变成实际 6px,附件下方从 4px 变成 8px。

如果只想分开相邻气泡,可以收窄成:

.bubble-wrap > .bubble + .bubble { margin-top: 4px; }

对应的测试断言也要跟着改。


/** How many job rows stay in the open before the rest folds into one line. */
const HELPER_ROWS_PREVIEW = 3;
let helpersExpanded = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[小问题] 展开状态会被带到后面

helpersExpanded 只在 mountChat 时重置。队列缩到 3 行以内、之后又变长时,会直接以展开状态出现,用户并没有点过。建议在 items.length <= HELPER_ROWS_PREVIEW 时重置为 false。

);
}),
);
ui.helpers.classList.toggle('has-fold', hidden > 0 || (helpersExpanded && items.length > HELPER_ROWS_PREVIEW));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[小问题] 重复条件

hidden > 0 || (helpersExpanded && items.length > HELPER_ROWS_PREVIEW) 在这里和下面 if 里写了两遍,可以提成一个 const foldable。

/* The fold button sits below the scroll area and takes a row of its own, so the strip keeps
the height budget the official one had. */
.helpers.has-fold .helper-rows {
max-height: min(248px, calc(40vh - 32px));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[小问题] 硬编码的按钮高度

calc(40vh - 32px) 里的 32px 是按钮高度加间距,以后改 .btn.sm 尺寸容易对不上。影响很小。

- **Reactions**: react to finished Bot replies in private and group chats. The quick bar offers 👍 ❤️ 🙌 😂 😭 😮, and more emoji can be browsed by category or searched in English or Chinese. Each message holds one reaction: picking a new one replaces it, and picking the same one again removes it. Reactions are saved locally, survive refreshes and restarts, and sync to other open windows. They do not trigger a Bot reply and are not sent to the model.
- **Reply actions**: the reaction, copy, quote-reply and open-session buttons sit at the bottom-left of a reply, under its last line. A long reply therefore keeps its actions within reach at the end of the text instead of pushing them off the top of the message. The reaction indicator sits directly above that row and is painted with the app's own tag colours, so it follows the light and dark themes.
- **Folded working messages**: the Host records a text part for every turn a Bot takes between two tool calls, so a reply that worked for a while arrives with many parts. The newest three bubbles stay in the open, exactly where the flat layout put them, the answer among them. The earlier ones keep their own shape but move into a folded area above them: one line says how many of them there are, and opening it shows them in a fixed height area with its own scrollbar, so the conversation above stays in reach. Hovering a bubble of such a reply tells what that bubble said, the way the task rows and the attachments do.
- **Working messages of one reply**: the Host records a text part for every turn a Bot takes between two tool calls, so a reply that worked for a while arrives with many parts, and the page draws one bubble per part. The bubbles keep the official shape and order, and a small gap between them tells them apart instead of letting them read as one block of text.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[小问题] README 没写任务条折叠

这次只改了这条 "Working messages",新的任务条折叠行为没写进 Background work 段落(第 17 行 "Running jobs are shown above the chat input…")。建议在那里补一句"超过 3 个任务时折叠,可展开"。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants