"use client"; import { useEffect, useState } from "react"; import { Send, Sparkles } from "lucide-react"; type ChatMessage = { role: "user" | "assistant"; content: string }; const SUGGESTIONS = [ "Why is the LLM stage tiered B instead of A?", "Walk me through the End-of-Speech Pop risk on Avatar.", "What would it take to fix the Failure 3 cascade?", ]; export default function ExpertChat({ selectedNodeId, seedQuestion, onSeedConsumed, }: { selectedNodeId: string | null; seedQuestion?: string | null; onSeedConsumed?: () => void; }) { const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); async function send(text?: string) { const content = (text ?? input).trim(); if (!content || loading) return; const next = [...messages, { role: "user" as const, content }]; setMessages(next); setInput(""); setLoading(true); setError(null); try { const res = await fetch("/api/expert", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: next, selectedNodeId }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Request failed"); setMessages([...next, { role: "assistant", content: data.text }]); } catch (err) { setError(err instanceof Error ? err.message : "Something went wrong."); } finally { setLoading(false); } } useEffect(() => { if (!seedQuestion) return; send(seedQuestion); onSeedConsumed?.(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [seedQuestion]); return (
{messages.length === 0 && (
Samantha audits this pipeline against 5 failure modes: Uncanny Valley, End-of-Speech Pop, Cascaded Latency, VRAM Death, and the VASA-1 Problem.
{SUGGESTIONS.map((s) => ( ))}
)} {messages.map((m, i) => (
{m.content}
))} {loading && (
Thinking…
)} {error && (
{error}
)}
setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} placeholder="Ask Samantha…" className="flex-1 bg-transparent outline-none text-sm placeholder:text-[var(--muted)]" />
); }