diff --git a/ui/src/components/ChatPanel.tsx b/ui/src/components/ChatPanel.tsx index 60a3fd0a..f03f8081 100644 --- a/ui/src/components/ChatPanel.tsx +++ b/ui/src/components/ChatPanel.tsx @@ -1,8 +1,9 @@ -import { useState, useMemo } from "react"; +import { useState, useMemo, useEffect, useCallback } from "react"; import { X } from "lucide-react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useChatPanel } from "../context/ChatPanelContext"; import { useCompany } from "../context/CompanyContext"; +import { useToast } from "../context/ToastContext"; import { ChatInput } from "./ChatInput"; import { ChatConversationList } from "./ChatConversationList"; import { ChatMessageList } from "./ChatMessageList"; @@ -13,6 +14,7 @@ import { chatApi } from "../api/chat"; import { agentsApi } from "../api/agents"; import { useChatMessages } from "../hooks/useChatMessages"; import { useStreamingChat } from "../hooks/useStreamingChat"; +import { useBrainstormerDefault } from "../hooks/useBrainstormerDefault"; import { resolveAgentFromContent } from "../lib/slash-commands"; import type { AgentRole } from "@paperclipai/shared"; @@ -20,12 +22,33 @@ export function ChatPanel() { const { chatOpen, setChatOpen, activeConversationId, setActiveConversationId } = useChatPanel(); const { selectedCompanyId } = useCompany(); const queryClient = useQueryClient(); + const { pushToast } = useToast(); const [isSending, setIsSending] = useState(false); const [activeAgentId, setActiveAgentId] = useState(null); const { messages } = useChatMessages(activeConversationId); const { streamingContent, isStreaming, startStream, stop } = useStreamingChat(activeConversationId); + const brainstormerDefaultId = useBrainstormerDefault(); + + // Auto-select brainstormer (general agent) for new conversations + useEffect(() => { + if (activeAgentId === null && brainstormerDefaultId !== null && !activeConversationId) { + setActiveAgentId(brainstormerDefaultId); + } + }, [activeAgentId, brainstormerDefaultId, activeConversationId]); + + // Handoff callback: call handoff API and invalidate messages cache + const handleHandoff = useCallback(async (spec: { what: string; why: string; constraints: string; success: string }) => { + if (!activeConversationId) return; + try { + await chatApi.handoffSpec(activeConversationId, spec, "pm"); + queryClient.invalidateQueries({ queryKey: ["chat", "messages", activeConversationId] }); + } catch { + pushToast({ title: "Could not send to PM. Try again.", tone: "error" }); + } + }, [activeConversationId, queryClient, pushToast]); + // Load agents for routing and identity const { data: agents = [], isLoading: agentsLoading } = useQuery({ queryKey: ["agents", selectedCompanyId], @@ -179,6 +202,7 @@ export function ChatPanel() { streamingAgentRole={streamingAgent?.role ?? null} onEdit={handleEdit} onRetry={handleRetry} + onHandoff={handleHandoff} agentMap={agentMap} /> ) : (