"use client"; import { useState } from "react"; import type { EvidenceItem } from "@/lib/types"; function ToolBadge({ name }: { name: string }) { const map: Record = { run_sql: "bg-blue-900/60 text-blue-200 border-blue-700/60", inspect_schema: "bg-violet-900/60 text-violet-200 border-violet-600/60", compare_periods: "bg-emerald-900/60 text-emerald-200 border-emerald-700/60", decompose_metric: "bg-orange-900/60 text-orange-200 border-orange-700/60", }; return ( {name} ); } function DurationBadge({ ms }: { ms: number | null }) { if (ms === null) return null; return ( {ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`} ); } function ArgValue({ label, value }: { label: string; value: unknown }) { if (typeof value === "string") { const isLong = value.length > 60 || value.includes("\n"); return (
{label}: {isLong ? (
            {value}
          
) : ( {value} )}
); } if (value === null || value === undefined) return null; return (
{label}: {JSON.stringify(value)}
); } function OutputPreview({ toolName, output, }: { toolName: string; output: Record; }) { if (output.error) return null; if (toolName === "run_sql") { const rows = output.rows as Record[] | undefined; const count = (output.row_count as number) ?? rows?.length ?? 0; if (!rows || rows.length === 0) return

{count} rows returned

; const cols = Object.keys(rows[0]); return (

{count} row{count !== 1 ? "s" : ""} {(output.truncated as boolean) ? " (truncated)" : ""}

{cols.map((c) => ( ))} {rows.slice(0, 3).map((row, i) => ( {cols.map((c) => ( ))} ))}
{c}
{String(row[c] ?? "")}
{count > 3 && (

+{count - 3} more rows

)}
); } if (toolName === "compare_periods") { const { before_value, after_value, abs_delta, pct_delta } = output as Record; if (before_value === undefined) return null; const trend = (abs_delta ?? 0) >= 0 ? "text-emerald-400" : "text-red-400"; return (
{before_value?.toFixed(4)} {after_value?.toFixed(4)} {(abs_delta ?? 0) > 0 ? "+" : ""} {abs_delta?.toFixed(4)} ( {pct_delta !== null ? `${pct_delta > 0 ? "+" : ""}${pct_delta?.toFixed(1)}%` : "n/a"} )
); } if (toolName === "decompose_metric") { const slices = output.slices as | { slice_value: string; anomaly_score: number }[] | undefined; if (!slices || slices.length === 0) return null; return (
{slices.slice(0, 3).map((s, i) => (
{i + 1}. {s.slice_value} anomaly: 0 ? "text-orange-300" : "text-blue-300"}`} > {s.anomaly_score > 0 ? "+" : ""} {s.anomaly_score?.toFixed(2)}
))} {slices.length > 3 && (

+{slices.length - 3} more

)}
); } if (toolName === "inspect_schema") { const tables = output.tables as string[] | undefined; const cols = output.columns as unknown[] | undefined; if (tables) return (

{tables.length} table{tables.length !== 1 ? "s" : ""}:{" "} {tables.join(", ")}

); if (cols) return (

{cols.length} column{cols.length !== 1 ? "s" : ""} described

); } return null; } function EvidenceRow({ item, index, isLatest, streaming, }: { item: EvidenceItem; index: number; isLatest: boolean; streaming: boolean; }) { const hasError = Boolean(item.output?.error); const [open, setOpen] = useState(false); return (
{open && (
{item.reasoning && (

Agent thought

{item.reasoning}

)}

Input

{Object.entries(item.args).map(([k, v]) => ( ))}
{!hasError && (

Result

)} {hasError && (

Error: {item.output.error}

{item.output.hint && (

Hint: {item.output.hint}

)}
)}
)}
); } export default function EvidencePanel({ evidence, streaming = false, }: { evidence: EvidenceItem[]; streaming?: boolean; }) { const [expanded, setExpanded] = useState(false); if (evidence.length === 0) return null; if (streaming) { return (
{evidence.map((e, i) => ( ))}
); } return (
{expanded && (
{evidence.map((e, i) => ( ))}
)}
); }