fix: show update reasoning progress

This commit is contained in:
2026-08-03 18:00:20 +01:00
parent 7bc1c93486
commit 74fc6d1457
2 changed files with 353 additions and 21 deletions
+74 -17
View File
@@ -5,6 +5,33 @@ import DiagnosticsView from "@/components/diagnostics-view";
import GraphUpdateView from "@/components/graph-update-view";
import SituationGraphView from "@/components/situation-graph-view";
// ── Technical summary detector (main view filters these) ───
const TECHNICAL_PATTERNS = [
/nodes?\s*[:\d]/i,
/edges?\s*[:\d]/i,
/\b(?:unknown|observation|conclusion)\b\s/i,
/\bsorted\b/i,
/by_kind/i,
/\b(?:node|edge|unknown|state)\s+count/i,
];
function isTechnicalSummary(summary) {
if (!summary || typeof summary !== "string") return false;
const trimmed = summary.trim();
if (!trimmed) return false;
for (const p of TECHNICAL_PATTERNS) {
if (p.test(trimmed)) return true;
}
return false;
}
function resolveCurrentSummary(currentSummary) {
if (isTechnicalSummary(currentSummary)) {
return null;
}
return currentSummary || null;
}
// ── Status message pools for loading feedback ────────────────
const INITIAL_MESSAGES = [
{ min: 0, text: "Reading your situation" },
@@ -74,22 +101,20 @@ function SituationCard({ centralStatement }) {
// ── Current understanding card ────────────────────────────────
function CurrentUnderstanding({ currentSummary }) {
if (currentSummary) {
return (
<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">
What we&#x27;ve established
</h2>
<p className="text-sm leading-relaxed text-gray-700">{currentSummary}</p>
</div>
);
}
const summary = resolveCurrentSummary(currentSummary);
return (
<div className="investigation-card rounded-lg border border-gray-200 bg-white p-5">
<p className="text-sm leading-relaxed text-gray-600">
We have started to separate what is known from what still needs checking.
</p>
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500">
What we&#x27;ve established
</h2>
{summary ? (
<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>
);
}
@@ -111,6 +136,22 @@ function CurrentInvestigationCard({ selectedQuestion }) {
);
}
// ── Outcome helpers ───────────────────────────────────────────
function hasGenuineCompletion(graph) {
if (!graph || !graph.nodes?.length) return false;
const resolvedIds = new Set(graph.resolvedNodeIds || []);
const unresolvedCount = graph.nodes.filter(
(n) => n.kind === "unknown" && n.status !== "resolved" && !resolvedIds.has(n.id),
).length;
if (unresolvedCount > 0) return false;
if (graph.activeUnknownNodeId) {
const active = graph.nodes.find((n) => n.id === graph.activeUnknownNodeId);
if (active && active.status !== "resolved" && !resolvedIds.has(active.id)) return false;
}
return true;
}
// ── Investigation progress card ──────────────────────────────
function InvestigationProgress({ graph, noQuestionReason: rwNoQuestionReason }) {
if (!graph?.nodes?.length) return null;
@@ -124,9 +165,11 @@ function InvestigationProgress({ graph, noQuestionReason: rwNoQuestionReason })
? graph.nodes.find((n) => n.id === graph.activeUnknownNodeId)
: null;
const isComplete = hasGenuineCompletion(graph);
return (
<div className="investigation-card rounded-lg border border-gray-200 bg-white px-5 py-4">
{remainingCount > 0 && !rwNoQuestionReason ? (
{remainingCount > 0 && !isComplete ? (
<p className="text-sm leading-relaxed text-gray-700">
We are still building confidence about your situation.{" "}
{remainingCount === 1
@@ -262,6 +305,13 @@ export default function ReasoningWorkspace({
const newlySurfacedNodeIds = result?.newlySurfacedNodeIds || [];
const noQuestionReason = diagnostics?.noQuestionReason ?? null;
const remainingUnknowns = graph?.nodes?.filter(
(n) => n.kind === "unknown" && n.status !== "resolved" && !(graph.resolvedNodeIds || []).includes(n.id),
);
const genuineCompletion = hasGenuineCompletion(graph);
const unresolvedRemaining = !genuineCompletion && remainingUnknowns ? remainingUnknowns.length > 0 : false;
return (
<div className="space-y-5">
{/* ── Loading overlays ─────────────────────────────── */}
@@ -290,10 +340,17 @@ export default function ReasoningWorkspace({
</div>
) : (
<>
{/* When investigation has nothing further to ask */}
{status === "success" && !canAnswer && graph && (
{/* Completion or holding state (only when there is no next question) */}
{status === "success" && !canAnswer && graph && genuineCompletion && (
<InvestigationCompleteMessage noQuestionReason={noQuestionReason} />
)}
{status === "success" && !canAnswer && graph && unresolvedRemaining && (
<div className="rounded-lg border border-gray-200 bg-gray-50 px-5 py-4 text-center">
<p className="text-sm text-gray-600">There is no further question the engine can justify at the moment.</p>
<p className="mt-1 text-xs text-gray-500">More evidence may be needed before a next step is clear.</p>
</div>
)}
{graph && <SituationCard centralStatement={graph.centralStatement} />}
{graph && <CurrentUnderstanding currentSummary={graph.currentSummary} />}
{canAnswer && <CurrentInvestigationCard selectedQuestion={selectedQ} />}
@@ -363,4 +420,4 @@ export default function ReasoningWorkspace({
);
}
export { useLoadingStatus, INITIAL_MESSAGES, UPDATE_MESSAGES, LoadingOverlay };
export { useLoadingStatus, INITIAL_MESSAGES, UPDATE_MESSAGES, LoadingOverlay, resolveCurrentSummary, isTechnicalSummary };