import React, { useMemo, useState } from 'react'; import { Bot, ChevronDown, CheckCircle2, Loader2, Sparkles, UserRound } from 'lucide-react'; import { useTheme } from '../../contexts/ThemeContext'; import MarkdownRenderer from '../MarkdownRenderer'; import { parseAgentResponse } from '../agent/agentResponseParser'; export interface AgentChatMsg { id: string; role: 'user' | 'assistant'; content: string; } interface AvatarProps { role: 'user' | 'assistant'; isActive?: boolean; } const AgentAvatar: React.FC = ({ role, isActive = false }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; const Icon = role === 'assistant' ? Bot : UserRound; const gradientClass = role === 'assistant' ? isDark ? 'bg-gradient-to-br from-cyan-500 via-blue-600 to-violet-600 text-white' : 'bg-gradient-to-br from-red-400 via-rose-500 to-orange-400 text-white' : isDark ? 'bg-gradient-to-br from-slate-500 via-slate-700 to-slate-900 text-white' : 'bg-gradient-to-br from-sky-400 via-indigo-500 to-violet-500 text-white'; return (
{role === 'assistant' && isActive && ( )}
); }; interface CollapsibleProps { title: React.ReactNode; children: React.ReactNode; defaultOpen?: boolean; className?: string; } const Collapsible: React.FC = ({ title, children, defaultOpen = true, className = '', }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; const [open, setOpen] = useState(defaultOpen); return (
{children}
); }; interface AssistantAnswerProps { steps: { title: string; content: string }[]; thinkingMarkdown: string; answerMarkdown: string; thinkingComplete: boolean; streaming: boolean; } const AssistantAnswer: React.FC = ({ steps, thinkingMarkdown, answerMarkdown, thinkingComplete, streaming, }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; const showThinkingSection = Boolean(thinkingMarkdown) || (!thinkingComplete && streaming); return (
{steps.length > 0 && (
步骤
展示技能执行、上下文准备和模型调用进度
} >
{steps.map((step, index) => (
{step.title}
{step.content}
))}
)} {showThinkingSection && (
思考过程
{thinkingComplete ? (
思考已完成,可展开查看
) : (
正在生成思考内容...
)}
} > {thinkingMarkdown ? ( ) : (
等待模型输出思考内容...
)} )} {answerMarkdown ? (
) : null} ); }; interface MessageRowProps { msg: AgentChatMsg; streaming?: boolean; } const MessageRow: React.FC = ({ msg, streaming = false }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; const isUser = msg.role === 'user'; const parsed = useMemo(() => { if (isUser) return null; return parseAgentResponse(msg.content); }, [msg.content, isUser]); if (isUser) { return (

{msg.content}

); } return (
{parsed ? ( ) : (
)}
); }; interface AgentChatMessageListProps { messages: AgentChatMsg[]; streamingMsgId?: string | null; agentName?: string; } const AgentChatMessageList: React.FC = ({ messages, streamingMsgId, agentName, }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; if (messages.length === 0) { return (

直接与 {agentName || 'MCP 智能体'} 对话以测试当前配置

已绑定技能会在步骤区显示实际执行过程

); } return (
{messages.map((msg, idx) => { const isLast = idx === messages.length - 1; const isStreaming = isLast && msg.role === 'assistant' && msg.id === streamingMsgId; return ; })}
); }; export default AgentChatMessageList;