fix(rectification): put the collect stem in the assistant bubble
Independent Staging Quality Gate / validate (push) Failing after 8m27s
Independent Staging Quality Gate / publish (push) Has been skipped

The live question slot still rendered the collect prompt below the action icons when the streamed body was only a greeting. Join the GET prompt into that bubble and stop drawing a sibling collect slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-02 16:30:26 +08:00
co-authored by Cursor
parent 39c30b5597
commit 42c6de142b
3 changed files with 67 additions and 47 deletions
@@ -105,23 +105,21 @@ test("cases current_question drives the unified question slot", () => {
assert.equal(parseRectificationChoiceCard(COLLECT_GET_QUESTION), null);
});
test("collect_spoken stem stays in the same assistant body; the slot is fallback only", () => {
test("collect_spoken stem is joined into the latest assistant bubble, never a slot sibling", () => {
const chat = readFileSync(new URL("../src/components/rectification-agentic-chat.tsx", import.meta.url), "utf8");
const styles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
const agentRun = readFileSync(new URL("../src/lib/rectification-agentic/v9/agent-run.ts", import.meta.url), "utf8");
assert.match(chat, /currentQuestion\?\.kind === "collect_spoken"/);
assert.match(chat, /const collectSpokenPrompt =/);
assert.match(chat, /composeCollectSpokenAssistantText\(latestCollectBody, collectSpokenPrompt\)/);
assert.match(chat, /const collectStemAlreadyInLatestBody = Boolean\(/);
assert.match(chat, /const showCollectSpokenPrompt = Boolean\(/);
assert.match(chat, /!collectStemAlreadyInLatestBody/);
assert.match(chat, /!busy/);
assert.match(chat, /composeCollectSpokenAssistantText\(displayedMessage\.text, collectSpokenPrompt\)/);
assert.match(chat, /composeCollectSpokenAssistantText\(last\.text, prompt\)/);
assert.match(chat, /composeCollectSpokenAssistantText\(parsed\.text, collectPrompt\)/);
assert.doesNotMatch(chat, /showCollectSpokenPrompt/);
assert.doesNotMatch(chat, /rectification-question-slot__prompt/);
assert.doesNotMatch(chat, /collectSpokenPromptId/);
assert.match(chat, /showQuestionSlot/);
assert.match(chat, /isLatestMessage && showQuestionSlot/);
assert.match(chat, /messages\.length === 0 && showQuestionSlot/);
assert.match(chat, /showCollectSpokenPrompt \|\| collectStemAlreadyInLatestBody/);
assert.match(chat, /rectification-question-slot__prompt/);
assert.match(chat, /describedBy=\{showCollectSpokenPrompt/);
assert.match(chat, /collectSpokenPrompt\n\s+\? "请回答上面的问题…"/);
assert.match(
readFileSync(new URL("../src/components/chat-composer.tsx", import.meta.url), "utf8"),
/\[describedBy, showRemaining \? remainingId : undefined\]\.filter\(Boolean\)\.join\(" "\)/,
@@ -137,7 +135,6 @@ test("collect_spoken stem stays in the same assistant body; the slot is fallback
assert.doesNotMatch(agentRun, /answerText\.(?:includes|match|search)\(/);
assert.match(styles, /\.rectification-question-slot \{[\s\S]*width: calc\(100% - var\(--assistant-content-inset\)\)/);
assert.match(styles, /\.rectification-question-slot \{[\s\S]*margin-inline-start: var\(--assistant-content-inset\)/);
assert.match(styles, /\.rectification-question-slot__prompt \{/);
assert.doesNotMatch(styles, /\.rectification-question-slot \.rectification-choice-card \{/);
});