import React from "react"; /** * StreamingMessage — Claude-Code-on-Web parity streaming renderer. * * Renders agent messages incrementally as they arrive via WebSocket. * Shows tool use blocks (bash commands + output), explanatory text, * and status indicators. */ export default function StreamingMessage({ events }) { if (!events || events.length === 0) return null; return (
{events.map((evt, idx) => ( ))}
); } function StreamingEvent({ event, isLast }) { const { type } = event; if (type === "agent_message") { return (
{event.content} {isLast && |}
); } if (type === "tool_use") { return (
{event.tool || "terminal"}
$ {event.input}
); } if (type === "tool_result") { return (
{event.output}
); } if (type === "status_change") { const statusLabels = { active: "Working...", waiting: "Waiting for input", completed: "Completed", failed: "Failed", }; return (
{statusLabels[event.status] || event.status}
); } if (type === "diff_update") { return null; // Handled by DiffStats in parent } if (type === "error") { return (
{event.message}
); } return null; } const styles = { container: { display: "flex", flexDirection: "column", gap: 4, }, textBlock: { fontSize: 14, lineHeight: 1.6, color: "#D4D4D8", whiteSpace: "pre-wrap", wordBreak: "break-word", }, cursor: { display: "inline-block", animation: "blink 1s step-end infinite", color: "#3B82F6", fontWeight: 700, }, toolBlock: { margin: "4px 0", borderRadius: 6, border: "1px solid #27272A", overflow: "hidden", }, toolHeader: { display: "flex", alignItems: "center", gap: 6, padding: "6px 10px", backgroundColor: "#18181B", fontSize: 11, color: "#71717A", fontFamily: "monospace", }, toolName: { fontWeight: 600, }, toolInput: { padding: "8px 10px", backgroundColor: "#0D0D0F", fontFamily: "monospace", fontSize: 12, color: "#10B981", whiteSpace: "pre-wrap", wordBreak: "break-all", }, toolOutput: { padding: "8px 10px", backgroundColor: "#0D0D0F", maxHeight: 300, overflowY: "auto", }, toolOutputPre: { margin: 0, fontFamily: "monospace", fontSize: 11, color: "#A1A1AA", whiteSpace: "pre-wrap", wordBreak: "break-all", }, statusLine: { display: "flex", alignItems: "center", gap: 6, padding: "4px 0", fontSize: 12, color: "#71717A", fontStyle: "italic", }, statusDot: { width: 6, height: 6, borderRadius: "50%", }, errorBlock: { padding: "8px 12px", borderRadius: 6, backgroundColor: "rgba(239, 68, 68, 0.08)", border: "1px solid rgba(239, 68, 68, 0.2)", color: "#FCA5A5", fontSize: 13, }, };