diff --git a/packages/web-client/src/features/chat/presentation/components/ChatWindow.tsx b/packages/web-client/src/features/chat/presentation/components/ChatWindow.tsx index 7dee049..23c52cb 100644 --- a/packages/web-client/src/features/chat/presentation/components/ChatWindow.tsx +++ b/packages/web-client/src/features/chat/presentation/components/ChatWindow.tsx @@ -2,14 +2,13 @@ import { useRef, useEffect } from 'react'; import { MessageBubble } from './MessageBubble'; import { InputArea } from './InputArea'; import { TypingIndicator } from './TypingIndicator'; -import { AgentStatusIndicator } from './AgentStatusIndicator'; import { useChatStore } from '../stores/chatStore'; import { useChat } from '../hooks/useChat'; import { MessageSquare, Menu } from 'lucide-react'; export function ChatWindow() { const messagesEndRef = useRef(null); - const { messages, currentConversationId, isStreaming, streamContent, sidebarOpen, toggleSidebar } = useChatStore(); + const { messages, currentConversationId, isStreaming, streamContent, sidebarOpen, toggleSidebar, activeAgents, coordinatorPhase } = useChatStore(); const { sendMessage, pendingFiles, @@ -19,10 +18,10 @@ export function ChatWindow() { removeFile, } = useChat(); - // Auto-scroll to bottom + // Auto-scroll to bottom (including when agent status changes) useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); - }, [messages, streamContent]); + }, [messages, streamContent, activeAgents, coordinatorPhase]); const currentMessages = currentConversationId ? messages[currentConversationId] || [] @@ -81,9 +80,8 @@ export function ChatWindow() { )} - {/* Agent status + Input area */} + {/* Input area */}
-
= { + policy_expert: '政策专家', + assessment_expert: '评估专家', + strategist: '策略顾问', + objection_handler: '异议处理专家', + case_analyst: '案例分析师', + memory_manager: '记忆管理', +}; + +const PHASE_DISPLAY: Record = { + analyzing: '正在分析问题...', + orchestrating: '正在协调专家团队...', + synthesizing: '正在综合分析结果...', + evaluating: '正在进行质量检查...', +}; export function TypingIndicator() { + const { activeAgents, completedAgents, coordinatorPhase, coordinatorMessage } = useChatStore(); + + const hasAgentActivity = activeAgents.length > 0 || coordinatorPhase !== null; + return (
{/* Avatar */} @@ -8,13 +30,74 @@ export function TypingIndicator() {
- {/* Typing dots */} -
-
- - - + {/* Content area */} +
+ {/* Typing dots — always shown as primary indicator */} +
+
+ + + +
+ + {/* Agent status — shown below dots when there's activity */} + {hasAgentActivity && ( +
+ {/* Coordinator phase */} + {coordinatorPhase && ( +
+ + + {PHASE_DISPLAY[coordinatorPhase] || coordinatorMessage} + +
+ )} + + {/* Active agents */} + {activeAgents.map((agent) => ( +
+ + + + {AGENT_DISPLAY_NAMES[agent.agentType] || agent.agentName} + + {agent.description && ( + - {agent.description} + )} + +
+ ))} + + {/* Completed agents (compact badges) */} + {completedAgents.length > 0 && activeAgents.length > 0 && ( +
+ {completedAgents.map((agent) => ( + + + {AGENT_DISPLAY_NAMES[agent.agentType] || agent.agentName} + {agent.durationMs > 0 && ( + + {(agent.durationMs / 1000).toFixed(1)}s + + )} + + ))} +
+ )} +
+ )}
);