| | import { Box, Stack, Typography } from '@mui/material'; |
| | import MarkdownContent from './MarkdownContent'; |
| | import ToolCallGroup from './ToolCallGroup'; |
| | import type { Message } from '@/types/agent'; |
| |
|
| | interface AssistantMessageProps { |
| | message: Message; |
| | |
| | isStreaming?: boolean; |
| | } |
| |
|
| | export default function AssistantMessage({ message, isStreaming = false }: AssistantMessageProps) { |
| | const renderSegments = () => { |
| | if (message.segments && message.segments.length > 0) { |
| | |
| | let lastTextIdx = -1; |
| | for (let i = message.segments.length - 1; i >= 0; i--) { |
| | if (message.segments[i].type === 'text') { |
| | lastTextIdx = i; |
| | break; |
| | } |
| | } |
| |
|
| | return message.segments.map((segment, idx) => { |
| | if (segment.type === 'text' && segment.content) { |
| | return ( |
| | <MarkdownContent |
| | key={idx} |
| | content={segment.content} |
| | isStreaming={isStreaming && idx === lastTextIdx} |
| | /> |
| | ); |
| | } |
| | if (segment.type === 'tools' && segment.tools && segment.tools.length > 0) { |
| | return <ToolCallGroup key={idx} tools={segment.tools} />; |
| | } |
| | return null; |
| | }); |
| | } |
| |
|
| | |
| | if (message.content) { |
| | return <MarkdownContent content={message.content} isStreaming={isStreaming} />; |
| | } |
| |
|
| | return null; |
| | }; |
| |
|
| | return ( |
| | <Box sx={{ minWidth: 0 }}> |
| | {/* Role label + timestamp */} |
| | <Stack direction="row" alignItems="baseline" spacing={1} sx={{ mb: 0.5 }}> |
| | <Typography |
| | variant="caption" |
| | sx={{ |
| | fontWeight: 700, |
| | fontSize: '0.72rem', |
| | color: 'var(--muted-text)', |
| | textTransform: 'uppercase', |
| | letterSpacing: '0.04em', |
| | }} |
| | > |
| | Assistant |
| | </Typography> |
| | <Typography |
| | variant="caption" |
| | sx={{ |
| | fontSize: '0.66rem', |
| | color: 'var(--muted-text)', |
| | opacity: 0.6, |
| | }} |
| | > |
| | {new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} |
| | </Typography> |
| | </Stack> |
| | |
| | {/* Message bubble */} |
| | <Box |
| | sx={{ |
| | maxWidth: { xs: '95%', md: '85%' }, |
| | bgcolor: 'var(--surface)', |
| | borderRadius: 1.5, |
| | borderTopLeftRadius: 4, |
| | px: { xs: 1.5, md: 2.5 }, |
| | py: 1.5, |
| | border: '1px solid var(--border)', |
| | }} |
| | > |
| | {renderSegments()} |
| | </Box> |
| | </Box> |
| | ); |
| | } |
| |
|