fix: preserve accurate investigation history

This commit is contained in:
2026-08-04 13:27:23 +01:00
parent 91168a8213
commit dced344680
+51 -37
View File
@@ -103,18 +103,14 @@ function SituationCard({ centralStatement }) {
function CurrentUnderstanding({ currentSummary }) { function CurrentUnderstanding({ currentSummary }) {
const summary = resolveCurrentSummary(currentSummary); const summary = resolveCurrentSummary(currentSummary);
if (!summary) return null;
return ( return (
<div className="investigation-card rounded-lg border border-gray-200 bg-white p-5"> <div className="investigation-card rounded-lg border border-gray-200 bg-white p-5">
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500"> <h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
What we&#x27;ve established What we&#x27;ve established
</h2> </h2>
{summary ? ( <p className="text-sm leading-relaxed text-gray-700">{summary}</p>
<p className="text-sm leading-relaxed text-gray-700">{summary}</p>
) : (
<p className="text-sm leading-relaxed text-gray-600">
We have separated what is known from what still needs checking.
</p>
)}
</div> </div>
); );
} }
@@ -199,21 +195,30 @@ function CurrentFocusCard({ graph }) {
// ── Investigation history card ──────────────────────────────── // ── Investigation history card ────────────────────────────────
function InvestigationHistoryCard({ turn }) { function InvestigationHistoryCard({ turn }) {
const qSnippet = turn.question.length > 80
? turn.question.slice(0, 80) + "…"
: turn.question;
return ( return (
<details className="rounded-lg border border-gray-100 bg-gray-50/60 px-4 py-3"> <details className="rounded-lg border border-gray-100 bg-gray-50/60 px-4 py-3" key={turn.id}>
<summary className="cursor-pointer text-xs font-semibold uppercase tracking-wide text-gray-400 hover:text-gray-600"> <summary className="cursor-pointer text-xs font-semibold uppercase tracking-wide text-gray-400 hover:text-gray-600">
{new Date(turn.timestamp).toLocaleString(undefined, { {new Date(turn.timestamp).toLocaleString(undefined, {
month: "short", month: "short",
day: "numeric", day: "numeric",
hour: "2-digit", hour: "2-digit",
minute: "2-digit", minute: "2-digit",
})} })} {qSnippet}
</summary> </summary>
<div className="mt-2 space-y-2 text-sm"> <div className="mt-2 space-y-2 text-sm">
<p><strong>{turn.question}</strong></p> <p><strong>Question</strong></p>
<p>{turn.question}</p>
<p><strong>You answered</strong></p>
<p className="text-gray-700">{turn.answer}</p> <p className="text-gray-700">{turn.answer}</p>
{turn.acknowledgement && ( {turn.acknowledgement && (
<p className="italic text-gray-500">{turn.acknowledgement}</p> <>
<p><strong>What changed</strong></p>
<p className="italic text-gray-500">{turn.acknowledgement}</p>
</>
)} )}
</div> </div>
</details> </details>
@@ -230,8 +235,8 @@ function InvestigationHistory({ turns }) {
Investigation history Investigation history
</h2> </h2>
<div className="space-y-2"> <div className="space-y-2">
{turns.map((turn, idx) => ( {turns.map((turn) => (
<InvestigationHistoryCard key={idx} turn={turn} /> <InvestigationHistoryCard key={turn.id} turn={turn} />
))} ))}
</div> </div>
</div> </div>
@@ -384,33 +389,42 @@ export default function ReasoningWorkspace({
lastSubmittedAnswer, lastSubmittedAnswer,
}) { }) {
const [investigationHistory, setInvestigationHistory] = useState([]); const [investigationHistory, setInvestigationHistory] = useState([]);
const turnCounter = useRef(0);
const pendingTurnRef = useRef(null);
// Capture the previous question before each new question is set // Capture the current selected question at submit time (not from a stale ref)
const prevQuestionRef = useRef(null); const capturePendingTurn = (selectedQuestion, answerText) => {
const hasCapturedInitialQuestion = useRef(false); if (!selectedQuestion || !answerText?.trim()) return null;
const q = typeof selectedQuestion === "string" ? selectedQuestion : selectedQuestion.question;
if (!q) return null;
turnCounter.current += 1;
return {
id: `turn-${turnCounter.current}`,
question: q,
answer: answerText.trim(),
acknowledgement: null,
timestamp: Date.now(),
};
};
// Append the captured pending turn to history after a successful update only
useEffect(() => { useEffect(() => {
if (result?.selectedQuestion && !hasCapturedInitialQuestion.current) { const pending = pendingTurnRef.current;
prevQuestionRef.current = result.selectedQuestion; if (!pending || updateStatus !== "success") return;
hasCapturedInitialQuestion.current = true;
}
}, [result?.selectedQuestion]);
// Append completed turn to history after a successful update setInvestigationHistory((prev) => [
useEffect(() => { ...prev,
if (updateStatus === "success" && lastSubmittedAnswer) { { ...pending, acknowledgement: result?.summary || null },
const q = prevQuestionRef.current; ]);
setInvestigationHistory((prev) => [ pendingTurnRef.current = null;
...prev, }, [updateStatus, result]);
{
question: typeof q === "string" ? q : q?.question ?? "", const handleUpdateCaptureAndSubmit = async (e) => {
answer: lastSubmittedAnswer, e.preventDefault();
acknowledgement: result?.summary || null, if (!answer?.trim() || !result?.selectedQuestion) return;
timestamp: Date.now(), pendingTurnRef.current = capturePendingTurn(result.selectedQuestion, answer);
}, await onAnswerSubmit(e);
]); };
}
}, [updateStatus, lastSubmittedAnswer, result]);
const { elapsed: startElapsed, currentMessage: startMsg } = useLoadingStatus( const { elapsed: startElapsed, currentMessage: startMsg } = useLoadingStatus(
INITIAL_MESSAGES, INITIAL_MESSAGES,
@@ -494,7 +508,7 @@ export default function ReasoningWorkspace({
{/* ── Answer form ──────────────────────────────── */} {/* ── Answer form ──────────────────────────────── */}
{canAnswer && ( {canAnswer && (
<form onSubmit={onAnswerSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5"> <form onSubmit={handleUpdateCaptureAndSubmit} className="space-y-4 rounded-lg border border-gray-200 bg-white p-5">
<div> <div>
<label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700"> <label htmlFor="rw-answer" className="mb-2 block text-sm font-medium text-gray-700">
Your response Your response