Files
confidence-engine/components/scenario-form.jsx
T
robbond d72c7c5465 chore: establish clean v0.2 baseline
Include only the working reconstruction prototype with Ollama integration:
- double-wrapping fix (lib/llm/provider.js)
- explicit v0.2 JSON output schema (prompts/reconstruct-v0.2.md)
- Zod validation layer (lib/reconstruction/schema.js)
- shared core analysis path (lib/analysis.js)
- prompt versioning infrastructure (lib/reconstruction/prompt.js)
- provider abstraction
- functioning Ollama provider path
- updated API route with centralized analysis
- UI components displaying v0.2 data and validation errors
- .gitignore rules for generated evaluation artifacts

Exclude: evaluator experiments, diagnostic tests, debug scripts,
generated artifacts, comparison findings, test data tied to evaluator.
2026-08-01 14:45:06 +01:00

136 lines
4.7 KiB
React

"use client";
import { useState, useRef } from "react";
import ReconstructionView from "@/components/reconstruction-view";
import DiagnosticsView from "@/components/diagnostics-view";
const MAX_LENGTH = 10000;
export default function ScenarioForm() {
const [scenario, setScenario] = useState("");
const [status, setStatus] = useState("idle"); // idle | loading | error | success | partial
const [result, setResult] = useState(null);
const textareaRef = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
setStatus("loading");
setResult(null);
try {
const res = await fetch("/api/analyse", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ scenario }),
});
const data = await res.json();
if (res.ok && data.validationStatus === "valid") {
setStatus("success");
setResult(data);
} else if (data.success) {
// Success in analysis but validation may be partial
setStatus("success");
setResult(data);
} else {
setStatus("error");
setResult(data);
}
} catch (err) {
setStatus("error");
setResult({ error: err.message || "Network request failed" });
}
};
// Determine if we have meaningful content to display
const hasClassification = result?.inputClassification;
const hasReconstruction = result?.reconstruction;
const hasNextQuestion = result?.nextQuestion;
const hasEvidence = result?.evidence && result.evidence.length > 0;
const hasMeaningfulContent =
hasClassification || hasReconstruction || hasNextQuestion || hasEvidence;
return (
<div className="space-y-6">
<form onSubmit={handleSubmit} className="space-y-4">
<textarea
ref={textareaRef}
value={scenario}
onChange={(e) => setScenario(e.target.value)}
placeholder="Describe the scenario you want analysed..."
rows={10}
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-gray-500 focus:outline-none focus:ring-2 focus:ring-gray-400"
/>
<div className="flex items-center justify-between">
<span className="text-xs text-gray-400">
{scenario.length}/{MAX_LENGTH}
</span>
<button
type="submit"
disabled={status === "loading" || !scenario.trim()}
className="rounded-lg bg-gray-900 px-6 py-2.5 text-sm font-medium text-white transition hover:bg-gray-700 disabled:cursor-not-allowed disabled:opacity-40"
>
{status === "loading" ? "Analysing..." : "Analyse"}
</button>
</div>
</form>
{/* Error state */}
{status === "error" && (
<div className="space-y-3">
{result?.error && (
<div className="rounded-lg border border-red-300 bg-red-50 px-4 py-3 text-sm text-red-700 whitespace-pre-wrap">
Error: {result.error}
</div>
)}
{/* Show partial content even on validation failure */}
{(hasClassification || hasReconstruction) && (
<div className="rounded-lg border border-yellow-300 bg-yellow-50 px-4 py-2 text-sm text-yellow-800">
Partial result some fields failed validation. Showing what was
accepted.
</div>
)}
{hasReconstruction && (
<ReconstructionView reconstruction={result} partial />
)}
</div>
)}
{/* Success state */}
{status === "success" && hasMeaningfulContent && (
<div className="space-y-4">
<ReconstructionView reconstruction={result} />
</div>
)}
{/* Always show diagnostics when we have any result */}
{(hasClassification || hasReconstruction || hasNextQuestion) && (
<DiagnosticsView result={result} />
)}
{status === "loading" && (
<div className="py-12 text-center text-sm text-gray-400">
Waiting for model response...
</div>
)}
{/* Empty state */}
{status === "idle" && (
<div className="rounded-lg border border-dashed border-gray-300 bg-gray-50 px-6 py-8 text-center">
<p className="text-sm text-gray-400">
Enter a scenario above and click Analyse to begin.
</p>
</div>
)}
{/* Invalid result with no partial data */}
{status === "error" && !result?.error && !hasMeaningfulContent && (
<div className="rounded-lg border border-yellow-300 bg-yellow-50 px-4 py-2 text-sm text-yellow-800">
Validation failed no structured output was produced.
</div>
)}
</div>
);
}