"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"; import InvestigationSummaryPanel from "@/components/investigation-summary-panel"; import InvestigationSummaryPanelV2 from "@/components/investigation-summary-panel-v2"; import InvestigationSummaryPanelV3 from "@/components/investigation-summary-panel-v3"; import InvestigationMap from "@/components/investigation-map"; // ── 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; } // ── Recovery state components (Phase 2) ─────────────────────── function ProviderUnavailableCard({ onRestart }) { return (

Provider unavailable

The reasoning service could not be reached. This is usually temporary — check that the local model is running and try again.

{onRestart && ( )}
); } function MalformedResponseCard({ onRestart }) { return (

Unexpected response

The reasoning service returned a response we could not interpret. This may indicate a temporary issue with the model output format.

{onRestart && ( )}
); } function UnexpectedStateCard({ stateName, onRetry, onRestart }) { return (

Unexpected state

{stateName ? `The system is in an unexpected state (${stateName}).` : "An unexpected internal error occurred."} Please restart the investigation to continue.

{onRetry && ( )} {onRestart && ( )}
); } function ContinueLaterBanner({ onRestart }) { return (

Your previous investigation state is still saved. You can continue where you left off or start fresh.

{onRestart && ( )}
); } // ── Shared focused-question body (extracted from OpenQuestionsPanel) ── function FocusedQuestionBody({ nodeId, isFocused, hasCompletedInvestigation: hasCompleted, focused, formulationStep, formulateMsg, processingStep, deconstructMsg, focusedAnswer, handleDeconstructSubmit, retryFormulation, setFocusedAnswer, setSelectedPresentationItemId, setFocusedPresentationItemId, setDoneForNowIds, setFollowUpQuestion, focusedContributions, currentFindings, findings, onUpdateFindingDisposition, onUpdateFindingProposition, }) { const hasContent = focused?.question?.trim() || formulationStep === "active" || processingStep === "active" || focused?.error; const hasResult = Boolean(focused?.result); const hasAnswer = Boolean(focused?.answer); // ── Local correction state (FQB-owned, not propagated upward) ─ const [editingFindingId, setEditingFindingId] = useState(null); const [draft, setDraft] = useState(""); function startEditing(id, proposition) { setEditingFindingId(id); setDraft(proposition ?? ""); } function cancelEditing() { setEditingFindingId(null); setDraft(""); } function saveEditing() { const trimmed = (draft ?? "").trim(); if (!trimmed || !editingFindingId) { cancelEditing(); return; } onUpdateFindingProposition?.(editingFindingId, trimmed); cancelEditing(); } return ( <> {isFocused && hasContent && (
{hasAnswer && focused?.question?.trim() ? (
{/* Previously answered question */}

Previously answered

{focused.question}

{/* User's verbatim response — distinct provenance from Engine-derived content */}

Your response

{focused.answer}

) : focused?.question?.trim() ? (

Question

{focused.question}

) : formulationStep === "active" ? (

{formulateMsg}

) : null} {focused?.question?.trim() && processingStep !== "active" && focused.status === "formulated" && !hasAnswer && (