From ae615c43433dc664df9107cfbb23104c3c951503 Mon Sep 17 00:00:00 2001 From: robbond Date: Tue, 4 Aug 2026 17:39:30 +0100 Subject: [PATCH] feat: make the workspace tldr first --- components/reasoning-workspace.jsx | 273 ++++++++++++++--------------- components/scenario-form.jsx | 56 ++++-- 2 files changed, 166 insertions(+), 163 deletions(-) diff --git a/components/reasoning-workspace.jsx b/components/reasoning-workspace.jsx index e65ccbf..c8aae00 100644 --- a/components/reasoning-workspace.jsx +++ b/components/reasoning-workspace.jsx @@ -86,45 +86,21 @@ function ActivitySpinner() { ); } -// ── Situation card ──────────────────────────────────────────── -function SituationCard({ centralStatement }) { - if (!centralStatement) return null; - return ( -
-

- Your situation -

-

{centralStatement}

-
- ); -} - -// ── Current understanding card ──────────────────────────────── -function CurrentUnderstanding({ currentSummary }) { - const summary = resolveCurrentSummary(currentSummary); - - if (!summary) return null; - - return ( -
-

- What we've established -

-

{summary}

-
- ); -} - -// ── Current investigation card (prominent) ───────────────────── +// ── Current investigation card (prominent hero section) ────── function CurrentInvestigationCard({ selectedQuestion, graph }) { if (!selectedQuestion) return null; const q = typeof selectedQuestion === "string" ? selectedQuestion : selectedQuestion.question; if (!q) return null; - const activeNode = graph?.activeUnknownNodeId - ? graph.nodes.find((n) => n.id === graph.activeUnknownNodeId) - : null; + // Derive meaningful context from the active node only when it adds value + let whyMattersText = null; + if (graph?.activeUnknownNodeId && graph.nodes) { + const activeNode = graph.nodes.find((n) => n.id === graph.activeUnknownNodeId); + if (activeNode?.description && activeNode.description !== activeNode.label) { + whyMattersText = activeNode.description; + } + } return (
@@ -132,18 +108,10 @@ function CurrentInvestigationCard({ selectedQuestion, graph }) { Current investigation

{q}

- {activeNode?.description && activeNode.description !== activeNode.label && ( + {whyMattersText && (
-

Why we are asking this

-

{activeNode.description}

-
- )} - {graph?.activeUnknownNodeId && activeNode && ( -
-

What we are investigating

-

- Understanding whether "{activeNode.label}" affects the confidence in this situation. -

+

Why this matters

+

{whyMattersText}

)}
@@ -166,34 +134,50 @@ function hasGenuineCompletion(graph) { return true; } -// ── Current focus card ─────────────────────────────────────── -function CurrentFocusCard({ graph }) { - const activeNode = graph?.activeUnknownNodeId - ? graph.nodes.find((n) => n.id === graph.activeUnknownNodeId) - : null; - - if (!graph || !activeNode) return null; - +// ── Completion card (terminal state when all unknowns resolved) ─ +function CompletionCard() { return ( -
-

- Current focus -

-

- We are investigating one part of your situation at a time. - {activeNode && ( - <> -
- Right now we are trying to understand{" "} - {activeNode.label}. - - )} -

+
+

Investigation complete

+

You have provided enough information. The situation has been fully investigated.

); } -// ── Investigation history card (readable notebook style) ─────── +// ── Evidence exhaustion card (terminal state) ───────────────── +function EvidenceExhaustedCard({ noQuestionReason }) { + let message = "There is not yet enough evidence to guide the next step."; + if (noQuestionReason) { + const reason = String(noQuestionReason); + if (reason.toLowerCase().includes("insufficient")) { + message = reason; + } + } + return ( +
+

Further investigation needed

+

{message}

+
+ ); +} + +// ── Current understanding card ──────────────────────────────── +function CurrentUnderstandingCard({ currentSummary }) { + const summary = resolveCurrentSummary(currentSummary); + + if (!summary) return null; + + return ( +
+

+ Current understanding +

+

{summary}

+
+ ); +} + +// ── Investigation history card (readable notebook style) ────── function InvestigationHistoryCard({ turn }) { const isCollapsed = turn._collapsed; @@ -249,54 +233,22 @@ function InvestigationHistory({ turns }) { ); } -// ── Investigation complete state ─────────────────────────────── -function InvestigationCompleteMessage({ noQuestionReason }) { - let message = "We have established enough for now."; - if (noQuestionReason) { - const reason = String(noQuestionReason); - if ( - reason.toLowerCase().includes("resolved") || - reason.toLowerCase().includes("satisfied") || - reason.toLowerCase().includes("complete") - ) { - message = "You have provided enough information. The situation has been fully investigated."; - } else if (reason.toLowerCase().includes("insufficient")) { - message = "There is not yet enough evidence to guide the next step. Your original situation will remain our focus when new information becomes available."; - } else { - message = reason; - } - } - return ( -
-

