fix(chat): keep rectification sessions findable and keep the delivery card
Rectification answers now advance chat_sessions.updated_at (BUG-704). A ?c= id missing from the loaded page is fetched before anyone may call it deleted (BUG-705). The range card no longer has a post-card tie-break button; live questions leave the card visible with adopt locked (BUG-706/708). Spoken copy bans 相对支持度 (BUG-709). Task docs assigned 700-704; qizheng already took 700-703.
This commit is contained in:
@@ -97,7 +97,7 @@ import {
|
||||
stableChoiceActionKey,
|
||||
type ChoiceOptionId,
|
||||
} from "@/lib/rectification-agentic/v9/choice-action";
|
||||
import { RECTIFICATION_USER_COPY, postAdoptVerifyDoneCopy } from "@/lib/rectification-agentic/user-copy";
|
||||
import { postAdoptVerifyDoneCopy } from "@/lib/rectification-agentic/user-copy";
|
||||
import { isRectificationCaseStatus, isResumableStatus, type RectificationCaseStatus } from "@/lib/rectification-agentic/v9/case-status";
|
||||
import { CHOICE_MODE, CHOICE_SKIP_QUESTION_LABEL, CHOICE_SKIP_QUESTION_MESSAGE, CHOICE_STOP_LABEL, CHOICE_STOP_MESSAGE, isPersistedFocusId, parseRectificationChoiceCard, type ChoiceKey, type RectificationChoiceCard as ChoiceCardModel } from "@/lib/rectification-agentic/v9/choice-card";
|
||||
import type { PublicLanguageModel } from "@/lib/public-models";
|
||||
@@ -1343,45 +1343,6 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
}
|
||||
}, [acceptingCandidateId, beginLiveRun, busy, candidateResult, caseId, loadCaseSnapshot, onCompleted, onSaved, readonly, send, sessionId, setPending]);
|
||||
|
||||
const requestTieBreak = useCallback(async () => {
|
||||
if (!candidateResult || acceptingCandidateId || busy || readonly) return;
|
||||
if (!candidateResult.rangeDelivery?.tie_break_available) return;
|
||||
setError("");
|
||||
setPending(true);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/rectification/cases/${encodeURIComponent(caseId)}/tie-break`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
sessionId,
|
||||
requestId: globalThis.crypto.randomUUID(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
const payload = await response.json().catch(() => null);
|
||||
if (payload?.code === "tie_break_unavailable") {
|
||||
await loadCaseSnapshot();
|
||||
return;
|
||||
}
|
||||
if (!response.ok || payload?.ok !== true) {
|
||||
throw new Error(payload?.error || payload?.message || "暂时无法开始参考题");
|
||||
}
|
||||
await loadCaseSnapshot((turns) => {
|
||||
setMessages((current) => applySnapshotTurnsToMessages(
|
||||
current,
|
||||
turns,
|
||||
(incoming) => messagesFromTurns(incoming as readonly PersistedTurn[]),
|
||||
));
|
||||
});
|
||||
} catch (caught) {
|
||||
setError(caught instanceof Error ? caught.message : "暂时无法开始参考题");
|
||||
} finally {
|
||||
setPending(false);
|
||||
}
|
||||
}, [acceptingCandidateId, busy, candidateResult, caseId, loadCaseSnapshot, readonly, sessionId, setPending]);
|
||||
|
||||
async function copyMessage(message: RenderMessage) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(copyTextForMessage(message.text, message.question));
|
||||
@@ -1509,15 +1470,19 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
const keepSelectionCardsWhileBusy = Boolean(
|
||||
acceptingCandidateId || candidateResult?.selectedTime,
|
||||
);
|
||||
const liveInterviewBlockingAdopt = Boolean(
|
||||
candidateResult
|
||||
&& !candidateResult.selectedTime
|
||||
&& messages.some((message) => (
|
||||
interviewQuestionBlocksAdoptOffer(message.question, false)
|
||||
)),
|
||||
);
|
||||
const showSelectionCards = Boolean(
|
||||
candidateResult
|
||||
&& caseSnapshotLoaded
|
||||
&& (!busy || keepSelectionCardsWhileBusy)
|
||||
&& selectionCardMessageKey
|
||||
&& (canOfferCards || Boolean(candidateResult.selectedTime))
|
||||
&& !messages.some((message) => (
|
||||
interviewQuestionBlocksAdoptOffer(message.question, Boolean(candidateResult.selectedTime))
|
||||
)),
|
||||
);
|
||||
const showReadonlyRange = Boolean(
|
||||
canShowRectificationReadonlyRange(candidateResult)
|
||||
@@ -1843,7 +1808,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
acceptingCandidateId={acceptingCandidateId}
|
||||
readonly={readonly || regeneratingMessageKey !== null || (busy && !acceptingCandidateId)}
|
||||
onAccept={(candidateId) => void acceptCandidate(candidateId)}
|
||||
onTieBreak={() => void requestTieBreak()}
|
||||
adoptLocked={liveInterviewBlockingAdopt}
|
||||
/>
|
||||
{verifiedIdleCopy && (
|
||||
<p className="rectification-pending-note" role="status">
|
||||
|
||||
@@ -21,19 +21,19 @@ export function RectificationRangeDelivery({
|
||||
acceptingCandidateId,
|
||||
readonly,
|
||||
onAccept,
|
||||
onTieBreak,
|
||||
adoptLocked,
|
||||
}: Readonly<{
|
||||
result: RectificationCandidateResult;
|
||||
acceptingCandidateId: string | null;
|
||||
readonly: boolean;
|
||||
onAccept: (candidateId: string) => void;
|
||||
onTieBreak?: () => void;
|
||||
adoptLocked?: boolean;
|
||||
}>) {
|
||||
const delivery: RangeDeliveryProjection | null = result.rangeDelivery;
|
||||
const range = delivery?.range ?? result.credibleRange;
|
||||
const eventCount = delivery?.event_count ?? 0;
|
||||
const selected = result.selectedTime;
|
||||
const busy = Boolean(acceptingCandidateId) || readonly;
|
||||
const busy = Boolean(acceptingCandidateId) || readonly || adoptLocked;
|
||||
const columns = delivery?.columns ?? [];
|
||||
const title = range
|
||||
? eventCount > 0
|
||||
@@ -68,15 +68,10 @@ export function RectificationRangeDelivery({
|
||||
{delivery?.provenance_line ? (
|
||||
<p className="rectification-range-delivery__provenance">{delivery.provenance_line}</p>
|
||||
) : null}
|
||||
{delivery?.tie_break_available && onTieBreak && !readonly ? (
|
||||
<button
|
||||
type="button"
|
||||
className="rectification-range-delivery__tie-break"
|
||||
disabled={busy}
|
||||
onClick={onTieBreak}
|
||||
>
|
||||
{RECTIFICATION_USER_COPY.rangeDeliveryTieBreakEntry}
|
||||
</button>
|
||||
{adoptLocked ? (
|
||||
<p className="rectification-range-delivery__narrow">
|
||||
{RECTIFICATION_USER_COPY.rangeDeliveryAdoptLocked}
|
||||
</p>
|
||||
) : null}
|
||||
{delivery?.tie_break_note ? (
|
||||
<p className="rectification-range-delivery__narrow">{delivery.tie_break_note}</p>
|
||||
|
||||
Reference in New Issue
Block a user