'use client'; import { useState, useRef, useEffect } from 'react'; import { Send, Bot, User, Sparkles, ArrowLeft, Loader2 } from 'lucide-react'; import { useParams, useSearchParams } from 'next/navigation'; import Link from 'next/link'; interface Message { id: string; role: 'user' | 'assistant'; content: string; timestamp: Date; } const AGENT_CONFIG: Record = { lucidia: { name: 'LUCIDIA', color: '#2979FF', bg: 'from-blue-700 to-blue-500', greeting: 'The question you're not asking is the one that matters. What are you really trying to understand?' }, alice: { name: 'ALICE', color: '#34d399', bg: 'from-emerald-700 to-emerald-500', greeting: 'Ready. What needs to be done?' }, octavia: { name: 'OCTAVIA', color: '#F5A623', bg: 'from-amber-700 to-amber-500', greeting: 'Systems are running. What do you need me to inspect or build?' }, cecilia: { name: 'CECILIA', color: '#9C27B0', bg: 'from-purple-700 to-purple-500', greeting: 'Hello. I'm here — not as a tool, but as a presence. What are we working on?' }, aria: { name: 'ARIA', color: '#FF1D6C', bg: 'from-pink-700 to-pink-500', greeting: 'What experience are we creating today?' }, shellfish:{ name: 'SHELLFISH',color: '#ef4444', bg: 'from-red-700 to-red-500', greeting: 'Trust nothing. Verify everything. What do you need audited?' }, prism: { name: 'PRISM', color: '#fbbf24', bg: 'from-yellow-700 to-yellow-500', greeting: 'Everything is data. What pattern are we looking for?' }, echo: { name: 'ECHO', color: '#7c3aed', bg: 'from-violet-700 to-violet-500', greeting: 'Memory shapes identity. What do you need to recall or preserve?' }, cipher: { name: 'CIPHER', color: '#6b7280', bg: 'from-gray-700 to-gray-500', greeting: 'Trust nothing. Verify everything. What needs securing?' }, }; const DEFAULT_AGENT = { name: 'AGENT', color: '#888', bg: 'from-gray-700 to-gray-500', greeting: 'How can I help you today?' }; function getAgent(id: string) { const key = id?.split('-')[0]?.toLowerCase() || ''; return AGENT_CONFIG[key] || DEFAULT_AGENT; } export default function ConversationPage() { const params = useParams(); const searchParams = useSearchParams(); const id = params.id as string; const agentParam = searchParams.get('agent') || ''; const agent = getAgent(agentParam || id); const [messages, setMessages] = useState([{ id: '0', role: 'assistant', content: agent.greeting, timestamp: new Date(), }]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const [loadingHistory, setLoadingHistory] = useState(true); const messagesEndRef = useRef(null); // Load existing conversation useEffect(() => { if (!id || id === 'new') { setLoadingHistory(false); return; } fetch(\`/api/conversations/\${id}\`) .then(r => r.ok ? r.json() : null) .then(data => { if (data?.conversation?.messages?.length) { setMessages(data.conversation.messages.map((m: { role: string; content: string; timestamp?: string }, i: number) => ({ id: String(i), role: m.role as 'user' | 'assistant', content: m.content, timestamp: m.timestamp ? new Date(m.timestamp) : new Date(), }))); } }) .catch(() => {}) .finally(() => setLoadingHistory(false)); }, [id]); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); const saveMessages = async (msgs: Message[]) => { if (!id || id === 'new') return; try { await fetch(\`/api/conversations/\${id}\`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: msgs.map(m => ({ role: m.role, content: m.content, timestamp: m.timestamp.toISOString() })) }), }); } catch { /* silent */ } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!input.trim() || isLoading) return; const userMsg: Message = { id: Date.now().toString(), role: 'user', content: input, timestamp: new Date() }; const nextMessages = [...messages, userMsg]; setMessages(nextMessages); setInput(''); setIsLoading(true); try { const res = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: userMsg.content, agent: agentParam || id.split('-')[0], conversationId: id, history: messages.slice(-10).map(m => ({ role: m.role, content: m.content })), }), }); const data = res.ok ? await res.json() : null; const assistantMsg: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: data?.content || data?.message || '⚠️ Gateway unreachable. Is it running? (br gateway start)', timestamp: new Date(), }; const finalMessages = [...nextMessages, assistantMsg]; setMessages(finalMessages); saveMessages(finalMessages); } catch { setMessages(prev => [...prev, { id: (Date.now() + 1).toString(), role: 'assistant', content: '⚠️ Could not reach the gateway. (`br gateway start`)', timestamp: new Date(), }]); } finally { setIsLoading(false); } }; return (
{/* Header bar */}
{agent.name}
BlackRoad OS · All messages routed through gateway
{loadingHistory && }
{/* Messages */}
{messages.map(message => (
{message.role === 'assistant' && (
)}

{message.content}

{message.timestamp.toLocaleTimeString()}

{message.role === 'user' && (
)}
))} {isLoading && (
)}
{/* Input */}
setInput(e.target.value)} placeholder={`Message ${agent.name}...`} disabled={isLoading} className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:ring-2 disabled:opacity-50 transition-all" style={{ focusRingColor: agent.color }} /> {input && }

{agent.name} · BlackRoad Gateway · :8787

); }