import * as React from 'react'; import { cn } from '@/lib/utils'; /** * Renders the light markup the capabilities emit — `**bold**`, bullets, * numbered items, `_asides_`, and ✓/⚠ check lines. * * A full markdown renderer is available in the project, but this content is * produced locally in a known shape, and parsing five constructs keeps the * assistant's typography inside the design system rather than inheriting a * library's defaults. */ const BOLD = /\*\*(.+?)\*\*/g; function inline(line, keyPrefix) { const parts = []; let last = 0; let match; BOLD.lastIndex = 0; while ((match = BOLD.exec(line)) !== null) { if (match.index > last) parts.push(line.slice(last, match.index)); parts.push( {match[1]} ); last = match.index + match[0].length; } if (last < line.length) parts.push(line.slice(last)); return parts.length ? parts : line; } export function RichText({ text, className }) { const lines = React.useMemo(() => String(text).split('\n'), [text]); return (
{lines.map((line, i) => { if (!line.trim()) return ); } /** The three-dot indicator shown before the first delta arrives. */ export function ThinkingIndicator() { return (
{[0, 1, 2].map((i) => ( ))} Assistant is thinking
); } /** * One turn in the conversation. The user's own words sit in a filled bubble; the * assistant's answer runs full width, because these answers are structured * multi-paragraph reports and a chat bubble would waste a third of a 380px * column on padding. */ export function Message({ role, text, streaming, stopped }) { if (role === 'user') { return (
{text}
); } return (
{streaming && (
); }