import { cn } from "@/lib/utils"; import { ChevronDown } from "lucide-react"; import { createContext, useContext, useEffect, useRef, useState } from "react"; import { Markdown } from "./markdown"; type ReasoningContextType = { isOpen: boolean; onOpenChange: (open: boolean) => void; }; const ReasoningContext = createContext(undefined); function useReasoningContext() { const context = useContext(ReasoningContext); if (!context) { throw new Error("useReasoningContext must be used within a Reasoning provider"); } return context; } function Reasoning({ children, className, open, onOpenChange, isStreaming, }: { children: React.ReactNode; className?: string; open?: boolean; onOpenChange?: (open: boolean) => void; isStreaming?: boolean; }) { const [internalOpen, setInternalOpen] = useState(false); const [wasAutoOpened, setWasAutoOpened] = useState(false); const isControlled = open !== undefined; const isOpen = isControlled ? open : internalOpen; const handleOpenChange = (newOpen: boolean) => { if (!isControlled) { setInternalOpen(newOpen); } onOpenChange?.(newOpen); }; useEffect(() => { if (isStreaming && !wasAutoOpened) { if (!isControlled) setInternalOpen(true); setWasAutoOpened(true); } if (!isStreaming && wasAutoOpened) { if (!isControlled) setInternalOpen(false); setWasAutoOpened(false); } }, [isStreaming, wasAutoOpened, isControlled]); return (
{children}
); } function ReasoningTrigger({ children, className, ...props }: { children: React.ReactNode; className?: string } & React.HTMLAttributes) { const { isOpen, onOpenChange } = useReasoningContext(); return ( ); } function ReasoningContent({ children, className, markdown = false, ...props }: { children: React.ReactNode; className?: string; markdown?: boolean; } & React.HTMLAttributes) { const contentRef = useRef(null); const innerRef = useRef(null); const { isOpen } = useReasoningContext(); useEffect(() => { if (!contentRef.current || !innerRef.current) return; const observer = new ResizeObserver(() => { if (contentRef.current && innerRef.current && isOpen) { contentRef.current.style.maxHeight = `${innerRef.current.scrollHeight}px`; } }); observer.observe(innerRef.current); if (isOpen) { contentRef.current.style.maxHeight = `${innerRef.current.scrollHeight}px`; } return () => observer.disconnect(); }, [isOpen]); return (
{markdown ? {children as string} : children}
); } export { Reasoning, ReasoningTrigger, ReasoningContent };