import { useEffect, useState } from 'react'; import Drawer from '@mui/material/Drawer'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; import Chip from '@mui/material/Chip'; import Divider from '@mui/material/Divider'; import LinearProgress from '@mui/material/LinearProgress'; import CircularProgress from '@mui/material/CircularProgress'; import Alert from '@mui/material/Alert'; import IconButton from '@mui/material/IconButton'; import { Sparkles, X } from 'lucide-react'; import type { CopilotExplainRequest, CopilotExplainResponse } from '../../types/labeleval'; import { copilotExplain } from '../../services/labeleval'; export default function CopilotDrawer({ open, onClose, request, }: { open: boolean; onClose: () => void; request: CopilotExplainRequest | null; }) { const [result, setResult] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { // Reset when a new context arrives. setResult(null); setError(null); }, [request]); const analyze = async () => { if (!request) return; setLoading(true); setError(null); try { const res = await copilotExplain(request); setResult(res); } catch (err) { // A 503 may still carry an offline-deterministic analysis in its body. const message = err instanceof Error ? err.message : String(err); const jsonStart = message.indexOf('{'); if (jsonStart >= 0) { try { const body = JSON.parse(message.slice(jsonStart)) as Partial; if (typeof body.analysis === 'string' && body.analysis) { setResult({ status: body.status ?? 'offline', provider: body.provider ?? 'offline_deterministic', analysis: body.analysis, structured: body.structured ?? null, }); setLoading(false); return; } } catch { /* body was not JSON */ } } setError(`Copilot unavailable: ${message}`); } finally { setLoading(false); } }; const structured = result?.structured ?? null; return ( Copilot Advisory only — the Copilot never changes metrics or overrides gates. {request ? ( CONTEXT {request.annotation_id ? : null} {request.event_id ? : null} {request.model_version ? : null} ) : ( No context selected. )} {error ? ( {error} The Copilot service may be offline — evidence and gate results above remain authoritative. ) : null} {result ? ( Provider: {result.provider} · Status: {result.status} {structured ? ( <> FAILURE CLASSIFICATION {structured.failure_classification} OBSERVED EVIDENCE
    {structured.observed_evidence.map((e, i) => (
  • {e}
  • ))}
LIKELY CAUSE {structured.likely_cause} {structured.contributing_factors.length > 0 ? ( CONTRIBUTING FACTORS
    {structured.contributing_factors.map((f, i) => (
  • {f}
  • ))}
) : null} Hypothesis — not a conclusion {structured.hypothesis} {structured.recommended_investigation.length > 0 ? ( RECOMMENDED INVESTIGATION
    {structured.recommended_investigation.map((r, i) => (
  • {r}
  • ))}
) : null} CONFIDENCE {(structured.confidence * 100).toFixed(0)}% ) : null} {result.analysis ? ( ANALYSIS {result.analysis} ) : null}
) : null}
); }