{message}

-
- ); -} - -// ── Loading overlay (for both start and update) ─────────────── -function LoadingOverlay({ isLoading, elapsed, currentMessage, variant }) { - if (!isLoading) return null; - - const messages = variant === "update" ? UPDATE_MESSAGES : INITIAL_MESSAGES; - let statusText = messages[0].text; - for (const m of messages) { - if (elapsed >= m.min) statusText = m.text; - } +// ── Original situation (collapsed by default) ───────────────── +function OriginalSituation({ scenario, centralStatement }) { + if (!scenario) return null; return ( -
-
- - Working through your situation -
-

{statusText}

-

- This has been running for {elapsed}s. - {variant === "initial" && elapsed >= 45 && ( - This can take around a minute with the current local model. +

+ + Original situation + +
+ {centralStatement && ( +

{centralStatement}

)} -

-
+

{scenario}

+
+ ); } @@ -384,8 +336,36 @@ function DeveloperDetails({ graph, selectedQuestion, diagnostics, newlySurfacedN ); } +// ── Loading overlay (for both start and update) ─────────────── +function LoadingOverlay({ isLoading, elapsed, currentMessage, variant }) { + if (!isLoading) return null; + + const messages = variant === "update" ? UPDATE_MESSAGES : INITIAL_MESSAGES; + let statusText = messages[0].text; + for (const m of messages) { + if (elapsed >= m.min) statusText = m.text; + } + + return ( +
+
+ + Working through your situation +
+

{statusText}

+

+ This has been running for {elapsed}s. + {variant === "initial" && elapsed >= 45 && ( + This can take around a minute with the current local model. + )} +

+
+ ); +} + // ── Main workspace component ────────────────────────────────── export default function ReasoningWorkspace({ + scenario, status, updateStatus, result, @@ -459,25 +439,24 @@ export default function ReasoningWorkspace({ const genuineCompletion = hasGenuineCompletion(graph); return ( -
+
{/* ── Loading overlays ─────────────────────────────── */} - - {updateStatus === "loading" && ( -
+ {status === "loading" && ( + + )} + {updateStatus === "loading" && ( + )} - - {/* ── User-facing workspace ────────────────────────── */} + {/* ── No graph produced after initial analysis ───────── */} {(status === "success" || status === "error") && !graph ? (
{noQuestionReason @@ -486,32 +465,27 @@ export default function ReasoningWorkspace({
) : ( <> - {/* Post-update acknowledgement */} - {updateStatus === "success" && canAnswer && } + {/* ── 1. Current investigation (or terminal state) ─ */} + {canAnswer && } - {/* Completion state */} + {/* Terminal states occupy the hero position when no question */} {status === "success" && !canAnswer && graph && genuineCompletion && ( - + )} {status === "success" && !canAnswer && graph && !genuineCompletion && updateStatus !== "success" && ( -
-

There is no further question the engine can justify at the moment.

-

More evidence may be needed before a next step is clear.

-
+ )} - {/* Situation context */} - {graph && } - {graph && } + {/* ── 2. Post-update acknowledgement ─────────────── */} + {updateStatus === "success" && canAnswer && } - {/* ── Investigation history (below situation, above current focus) ─ */} + {/* ── 3. Current understanding ───────────────────── */} + {canAnswer && graph && } + + {/* ── 4. Investigation history ───────────────────── */} - {/* Active investigation (only when we have a question to answer) */} - {canAnswer && } - {canAnswer && } - - {/* ── Answer form ──────────────────────────────── */} + {/* ── 5. Response form (immediately after Current investigation) ─ */} {canAnswer && (
@@ -543,7 +517,10 @@ export default function ReasoningWorkspace({ )} - {/* ── Developer details (collapsed by default) ─── */} + {/* ── 6. Original situation (collapsed by default) ─ */} + + + {/* ── 7. Developer details (collapsed by default) ── */} {(status === "success" || status === "error") && graph && ( )} + + {/* ── Terminal state with understanding (when no active question) ─ */} + {status === "success" && !canAnswer && graph && genuineCompletion && } + {status === "success" && !canAnswer && graph && !genuineCompletion && updateStatus !== "success" && } )} diff --git a/components/scenario-form.jsx b/components/scenario-form.jsx index bd598b8..7a6a744 100644 --- a/components/scenario-form.jsx +++ b/components/scenario-form.jsx @@ -309,20 +309,20 @@ export default function ScenarioForm() { return (
-
-