Skip to main content
The Terminal component provides a live view of agent activity through WebSocket-based log streaming. It displays color-coded logs with timestamps, allowing you to monitor the agent’s decisions and actions in real-time.

Overview

The terminal interface streams logs directly from the backend using WebSocket connections, providing instant feedback on:
  • Service monitoring events
  • Diagnostic findings
  • Execution commands
  • Error messages
  • System notifications

Real-time Updates

WebSocket connection delivers logs with sub-second latency

Auto-scrolling

Terminal automatically scrolls to the latest log entry

Color-coded Logs

Different log types use distinct colors for easy scanning

500 Log Buffer

Keeps the last 500 logs in memory to prevent overflow

WebSocket Connection

The terminal uses a custom React hook (useLogs) to manage the WebSocket connection:
// hooks/use-logs.ts
export function useLogs() {
  const [logs, setLogs] = useState<LogEntry[]>([]);
  const [isConnected, setIsConnected] = useState(false);
  const ws = useRef<WebSocket | null>(null);

  useEffect(() => {
    const connect = () => {
      // Convert HTTP URL to WebSocket URL
      const wsUrl = API_URL.replace(/^http/, 'ws') + '/ws/logs';
      const socket = new WebSocket(wsUrl);

      socket.onopen = () => {
        setIsConnected(true);
        setLogs(prev => [...prev, {
          timestamp: new Date().toISOString(),
          type: 'system',
          message: 'Connected to Sentinel AI Event Stream'
        }]);
      };

      socket.onmessage = (event) => {
        const data = JSON.parse(event.data);
        setLogs(prev => {
          const newLogs = [...prev, data];
          return newLogs.slice(-500); // Keep last 500 logs
        });
      };

      socket.onclose = () => {
        setIsConnected(false);
        setTimeout(connect, 5000); // Reconnect after 5s
      };

      ws.current = socket;
    };

    connect();
    return () => ws.current?.close();
  }, []);

  return { logs, isConnected };
}
The WebSocket connection automatically reconnects every 5 seconds if the connection is lost.

Log Entry Structure

Each log entry follows this TypeScript interface:
export interface LogEntry {
  timestamp: string;        // ISO 8601 timestamp
  type: string;            // Log type (monitor, plan, execute, etc.)
  message: string;         // Human-readable message
  details?: Record<string, unknown>; // Optional structured data
}

Backend WebSocket Handler

The FastAPI backend implements the WebSocket endpoint:
# src/api/routes.py
@router.websocket("/ws/logs")
async def websocket_logs(websocket: WebSocket):
    await websocket.accept()
    queue = await bus.subscribe()
    try:
        while True:
            data = await queue.get()
            await websocket.send_json(data)
    except WebSocketDisconnect:
        bus.unsubscribe(queue)
    except Exception as e:
        log("error", f"WebSocket error: {e}")
        bus.unsubscribe(queue)
The backend uses an event bus pattern to distribute logs to all connected WebSocket clients.
Multiple dashboard instances can connect simultaneously - each receives the same log stream.

Terminal UI Component

The Terminal component renders logs with syntax highlighting:
// components/dashboard/Terminal.tsx
export function Terminal({ logs }: TerminalProps) {
  const endRef = useRef<HTMLDivElement>(null);

  // Auto-scroll to bottom when new logs arrive
  useEffect(() => {
    endRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [logs]);

  const getLogColor = (type: string) => {
    switch (type.toLowerCase()) {
      case 'error': return 'text-red-400';
      case 'warning': return 'text-yellow-400';
      case 'success': return 'text-green-400';
      case 'monitor': return 'text-blue-300';
      case 'plan': return 'text-purple-400';
      case 'execute': return 'text-orange-400';
      case 'system': return 'text-gray-400 italic';
      default: return 'text-gray-300';
    }
  };

  return (
    <div className="rounded-lg border bg-black/40 backdrop-blur-xl">
      <div className="flex items-center px-4 py-2 border-b">
        <TerminalIcon className="w-4 h-4 mr-2" />
        <span className="text-xs">Live Agent Logs</span>
      </div>

      <div className="overflow-y-auto p-4 space-y-1 font-mono text-sm">
        {logs.map((log, i) => (
          <div key={i} className="flex gap-2">
            <span className="text-muted-foreground text-xs">
              [{new Date(log.timestamp).toLocaleTimeString()}]
            </span>
            <span className={getLogColor(log.type)}>
              <span className="font-bold mr-2 uppercase text-[10px]">
                {log.type}
              </span>
              {log.message}
            </span>
          </div>
        ))}
        <div ref={endRef} />
      </div>
    </div>
  );
}

Log Types and Colors

ERROR

Red - Critical errors requiring attention

WARNING

Yellow - Warnings and non-critical issues

SUCCESS

Green - Successful operations

MONITOR

Blue - Service monitoring events

PLAN

Purple - Planning and decision-making

EXECUTE

Orange - Command execution

SYSTEM

Gray - System notifications

Connection Status Indicator

The dashboard displays the WebSocket connection status:
// app/page.tsx
<div className="flex items-center gap-2">
  <span className={`w-2 h-2 rounded-full ${
    isConnected ? 'bg-green-500 animate-pulse' : 'bg-red-500'
  }`} />
  <span className="text-xs text-muted-foreground">
    {isConnected ? 'Real-time via WebSocket' : 'Connecting...'}
  </span>
</div>
If the connection status shows “Connecting…” for more than 10 seconds, check that the backend server is running and accessible.

Example Log Stream

Here’s what a typical log stream looks like:
[14:23:45] SYSTEM     Connected to Sentinel AI Event Stream
[14:23:46] MONITOR    Checking service status for nginx
[14:23:47] MONITOR    Checking service status for postgresql
[14:23:48] SUCCESS    All services healthy
[14:25:12] MONITOR    Service 'nginx' detected as stopped
[14:25:13] PLAN       Analyzing failure: nginx not responding
[14:25:14] PLAN       Proposed fix: sudo systemctl restart nginx
[14:25:15] EXECUTE    Running remediation command
[14:25:16] SUCCESS    Service restored successfully

Performance Considerations

Log Buffer Management: The terminal keeps only the last 500 logs to prevent memory issues during long-running sessions.
The log buffer is managed automatically:
setLogs(prev => {
  const newLogs = [...prev, data];
  return newLogs.slice(-500); // Keep last 500
});
While the current implementation displays all logs, you can filter by log type:
const filteredLogs = logs.filter(log => 
  log.type.toLowerCase() === 'error'
);
For advanced filtering, consider implementing a search bar that filters logs by type, message content, or time range.

Next Steps

Action History

View filtered high-level actions instead of raw logs

Chat Interface

Ask questions about logs using natural language

WebSocket API

Learn about the backend event distribution system

Build docs developers (and LLMs) love