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 (
);
}
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,
},
};