import { useCallback, useState } from "react"; import { AgentAction } from "../components/AgentAction"; import { ChatInput } from "../components/ChatInput"; import { ChatMessages } from "../components/ChatMessages"; import { InterruptPrompt } from "../components/InterruptPrompt"; import { useWebSocket } from "../hooks/useWebSocket"; import type { ChatMessage, ConnectionStatus, InterruptMessage, ServerMessage, ToolAction, } from "../types"; let msgCounter = 0; function nextId(): string { msgCounter += 1; return `msg-${msgCounter}`; } export function ChatPage() { const [messages, setMessages] = useState([]); const [toolActions, setToolActions] = useState([]); const [currentInterrupt, setCurrentInterrupt] = useState(null); const [isWaiting, setIsWaiting] = useState(false); const handleServerMessage = useCallback((msg: ServerMessage) => { switch (msg.type) { case "token": { setMessages((prev) => { const last = prev[prev.length - 1]; if (last && last.sender === "agent" && last.isStreaming) { return [ ...prev.slice(0, -1), { ...last, content: last.content + msg.content }, ]; } return [ ...prev, { id: nextId(), sender: "agent", agent: msg.agent, content: msg.content, timestamp: Date.now(), isStreaming: true, }, ]; }); break; } case "tool_call": { setToolActions((prev) => [ ...prev, { id: nextId(), agent: msg.agent, tool: msg.tool, args: msg.args, timestamp: Date.now(), }, ]); break; } case "interrupt": { setCurrentInterrupt(msg); setIsWaiting(false); break; } case "message_complete": { setMessages((prev) => { const last = prev[prev.length - 1]; if (last && last.isStreaming) { return [...prev.slice(0, -1), { ...last, isStreaming: false }]; } return prev; }); setIsWaiting(false); break; } case "error": { setMessages((prev) => [ ...prev, { id: nextId(), sender: "agent", agent: "System", content: `Error: ${msg.message}`, timestamp: Date.now(), }, ]); setIsWaiting(false); break; } } }, []); const { status, sendMessage, sendInterruptResponse } = useWebSocket(handleServerMessage); const handleSend = useCallback( (content: string) => { setMessages((prev) => [ ...prev, { id: nextId(), sender: "user", content, timestamp: Date.now(), }, ]); setIsWaiting(true); sendMessage(content); }, [sendMessage] ); const handleInterruptResponse = useCallback( (approved: boolean) => { sendInterruptResponse(approved); setCurrentInterrupt(null); setIsWaiting(true); }, [sendInterruptResponse] ); return (

Smart Support

{toolActions.length > 0 && (
{toolActions.slice(-3).map((action) => ( ))}
)} {currentInterrupt && ( )}
); } function StatusIndicator({ status }: { status: ConnectionStatus }) { const colors: Record = { connected: "#4caf50", connecting: "#ff9800", disconnected: "#f44336", }; return (
{status}
); } const styles: Record = { page: { height: "100vh", display: "flex", flexDirection: "column", background: "white", maxWidth: "800px", margin: "0 auto", boxShadow: "0 0 20px rgba(0,0,0,0.1)", }, header: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 16px", borderBottom: "1px solid #e0e0e0", }, title: { fontSize: "18px", fontWeight: 700, margin: 0, color: "#333", }, actionsBar: { borderTop: "1px solid #eee", paddingTop: "4px", }, };