"use client"; import React, { useState, useRef, useEffect, useMemo } from "react"; import DiagnosticsView from "@/components/diagnostics-view"; import GraphUpdateView from "@/components/graph-update-view"; import SituationGraphView from "@/components/situation-graph-view"; // ── Status message pools for loading feedback ──────────────── const INITIAL_MESSAGES = [ { min: 0, text: "Reading your situation" }, { min: 10, text: "Building a structured understanding" }, { min: 25, text: "Identifying what is known and still unclear" }, { min: 45, text: "Selecting the next useful question" }, ]; const UPDATE_MESSAGES = [ { min: 0, text: "Considering your answer" }, { min: 10, text: "Updating the situation" }, { min: 25, text: "Checking what changed" }, { min: 45, text: "Choosing the next question" }, ]; function useLoadingStatus(messages, isLoading) { const [elapsed, setElapsed] = useState(0); const startRef = useRef(null); useEffect(() => { if (isLoading) { startRef.current = Date.now(); const iv = setInterval(() => { setElapsed(Math.floor((Date.now() - startRef.current) / 1000)); }, 1000); return () => clearInterval(iv); } else { setElapsed(0); startRef.current = null; } }, [isLoading]); const currentMessage = useMemo(() => { if (!messages || messages.length === 0) return ""; let msg = messages[0].text; for (const m of messages) { if (elapsed >= m.min) msg = m.text; } return msg; }, [messages, elapsed]); return { elapsed, currentMessage }; } // ── Spinner component ─────────────────────────────────────── function ActivitySpinner() { return ( ); } // ── Situation card ──────────────────────────────────────────── function SituationCard({ centralStatement }) { if (!centralStatement) return null; return (

Your situation

{centralStatement}

); } // ── Current understanding card ──────────────────────────────── function CurrentUnderstanding({ currentSummary }) { if (currentSummary) { return (

What we've established

{currentSummary}

); } return (

We have started to separate what is known from what still needs checking.

); } // ── Current investigation card (prominent) ───────────────────── function CurrentInvestigationCard({ selectedQuestion }) { if (!selectedQuestion) return null; const q = typeof selectedQuestion === "string" ? selectedQuestion : selectedQuestion.question; if (!q) return null; return (

Current investigation

{q}

); } // ── Investigation progress card ────────────────────────────── function InvestigationProgress({ graph, noQuestionReason: rwNoQuestionReason }) { if (!graph?.nodes?.length) return null; const resolvedIds = new Set(graph.resolvedNodeIds || []); const unknowns = graph.nodes.filter((n) => n.kind === "unknown"); const remainingCount = unknowns.filter( (u) => u.status !== "resolved" && !resolvedIds.has(u.id), ).length; const activeNode = graph.activeUnknownNodeId ? graph.nodes.find((n) => n.id === graph.activeUnknownNodeId) : null; return (
{remainingCount > 0 && !rwNoQuestionReason ? (

We are still building confidence about your situation.{" "} {remainingCount === 1 ? "One area remains." : `${remainingCount} areas remain.`}

) : (

All areas under investigation are now complete.

)} {activeNode && ( <>

Current focus

{activeNode.label}

{activeNode.description && activeNode.description !== activeNode.label && (

Why it matters: {activeNode.description}

)} )} {!activeNode && remainingCount === 0 && (

There is nothing further to investigate at this time.

)}
); } // ── 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; } 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. )}

); } // ── Developer details disclosure ────────────────────────────── function DeveloperDetails({ graph, selectedQuestion, diagnostics, newlySurfacedNodeIds, updateResult }) { return (
Developer details
{graph && ( )} {updateResult && ( )} {diagnostics && }
); } // ── Main workspace component ────────────────────────────────── export default function ReasoningWorkspace({ status, updateStatus, result, answer, setAnswer, onAnswerSubmit, }) { const { elapsed: startElapsed, currentMessage: startMsg } = useLoadingStatus( INITIAL_MESSAGES, status === "loading" ); const { elapsed: updateElapsed, currentMessage: updateMsg } = useLoadingStatus( UPDATE_MESSAGES, updateStatus === "loading" ); const canAnswer = status === "success" && updateStatus === "idle" && Boolean(result?.situationGraph) && Boolean(result?.selectedQuestion); const selectedQ = result?.selectedQuestion ?? null; const graph = result?.situationGraph ?? null; const diagnostics = result?.diagnostics ?? null; const newlySurfacedNodeIds = result?.newlySurfacedNodeIds || []; const noQuestionReason = diagnostics?.noQuestionReason ?? null; return (
{/* ── Loading overlays ─────────────────────────────── */} {updateStatus === "loading" && (
)} {/* ── User-facing workspace ────────────────────────── */} {(status === "success" || status === "error") && !graph ? (
{noQuestionReason ? "Validation failed — no structured graph output was produced." : "The analysis completed but did not produce a structured result."}
) : ( <> {/* When investigation has nothing further to ask */} {status === "success" && !canAnswer && graph && ( )} {graph && } {graph && } {canAnswer && } {graph && } {/* ── Answer form ──────────────────────────────── */} {canAnswer && (