fix(rectification): put each question inside the assistant message
Independent Staging Quality Gate / validate (push) Successful in 25m7s
Independent Staging Quality Gate / publish (push) Successful in 2m8s

Focuses now carry asked_turn_id so GET rebuilds stem and options on the
same turn. Agent writes spokenPrompt; the live question slot is gone.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-02 19:55:20 +08:00
co-authored by Cursor
parent a594990a16
commit d94049769e
42 changed files with 1760 additions and 475 deletions
@@ -737,6 +737,7 @@ export async function POST(request: Request) {
caseId,
action,
assistantBodyPresent: Boolean(result.answerText?.trim()),
askedTurnId: result.turnId,
});
} catch (error) {
const code = error instanceof RectificationToolServiceError ? error.code : "run_failed";
@@ -9,10 +9,13 @@ import {
loadV9TurnReceipt,
receiptStatusFromTurn,
RectificationToolServiceError,
listV10ConversationFocuses,
type ConversationFocus,
type V9CaseDossier,
} from "@/lib/rectification-agentic/v9/tool-service";
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision } from "@/lib/rectification-agentic/v9/interview-state";
import { projectCurrentQuestion } from "@/lib/rectification-agentic/v9/turn-decision";
import { attachQuestionsToTurns } from "@/lib/rectification-agentic/v9/turn-question";
import { previousInferenceFromReceipt } from "@/lib/rectification-agentic/v9/inference-adapter";
import { publicDecisionFields } from "@/lib/rectification-agentic/core/rectification-decision";
import { slimDecisionReceipt } from "@/lib/rectification-agentic/v9/case-receipt-projection";
@@ -69,7 +72,8 @@ export async function GET(request: Request, context: RouteContext) {
}
}),
);
return NextResponse.json(dossierResponse(dossier, receipts, skillIdentity, { fullDetail }));
const focuses = await listV10ConversationFocuses(accounting, user.id, caseId);
return NextResponse.json(dossierResponse(dossier, receipts, skillIdentity, { fullDetail, focuses }));
} catch (error) {
if (error instanceof RectificationToolServiceError) {
const message = error.message;
@@ -88,11 +92,12 @@ function dossierResponse(
dossier: V9CaseDossier,
receipts: Array<Awaited<ReturnType<typeof loadV9TurnReceipt>>>,
skillIdentity: Awaited<ReturnType<typeof loadV9CaseSkillIdentityStatus>>,
options: { fullDetail?: boolean } = {},
options: { fullDetail?: boolean; focuses?: readonly ConversationFocus[] } = {},
) {
const decision = decideFromDossier(dossier, {
currentEvidenceFingerprint: evidenceLedgerFingerprint(dossier.evidence),
});
const turns = attachQuestionsToTurns(dossier.turns, options.focuses ?? []);
return {
case: {
case_id: dossier.case.caseId,
@@ -110,13 +115,14 @@ function dossierResponse(
last_activity_at: dossier.case.lastActivityAt,
case_revision: previousInferenceFromReceipt(dossier.latestResult?.decisionReceipt ?? null)?.revision ?? 0,
},
turns: dossier.turns.map((turn) => ({
turns: turns.map((turn) => ({
id: turn.id,
role: turn.role,
text: turn.text,
status: turn.status,
created_at: turn.createdAt,
receipt: turnReceipt(turn.id, receipts),
question: turn.question,
})),
evidence: dossier.evidence,
latest_result: dossier.latestResult
+19 -15
View File
@@ -2898,30 +2898,21 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
font-size: var(--type-caption);
}
.rectification-question-slot {
.rectification-message-question {
display: grid;
gap: var(--space-2);
width: calc(100% - var(--assistant-content-inset));
margin-block: var(--space-3);
margin-inline-start: var(--assistant-content-inset);
}
.rectification-message-wrap .rectification-question-slot {
width: calc(100% - var(--assistant-content-inset));
margin-inline-start: var(--assistant-content-inset);
}
.rectification-message-wrap .rectification-question-slot > .rectification-choice-card {
gap: var(--space-3);
margin-block-start: var(--space-3);
width: 100%;
margin-inline-start: 0;
}
.rectification-question-slot__prompt {
.rectification-message-question__prompt {
margin: 0;
color: var(--color-ink);
font-size: var(--type-body-sm);
font-weight: 600;
line-height: 1.55;
}
.rectification-question-slot__status {
margin: 0;
.rectification-composer-status {
margin: 0 0 var(--space-2);
color: var(--color-ink-secondary);
font-size: var(--type-caption);
}
@@ -2976,6 +2967,19 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
margin: var(--space-3) 0 var(--space-4);
margin-inline-start: var(--assistant-content-inset);
}
.rectification-message-wrap .rectification-choice-card.is-embedded,
.message-bubble .rectification-choice-card.is-embedded {
width: 100%;
margin: 0;
margin-inline-start: 0;
padding: 0;
border: none;
border-radius: 0;
background: transparent;
}
.rectification-choice-card.is-embedded .birth-time-choice-question legend {
display: unset;
}
.rectification-choice-why {
margin: 0 0 var(--space-3);
color: var(--color-ink-secondary);