import { AlertTriangle, CheckCircle2, CircleHelp, ShieldX } from "lucide-react"; import type { AskResult } from "../../../pipeline/types"; import { cn } from "../lib/utils"; import { Badge } from "./ui/badge"; export type AskVerification = NonNullable; interface AskVerificationPanelProps { navigate: (to: string) => void; verification: AskVerification; } const STATUS_PRESENTATION = { supported: { label: "supported", icon: CheckCircle2, className: "border-emerald-500/30 bg-emerald-500/10 text-emerald-300", }, contradicted: { label: "contradicted", icon: ShieldX, className: "border-destructive/40 bg-destructive/10 text-destructive", }, insufficient: { label: "insufficient", icon: AlertTriangle, className: "border-amber-500/30 bg-amber-500/10 text-amber-300", }, uncertain: { label: "uncertain", icon: CircleHelp, className: "border-sky-500/30 bg-sky-500/10 text-sky-300", }, } as const; const evidenceLabel = (uri: string, startLine: number, endLine: number) => `${uri}:L${startLine}${startLine === endLine ? "" : `-L${endLine}`}`; export function AskVerificationPanel({ navigate, verification, }: AskVerificationPanelProps) { const { claims, capsule, semantic } = verification; const degradedCapabilities = Object.entries( capsule.retrieval.capabilityStates ).filter(([, state]) => state.requested && state.outcome !== "used"); const gaps = capsule.coverage.gaps; return (
{claims.answerStatus === "verified" ? "All claims verified" : "Answer withheld"} {claims.coverage.supportedClaims}/{claims.coverage.totalClaims}{" "} supported

{claims.abstentionReason ?? `${claims.coverage.supportedRatio * 100}% support coverage`}

details
semantic: {semantic.status}/{semantic.reason} {degradedCapabilities.map(([name, state]) => ( {name}: {state.outcome} {state.fallbackReasons.length > 0 ? ` (${state.fallbackReasons.join(", ")})` : ""} ))}
{claims.coverage.supportedClaims} supported {claims.coverage.contradictedClaims} contradicted {claims.coverage.insufficientClaims} insufficient {claims.coverage.uncertainClaims} uncertain
{claims.claims.map((claim) => { const presentation = STATUS_PRESENTATION[claim.status]; const StatusIcon = presentation.icon; return (
{claim.text} {presentation.label}
{claim.evidence.length > 0 ? ( claim.evidence.map((evidence) => ( )) ) : (

No retained evidence span.

)}

{claim.rationaleCode} {claim.confidence === null ? "" : ` ยท confidence ${claim.confidence.toFixed(2)}`}

); })}
{(capsule.coverage.unresolvedFacets.length > 0 || gaps.length > 0) && (

Evidence gaps

    {capsule.coverage.unresolvedFacets.map((facet) => (
  • unresolved facet: {facet}
  • ))} {gaps.map((gap) => (
  • {gap.facet}: {gap.code}
  • ))}
)}
); }