import React, { useCallback, useEffect, useState } from 'react' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import { IconCheck, IconCopy } from './SvgIcons' const CODE_BLOCK_MAX_LINES = 30 const CODE_BLOCK_PEEK_LINES = 10 function CodeBlock({ className, children }: { className?: string; children?: React.ReactNode }) { const [copied, setCopied] = useState(false) const [expanded, setExpanded] = useState(false) const text = String(children).replace(/\n$/, '') const lang = className?.replace('language-', '') || '' const lines = text.split('\n') const needsTruncation = lines.length > CODE_BLOCK_MAX_LINES const omittedCount = needsTruncation ? lines.length - CODE_BLOCK_PEEK_LINES * 2 : 0 const handleCopy = useCallback(() => { navigator.clipboard.writeText(text) setCopied(true) setTimeout(() => setCopied(false), 1500) }, [text]) return (
{lang || 'code'}{needsTruncation ? ` (${lines.length} lines)` : ''}

        {needsTruncation && !expanded ? (
          <>
            {lines.slice(0, CODE_BLOCK_PEEK_LINES).join('\n') + '\n'}
             setExpanded(true)}>
              {'... +'}{omittedCount}{' lines (click to expand)'}
            
            {'\n' + lines.slice(-CODE_BLOCK_PEEK_LINES).join('\n')}
          
        ) : (
          text
        )}
      
{needsTruncation && expanded && ( )}
) } const mdComponents = { code({ className, children, ...props }: any) { const isBlock = className?.startsWith('language-') if (isBlock) { return {children} } return {children} }, } const MSG_COLLAPSE_CHAR_THRESHOLD = 3000 const MSG_COLLAPSE_LINE_THRESHOLD = 60 const MSG_PREVIEW_CHARS = 800 function shouldCollapseContent(content: string): boolean { if (content.length > MSG_COLLAPSE_CHAR_THRESHOLD) return true let newlines = 0 for (let i = 0; i < content.length; i++) { if (content[i] === '\n' && ++newlines >= MSG_COLLAPSE_LINE_THRESHOLD) return true } return false } function truncatePreview(content: string): string { const cut = content.lastIndexOf('\n', MSG_PREVIEW_CHARS) return content.slice(0, cut > MSG_PREVIEW_CHARS / 2 ? cut : MSG_PREVIEW_CHARS) } type MarkdownCollapseMode = 'auto' | 'never' export const MarkdownBody = React.memo(function MarkdownBody({ content, className = 'msg-content-agent', collapseMode = 'auto', }: { content: string className?: string collapseMode?: MarkdownCollapseMode }) { const collapsible = collapseMode !== 'never' && shouldCollapseContent(content) const [collapsed, setCollapsed] = useState(collapsible) useEffect(() => { setCollapsed(collapseMode !== 'never' && shouldCollapseContent(content)) }, [collapseMode, content]) const displayContent = collapsed ? truncatePreview(content) : content const lineCount = content.split('\n').length const charCount = content.length return (
{displayContent} {collapsible && collapsed && ( )} {collapsible && !collapsed && ( )}
) })