/** * JARVIS — StreamingMessageFeed * Drop-in replacement for MessageFeed that shows streaming tokens in real-time. * Uses useStreamingChat (WebSocket) with REST fallback. * * Replace with in ChatPage.jsx * to enable live token streaming. */ import React, { useEffect, useRef, useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Bot, User, Mic, Image, Wrench, Brain, Zap } from 'lucide-react' import clsx from 'clsx' import useAppStore from '../../stores/appStore' import MessageBubble from './MessageBubble' import { useStreamingChat } from '../../hooks/useStreamingChat' export default function StreamingMessageFeed() { const { getActiveMessages, activeSessionId, isLoading } = useAppStore() const messages = getActiveMessages() const bottomRef = useRef(null) // WebSocket streaming state const { sendMessage: wsSend, isStreaming, currentTokens, toolEvents, error: wsError, } = useStreamingChat(activeSessionId) // Auto-scroll useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages.length, currentTokens, isLoading]) if (messages.length === 0 && !isStreaming) { return } return (
{messages.map((msg) => ( ))} {/* Live streaming bubble */} {(isStreaming || isLoading) && ( )}
) } // ── Message row (reused from MessageFeed) ────────────────────── function MessageRow({ message, isUser }) { if (message.content === '__typing__') return return (
{message.used_tools?.length > 0 && (
{message.used_tools.map((tool) => ( ))}
)}
) } // ── Live streaming bubble ────────────────────────────────────── function StreamingBubble({ tokens, toolEvents, isLoading }) { return (
{/* Tool use events */} {toolEvents.map((evt, i) => ( {evt} ))} {/* Token stream or typing indicator */}
{isLoading ? ( ) : tokens && tokens !== '...' ? (
{tokens}
) : (
Reasoning…
)}
) } // ── Sub-components ───────────────────────────────────────────── function Avatar({ isUser, modality }) { const Icon = isUser ? User : Bot return (
) } function ToolBadge({ name }) { return ( {name} ) } function TypingDots() { return (
) } function TypingBubble() { return (
) } function StreamingEmptyState() { return (

JARVIS ONLINE

Multi-modal AI assistant with real-time streaming. Speak, upload, or type.

{[ { icon: '💬', label: 'Text Chat', hint: 'Streaming responses' }, { icon: '🖼️', label: 'Vision', hint: 'BLIP + CLIP analysis' }, { icon: '🎤', label: 'Voice', hint: 'Whisper + TTS' }, ].map(({ icon, label, hint }) => (
{icon}

{label}

{hint}

))}
) }