fix(web): keep composer enabled while generating and treat stop as neutral (BUG-551, BUG-552)

Enter now queues one follow-up instead of dropping it, and a rectification stop leaves the streamed reply with a grey notice instead of an error alert.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-06 13:08:43 +08:00
co-authored by Cursor
parent f5566c06ef
commit 055b7adca9
18 changed files with 534 additions and 74 deletions
@@ -542,10 +542,25 @@ test("rectification composer can stop a live agent run", () => {
assert.match(chat, /onStop=\{stopRun\}/);
assert.match(readFileSync(new URL("../src/components/chat-composer.tsx", import.meta.url), "utf8"), /className="composer-stop"/);
assert.match(chat, /event\.type === "attempt\.reset"/);
assert.match(chat, /caught\.name === "AbortError"/);
// 原值:caught.name === "AbortError"
// 新值:isAbortError(caught)
// 原因:选择题与采用路径共用同一中止判定(BUG-552)
assert.match(chat, /isAbortError\(caught\)/);
assert.match(chat, /showActivity=\{displayedMessage\.state !== "settled"\}/);
});
test("aborting a live run marks the bubble stopped without an alert", () => {
assert.match(chat, /failed: false,\s*stopped: true/);
assert.match(chat, /stoppedNotice=\{message\.stopped \? RECTIFICATION_STOPPED_NOTICE : undefined\}/);
assert.doesNotMatch(chat, /role="alert"[\s\S]{0,80}RECTIFICATION_STOPPED_NOTICE/);
const choiceFetch = chat.slice(chat.indexOf("const submitStructuredChoice"), chat.indexOf("const acceptCandidate"));
assert.match(choiceFetch, /runAbort\.current = abortController/);
assert.match(choiceFetch, /signal: abortController\.signal/);
const adoptFetch = chat.slice(chat.indexOf("const acceptCandidate"), chat.indexOf("async function copyMessage"));
assert.match(adoptFetch, /runAbort\.current = abortController/);
assert.match(adoptFetch, /signal: abortController\.signal/);
});
test("conversation and house board reuse the quiet overlay scrollbar", () => {
assert.match(styles, /\[data-sidebar="content"\],\s*\n\.conversation,\s*\n\.rectification-board__body \{/);
assert.match(styles, /\.conversation \{[^}]*overflow-y:\s*auto/);