import { useState, useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; import { LuBrain, LuChevronDown, LuChevronRight } from "react-icons/lu"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; type ReasoningBubbleProps = { /** The accumulated reasoning text from the model. */ reasoning: string; /** * Whether the assistant has begun producing the user-facing answer. * While false the reasoning is still streaming and we keep the panel * open with a "Thinking…" label. Once true, the panel auto-collapses * so the answer is the primary focus, but stays expandable. */ answerStarted: boolean; }; export function ReasoningBubble({ reasoning, answerStarted, }: ReasoningBubbleProps) { const { t } = useTranslation(["views/chat"]); // Open while the model is still mid-thought (no answer tokens yet); // once the answer begins, collapse on its own but let the user reopen. const [open, setOpen] = useState(true); const userInteractedRef = useRef(false); const lastAutoState = useRef(true); useEffect(() => { if (userInteractedRef.current) return; const desired = !answerStarted; if (desired !== lastAutoState.current) { lastAutoState.current = desired; setOpen(desired); } }, [answerStarted]); const handleOpenChange = (next: boolean) => { userInteractedRef.current = true; setOpen(next); }; const label = !answerStarted ? t("reasoning.thinking") : open ? t("reasoning.hide") : t("reasoning.show"); return (
{reasoning}