fix(h5-chat): queue main-session submits while agent is busy
Memind CI / Test, build, and release guards (push) Successful in 4m1s

Prevent silent drops when users send follow-up instructions during waiting or streaming by showing the message immediately, notifying them it is queued, and auto-flushing after the composer returns to idle.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-13 08:51:30 +08:00
parent 53b0d2c62f
commit 558c4ef2ee
4 changed files with 280 additions and 96 deletions
+49
View File
@@ -1,6 +1,9 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import {
buildQueuedChatSubmitNotice,
canFlushQueuedChatSubmit,
isChatSubmitBusy,
reconcileSessionEventRequestContext,
resolvePostAgentRunChatState,
shouldIgnoreZeroActivityFinish,
@@ -145,6 +148,52 @@ test('missing ActiveRequests cannot unlock while the Portal agent-run is pending
);
});
test('isChatSubmitBusy covers active composer states', () => {
assert.equal(isChatSubmitBusy('idle'), false);
assert.equal(isChatSubmitBusy('error'), false);
assert.equal(isChatSubmitBusy('waiting'), true);
assert.equal(isChatSubmitBusy('streaming'), true);
assert.equal(isChatSubmitBusy('connecting'), true);
});
test('buildQueuedChatSubmitNotice reflects queue depth', () => {
assert.match(buildQueuedChatSubmitNotice(1), /当前任务完成后/);
assert.match(buildQueuedChatSubmitNotice(2), /2 条待执行/);
});
test('canFlushQueuedChatSubmit waits for idle composer without pending tool or run', () => {
assert.equal(
canFlushQueuedChatSubmit({
chatState: 'idle',
queueLength: 1,
}),
true,
);
assert.equal(
canFlushQueuedChatSubmit({
chatState: 'waiting',
queueLength: 1,
}),
false,
);
assert.equal(
canFlushQueuedChatSubmit({
chatState: 'idle',
agentRunPending: true,
queueLength: 1,
}),
false,
);
assert.equal(
canFlushQueuedChatSubmit({
chatState: 'idle',
pendingTool: true,
queueLength: 1,
}),
false,
);
});
test('reconcileSessionEventRequestContext adopts Goose request id while agent-run gate waits', () => {
assert.deepEqual(
reconcileSessionEventRequestContext({