import { AlertTriangle, Archive, CheckSquare, MessageSquare, Plus, Square, Terminal } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import type { AgentInfo } from "sandbox-agent"; import { formatShortId } from "../../utils/format"; type AgentModeInfo = { id: string; name: string; description: string }; type AgentModelInfo = { id: string; name?: string }; import SessionCreateMenu, { type SessionConfig } from "../SessionCreateMenu"; import ChatInput from "./ChatInput"; import ChatMessages from "./ChatMessages"; import type { TimelineEntry } from "./types"; const ChatPanel = ({ sessionId, transcriptEntries, sessionError, message, onMessageChange, onSendMessage, onKeyDown, onCreateSession, onSelectAgent, agents, agentsLoading, agentsError, messagesEndRef, agentLabel, modelLabel, currentAgentVersion, sessionEnded, sessionArchived, onEndSession, onArchiveSession, onUnarchiveSession, modesByAgent, modelsByAgent, defaultModelByAgent, onEventClick, isThinking, agentId, tokenUsage, }: { sessionId: string; transcriptEntries: TimelineEntry[]; sessionError: string | null; message: string; onMessageChange: (value: string) => void; onSendMessage: () => void; onKeyDown: (event: React.KeyboardEvent) => void; onCreateSession: (agentId: string, config: SessionConfig) => Promise; onSelectAgent: (agentId: string) => Promise; agents: AgentInfo[]; agentsLoading: boolean; agentsError: string | null; messagesEndRef: React.RefObject; agentLabel: string; modelLabel?: string | null; currentAgentVersion?: string | null; sessionEnded: boolean; sessionArchived: boolean; onEndSession: () => void; onArchiveSession: () => void; onUnarchiveSession: () => void; modesByAgent: Record; modelsByAgent: Record; defaultModelByAgent: Record; onEventClick?: (eventId: string) => void; isThinking?: boolean; agentId?: string; tokenUsage?: { used: number; size: number; cost?: number } | null; }) => { const [showAgentMenu, setShowAgentMenu] = useState(false); const [copiedSessionId, setCopiedSessionId] = useState(false); const menuRef = useRef(null); useEffect(() => { if (!showAgentMenu) return; const handler = (event: MouseEvent) => { if (!menuRef.current) return; if (!menuRef.current.contains(event.target as Node)) { setShowAgentMenu(false); } }; document.addEventListener("mousedown", handler); return () => document.removeEventListener("mousedown", handler); }, [showAgentMenu]); const copySessionId = async () => { if (!sessionId) return; const onSuccess = () => { setCopiedSessionId(true); window.setTimeout(() => setCopiedSessionId(false), 1200); }; try { if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(sessionId); onSuccess(); return; } } catch { // Fallback below for older/insecure contexts. } const textarea = document.createElement("textarea"); textarea.value = sessionId; textarea.style.position = "fixed"; textarea.style.opacity = "0"; document.body.appendChild(textarea); textarea.select(); try { document.execCommand("copy"); onSuccess(); } finally { document.body.removeChild(textarea); } }; const handleArchiveSession = () => { if (!sessionId) return; onArchiveSession(); }; const handleUnarchiveSession = () => { if (!sessionId) return; onUnarchiveSession(); }; return (
{sessionId ? agentLabel : "No Session"} {sessionId && modelLabel && ( {modelLabel} )} {sessionId && currentAgentVersion && ( v{currentAgentVersion} )} {sessionId && ( )}
{sessionId && tokenUsage && ( {tokenUsage.used.toLocaleString()} tokens )} {sessionId && ( sessionEnded ? ( <> Ended ) : ( ) )}
{sessionError && (
{sessionError}
)}
{!sessionId ? (
No Session Selected

Create a new session to start chatting with an agent.

setShowAgentMenu(false)} />
) : transcriptEntries.length === 0 && !sessionError ? (
Ready to Chat

Send a message to start a conversation with the agent.

) : ( )}
); }; export default ChatPanel;