fix(web): exit rectification when the probe pool is exhausted (BUG-558)
Stop falling through to "say another event" after dated and occupation collect are done. Deliver an adopt path or a gate sentence, and add a spoken-collect stop control. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -167,11 +167,26 @@ function questionSourceFromSnapshot(value: unknown): "focus" | "unavailable" | n
|
||||
|
||||
function RectificationReadonlyRange({
|
||||
range,
|
||||
}: Readonly<{ range: readonly [string, string] }>) {
|
||||
onStop,
|
||||
}: Readonly<{
|
||||
range: readonly [string, string];
|
||||
onStop?: () => void;
|
||||
}>) {
|
||||
if (!onStop) {
|
||||
return (
|
||||
<p className="rectification-readonly-range" role="status">
|
||||
目前范围 {range[0]}–{range[1]},还在收窄
|
||||
</p>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p className="rectification-readonly-range" role="status">
|
||||
<button
|
||||
type="button"
|
||||
className="rectification-readonly-range"
|
||||
onClick={onStop}
|
||||
>
|
||||
目前范围 {range[0]}–{range[1]},还在收窄
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1080,23 +1095,27 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
action: typeof CHOICE_ACTION | typeof STOP_ACTION | typeof SKIP_PROBE_ACTION,
|
||||
optionId: ChoiceKey | "stop" | "skip_probe",
|
||||
override?: Readonly<{
|
||||
focusId: string;
|
||||
questionId: string | null;
|
||||
focusId?: string;
|
||||
questionId?: string | null;
|
||||
probeId?: string | null;
|
||||
caseRevision?: number | null;
|
||||
}>,
|
||||
) => {
|
||||
const focusId = override?.focusId ?? choiceCard?.focus_id;
|
||||
if (!focusId || busy || readonly) return;
|
||||
if (!override && !choiceCard) return;
|
||||
if (!isPersistedFocusId(focusId)) {
|
||||
const focusId = override?.focusId ?? choiceCard?.focus_id ?? (
|
||||
action === STOP_ACTION && currentQuestion?.kind === "collect_spoken"
|
||||
? currentQuestion.focus_id
|
||||
: null
|
||||
);
|
||||
if (busy || readonly) return;
|
||||
if (action !== STOP_ACTION && (!focusId || (!override && !choiceCard))) return;
|
||||
if (focusId && !isPersistedFocusId(focusId)) {
|
||||
setError("当前选择题已失效,请等待下一问。");
|
||||
return;
|
||||
}
|
||||
const questionId = override?.questionId ?? choiceCard?.question_id;
|
||||
const questionId = override?.questionId ?? choiceCard?.question_id ?? currentQuestion?.question_id ?? null;
|
||||
const probeId = override?.probeId ?? choiceCard?.probe_id;
|
||||
const expectedRevision = override?.caseRevision ?? choiceCard?.case_revision ?? 0;
|
||||
const actionId = actionIdForChoice(focusId, optionId);
|
||||
const actionId = actionIdForChoice(focusId ?? caseId, optionId);
|
||||
setError("");
|
||||
keyCounter.current += 1;
|
||||
const turnKey = keyCounter.current;
|
||||
@@ -1104,7 +1123,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
const recordingLabel = RECTIFICATION_ACTIVITY_PROGRESS_LABELS.recording_answer;
|
||||
beginLiveRun(recordingLabel);
|
||||
setMessages((current) => [
|
||||
...markQuestionAnswered(current, focusId, optionId),
|
||||
...markQuestionAnswered(current, focusId ?? "", optionId),
|
||||
{
|
||||
role: "assistant",
|
||||
text: "",
|
||||
@@ -1132,8 +1151,8 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
requestId: actionId,
|
||||
action,
|
||||
actionId,
|
||||
focusId,
|
||||
questionId,
|
||||
...(focusId ? { focusId } : {}),
|
||||
...(questionId ? { questionId } : {}),
|
||||
probeId: probeId ?? null,
|
||||
optionId: optionId === "stop" ? undefined : optionId,
|
||||
expectedRevision,
|
||||
@@ -1219,6 +1238,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
beginLiveRun,
|
||||
caseId,
|
||||
choiceCard,
|
||||
currentQuestion,
|
||||
loadCaseSnapshot,
|
||||
onCompleted,
|
||||
onMessagesChange,
|
||||
@@ -1523,9 +1543,19 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
}
|
||||
|
||||
function submitStop() {
|
||||
if (!choiceCard) return;
|
||||
if (choiceCard.skip_this_probe) {
|
||||
void submitStructuredChoice(SKIP_PROBE_ACTION, "skip_probe");
|
||||
if (choiceCard) {
|
||||
if (choiceCard.skip_this_probe) {
|
||||
void submitStructuredChoice(SKIP_PROBE_ACTION, "skip_probe");
|
||||
return;
|
||||
}
|
||||
void submitStructuredChoice(STOP_ACTION, "stop");
|
||||
return;
|
||||
}
|
||||
if (currentQuestion?.kind === "collect_spoken" && currentQuestion.focus_id) {
|
||||
void submitStructuredChoice(STOP_ACTION, "stop", {
|
||||
focusId: currentQuestion.focus_id,
|
||||
questionId: currentQuestion.question_id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
void submitStructuredChoice(STOP_ACTION, "stop");
|
||||
@@ -1686,7 +1716,10 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
/>
|
||||
)}
|
||||
{showReadonlyRange && message.renderKey === latestSettledAssistant?.renderKey && candidateResult?.credibleRange && (
|
||||
<RectificationReadonlyRange range={candidateResult.credibleRange} />
|
||||
<RectificationReadonlyRange
|
||||
range={candidateResult.credibleRange}
|
||||
onStop={readonly || busy ? undefined : submitStop}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -1746,6 +1779,15 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
<span className="rectification-adopt-status__hint">之后新建对话即按此时间排盘。</span>
|
||||
</div>
|
||||
)}
|
||||
{currentQuestion?.kind === "collect_spoken" && !readonly && !busy && (
|
||||
<button
|
||||
type="button"
|
||||
className="rectification-collect-stop"
|
||||
onClick={submitStop}
|
||||
>
|
||||
{CHOICE_STOP_LABEL}
|
||||
</button>
|
||||
)}
|
||||
<ChatComposer
|
||||
inputRef={composer}
|
||||
value={draft}
|
||||
|
||||
Reference in New Issue
Block a user