import { useState, useRef, useEffect } from 'react'; import { Send, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { ChatMessage } from './ChatMessage'; import { sendChat } from '@/services/rag'; import type { ChatMessage as ChatMessageType } from '@/types/rag'; import { useToast } from '@/hooks/useToast'; import { APIException } from '@/services/api'; interface ChatPanelProps { onNavigateToNote: (path: string) => void; onNotesChanged?: () => void; } export function ChatPanel({ onNavigateToNote, onNotesChanged }: ChatPanelProps) { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const scrollRef = useRef(null); const toast = useToast(); // Auto-scroll to bottom useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [messages]); const handleSubmit = async () => { if (!input.trim() || isLoading) return; const userMsg: ChatMessageType = { role: 'user', content: input.trim(), timestamp: new Date().toISOString() }; // Construct new history immediately const newHistory = [...messages, userMsg]; // Optimistically update UI setMessages(newHistory); setInput(''); setIsLoading(true); try { const response = await sendChat({ messages: newHistory }); const assistantMsg: ChatMessageType = { role: 'assistant', content: response.answer, timestamp: new Date().toISOString(), sources: response.sources, notes_written: response.notes_written }; setMessages(prev => [...prev, assistantMsg]); // Trigger refresh if notes were created/updated if (response.notes_written && response.notes_written.length > 0) { console.log('[ChatPanel] Notes written:', response.notes_written); if (onNotesChanged) { console.log('[ChatPanel] Calling onNotesChanged()'); await onNotesChanged(); console.log('[ChatPanel] onNotesChanged() completed'); } else { console.error('[ChatPanel] onNotesChanged is undefined!'); } } else { console.log('[ChatPanel] No notes written, skipping refresh'); } } catch (err) { console.error("Chat error:", err); let errorMessage = "Failed to get response from agent"; if (err instanceof APIException) { errorMessage = err.message || err.error; } else if (err instanceof Error) { errorMessage = err.message; } toast.error(errorMessage); } finally { setIsLoading(false); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(); } }; return (
{/* Header */}

Gemini Planning Agent

Ask questions about your vault

{/* Message List */}
{messages.length === 0 ? (

👋 Hi! I can help you navigate this vault.

Try asking: "How does authentication work?"

) : (
{messages.map((msg, i) => ( ))} {isLoading && (
Thinking...
)}
)}
{/* Input Area */}