import { Divider, Tag, Avatar } from 'antd'; import { useState, useEffect } from 'react'; import type { Agent, BranchInfo, ChatMessage } from '../../../api'; import Markdown from '../../../components/Markdown'; import type { StreamingState } from '../hooks/useChatSender'; import type { CopyMode } from '../utils/copy'; import MessageItem from './messages/MessageItem'; import { ReasoningView, RetrievedView, ToolCallView } from './messages/MetaViews'; import './ChatBody.css'; const isImageUrl = (url: string) => url?.startsWith('http') || url?.startsWith('/'); export default function ChatBody(props: { bodyRef: React.RefObject; agent: Agent; agentList: Agent[]; currentAgentId: string; messages: ChatMessage[]; branches: Record; highlightId: string | null; sending: boolean; streaming: StreamingState; onRegenerate: (assistantId: string) => void; onSwitchBranch: (userMsgId: string, branchId: string) => void; onCopy: (text: string, mode: CopyMode) => void; isMobile?: boolean; }) { const { bodyRef, agent, agentList, currentAgentId, messages, branches, highlightId, sending, streaming, onRegenerate, onSwitchBranch, onCopy, isMobile } = props; const [streamingReasoningExpanded, setStreamingReasoningExpanded] = useState(true); // 当开始新的回答时,默认展开推理过程;当正式回答开始时,自动折叠推理过程 useEffect(() => { if (streaming.active) { if (!streaming.answerText) { setStreamingReasoningExpanded(true); } else { setStreamingReasoningExpanded(false); } } }, [streaming.active, !!streaming.answerText]); return (
{messages.length === 0 && !streaming.active ? (
{isImageUrl(agent.avatar) ? ( avatar ) : ( (agent.name?.charAt(0) || '?').toUpperCase() )}

你好,今天想一起完成什么?

{agent.description || '我是你的专属 AI 助手,随时准备为你服务。'}

) : ( <> {messages.map((m) => ( ))} {streaming.active && (
{(() => { const streamingAgentId = streaming.targetAgentId || currentAgentId; const streamingAgent = agentList.find(a => a.id === streamingAgentId); return ( {streamingAgent?.name?.charAt(0)?.toUpperCase() || 'A'} ); })()}
{agentList.find(a => a.id === (streaming.targetAgentId || currentAgentId))?.name || 'AI'}
{!!streaming.retryInfo?.message && (
{streaming.retryInfo.stage === 'fallback_model' ? '自动切换模型' : '自动重试'} {streaming.retryInfo.stage === 'fallback_model' ? ( {String(streaming.retryInfo.fromModel || '')} → {String(streaming.retryInfo.toModel || '')} ) : ( {String(streaming.retryInfo.model || '')} {streaming.retryInfo.attempt ? ` · 第${streaming.retryInfo.attempt}次` : ''} )}
{String(streaming.retryInfo.message)}
)}
setStreamingReasoningExpanded(!streamingReasoningExpanded)} />
{streaming.answerText && ( <>
正式回答
{streaming.answerText + '▍'}
)}
{(streaming.retrieved.length > 0 || streaming.toolCalls.length > 0) && (
{streaming.retrieved.length > 0 && } {streaming.toolCalls.length > 0 && }
)}
)} )}
); }