"use client"; import { useState } from "react"; import { Bot, Check, ChevronDown, Clipboard, MessageSquare, Sparkles, UserRound, } from "lucide-react"; import { ToolCallBlock } from "@/components/claude/ToolCallBlock"; import { type SessionMessage } from "@/lib/api/claude-code"; import { formatTimestamp } from "@/lib/formatters"; import { cn } from "@/lib/utils"; type SessionMessageThreadProps = { messages: SessionMessage[]; }; async function copyText(value: string, onCopied: () => void) { if (!value || typeof navigator === "undefined" || !navigator.clipboard) return; await navigator.clipboard.writeText(value); onCopied(); } function messageText(message: SessionMessage) { return message.text_blocks.map((block) => block.text).join("\n\n"); } function tokenTotal(message: SessionMessage) { if (!message.tokens) return null; return ( message.tokens.input + message.tokens.output + message.tokens.cache_read + message.tokens.cache_write ); } export function SessionMessageThread({ messages }: SessionMessageThreadProps) { const [openThinking, setOpenThinking] = useState>({}); const [copiedId, setCopiedId] = useState(null); const markCopied = (id: string) => { setCopiedId(id); window.setTimeout(() => setCopiedId(null), 1400); }; if (messages.length === 0) { return (

No conversation messages

This session was found, but there are no displayable user or assistant turns in the selected page.

); } return (
{messages.map((message, index) => { const isAssistant = message.role === "assistant"; const text = messageText(message); const thinkingOpen = openThinking[message.uuid] ?? false; const tokens = tokenTotal(message); return (
{isAssistant ? ( ) : ( )}

{isAssistant ? "Assistant" : "User"}

#{index + 1} {message.model ? ( {message.model} ) : null}

{formatTimestamp(message.timestamp)} {tokens !== null ? ` ยท ${tokens.toLocaleString()} tokens` : ""}

{text ? ( ) : null}
{message.thinking_blocks.length > 0 ? (
{thinkingOpen ? (
{message.thinking_blocks.map((block, blockIndex) => (

{block.text} {block.truncated ? " [truncated]" : ""}

))}
) : null}
) : null} {message.text_blocks.map((block, blockIndex) => (
{block.text} {block.truncated ? ( truncated ) : null}
))} {message.tool_uses.length > 0 ? (
{message.tool_uses.map((tool) => ( ))}
) : null}
); })}
); }