'use client' import { useState, useCallback, useRef, useEffect } from 'react' import { useThread } from '@standardagents/react' import { MessageList } from './MessageList' import { MessageInput } from './MessageInput' import { type Thread, getThreadTitle } from '../hooks/useThreads' interface ChatProps { thread?: Thread onUpdateTitle?: (title: string) => void /** Called when the pushed run state changes, so the thread list can refresh. */ onRunStateChange?: () => void sidebarOpen?: boolean } export function Chat({ thread, onUpdateTitle, onRunStateChange, sidebarOpen = true }: ChatProps) { const { status, runStatus } = useThread() const runState = runStatus?.state const lastRunState = useRef(runState) // Event-driven sidebar refresh: one read per run-state transition. useEffect(() => { if (lastRunState.current !== undefined && runState !== lastRunState.current) { onRunStateChange?.() } lastRunState.current = runState }, [runState, onRunStateChange]) const [isEditingTitle, setIsEditingTitle] = useState(false) const [titleValue, setTitleValue] = useState('') const inputRef = useRef(null) const agentName = thread?.agent?.title || thread?.agent?.name || 'Agent' const threadTitle = thread ? getThreadTitle(thread) : 'Untitled' // Focus input when entering edit mode useEffect(() => { if (isEditingTitle && inputRef.current) { inputRef.current.focus() inputRef.current.select() } }, [isEditingTitle]) const handleStartEdit = useCallback(() => { const currentTitle = thread ? getThreadTitle(thread) : '' setTitleValue(currentTitle === 'Untitled' ? '' : currentTitle) setIsEditingTitle(true) }, [thread]) const handleSaveTitle = useCallback(() => { const trimmed = titleValue.trim() if (trimmed && onUpdateTitle) { onUpdateTitle(trimmed) } setIsEditingTitle(false) }, [titleValue, onUpdateTitle]) const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter') { handleSaveTitle() } else if (e.key === 'Escape') { setIsEditingTitle(false) } }, [handleSaveTitle]) // Connection status LED color const ledColor = status === 'connected' ? 'bg-emerald-500' : status === 'connecting' || status === 'reconnecting' ? 'bg-yellow-500 animate-pulse' : 'bg-red-500' return (
{/* Header bar - frosted glass effect, fixed on scroll */}
{/* Editable title on the left */}
{isEditingTitle ? ( setTitleValue(e.target.value)} onBlur={handleSaveTitle} onKeyDown={handleKeyDown} className="text-sm font-medium text-[var(--text-primary)] bg-transparent outline-none w-full max-w-xs" placeholder="Enter title..." /> ) : ( <> {threadTitle} )}
{/* Agent name and connection status on the right */}
{runState === 'running' && ( Running )} {agentName}
{/* Opaque blocker behind input - covers bottom half of input area down */}
) }