"use client"; import { Loader2, Search } from "lucide-react"; import type { Citation } from "@/lib/api"; import { citationColor, scoreStrength, STRENGTH_META } from "@/lib/citations"; import { displaySource } from "@/lib/format"; const ROUTE_LABEL: Record = { fast: "fast retrieval", hybrid: "hybrid retrieval", graph: "graph traversal", relational: "graph traversal", }; function rgba(rgb: string, a: number): string { return rgb.replace("rgb(", "rgba(").replace(")", `,${a})`); } /** * Progressive-evidence strip shown while an answer streams (Perplexity's finding: * visible evidence assembling beats a bare spinner). Once the SSE `meta` event * arrives, retrieval is already done — so we render the real retrieved source * candidates as number-matched cards *above* the forming answer, then the final * event narrows them to the actually-cited subset. Falls back to detected-entity * chips before sources are known. */ export function StreamingEvidence({ route, entities, sources, }: { route?: string; entities: string[]; sources: Citation[]; }) { const label = route ? ROUTE_LABEL[route] ?? route.replace(/_/g, " ") : null; const hasSources = sources.length > 0; return (
{hasSources ? "Reading sources" : "Gathering evidence"} {label && ( {label} )} {!hasSources && entities.slice(0, 6).map((e) => ( {e} ))}
{hasSources && (
{sources.map((c) => { const color = citationColor(c.marker); const sm = scoreStrength(c.score); return ( {c.marker} {displaySource(c.source)} {sm && c.score != null && ( {c.score.toFixed(2)} )} ); })}
)}
); }