'use client' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { LoadingSpinner } from '@/components/common/LoadingSpinner' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' import { CheckCircle, Sparkles, Lightbulb, ChevronDown } from 'lucide-react' import { useState } from 'react' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import { convertReferencesToMarkdownLinks, createReferenceLinkComponent } from '@/lib/utils/source-references' import { useModalManager } from '@/lib/hooks/use-modal-manager' import { toast } from 'sonner' interface StrategyData { reasoning: string searches: Array<{ term: string; instructions: string }> } interface StreamingResponseProps { isStreaming: boolean strategy: StrategyData | null answers: string[] finalAnswer: string | null } export function StreamingResponse({ isStreaming, strategy, answers, finalAnswer }: StreamingResponseProps) { const [strategyOpen, setStrategyOpen] = useState(false) const [answersOpen, setAnswersOpen] = useState(false) const { openModal } = useModalManager() const handleReferenceClick = (type: string, id: string) => { const modalType = type === 'source_insight' ? 'insight' : type as 'source' | 'note' | 'insight' try { openModal(modalType, id) // Note: The modal system uses URL parameters and doesn't throw errors for missing items. // The modal component itself will handle displaying "not found" states. // This try-catch is here for future enhancements or unexpected errors. } catch { const typeLabel = type === 'source_insight' ? 'insight' : type toast.error(`This ${typeLabel} could not be found`) } } if (!strategy && !answers.length && !finalAnswer && !isStreaming) { return null } return (
{/* Strategy Section - Collapsible */} {strategy && ( Strategy

Reasoning:

{strategy.reasoning}

{strategy.searches.length > 0 && (

Search Terms:

{strategy.searches.map((search, i) => (
{i + 1}

{search.term}

{search.instructions}

))}
)}
)} {/* Individual Answers Section - Collapsible */} {answers.length > 0 && ( Individual Answers ({answers.length}) {answers.map((answer, i) => (

{answer}

))}
)} {/* Final Answer Section - Always Open */} {finalAnswer && ( Final Answer )} {/* Loading Indicator */} {isStreaming && !finalAnswer && (
Processing your question...
)}
) } // Helper component to render final answer with clickable references function FinalAnswerContent({ content, onReferenceClick }: { content: string onReferenceClick: (type: string, id: string) => void }) { // Convert references to markdown links const markdownWithLinks = convertReferencesToMarkdownLinks(content) // Create custom link component const LinkComponent = createReferenceLinkComponent(onReferenceClick) return (
(
{children}
), thead: ({ children }) => {children}, tbody: ({ children }) => {children}, tr: ({ children }) => {children}, th: ({ children }) => {children}, td: ({ children }) => {children}, }} > {markdownWithLinks}
) }