({ content, isStreaming, isLast }: ReasoningBlockProps)
| 15 | } |
| 16 | |
| 17 | export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockProps) => { |
| 18 | const { t } = useTranslation() |
| 19 | const { reasoningBlockCollapsed } = useExtensionState() |
| 20 | |
| 21 | const [isCollapsed, setIsCollapsed] = useState(reasoningBlockCollapsed) |
| 22 | |
| 23 | const startTimeRef = useRef<number>(Date.now()) |
| 24 | const [elapsed, setElapsed] = useState<number>(0) |
| 25 | const contentRef = useRef<HTMLDivElement>(null) |
| 26 | |
| 27 | useEffect(() => { |
| 28 | setIsCollapsed(reasoningBlockCollapsed) |
| 29 | }, [reasoningBlockCollapsed]) |
| 30 | |
| 31 | useEffect(() => { |
| 32 | if (isLast && isStreaming) { |
| 33 | const tick = () => setElapsed(Date.now() - startTimeRef.current) |
| 34 | tick() |
| 35 | const id = setInterval(tick, 1000) |
| 36 | return () => clearInterval(id) |
| 37 | } |
| 38 | }, [isLast, isStreaming]) |
| 39 | |
| 40 | const seconds = Math.floor(elapsed / 1000) |
| 41 | const secondsLabel = t("chat:reasoning.seconds", { count: seconds }) |
| 42 | |
| 43 | const handleToggle = () => { |
| 44 | setIsCollapsed(!isCollapsed) |
| 45 | } |
| 46 | |
| 47 | return ( |
| 48 | <div className="group"> |
| 49 | <div |
| 50 | className="flex items-center justify-between mb-2.5 pr-2 cursor-pointer select-none" |
| 51 | onClick={handleToggle}> |
| 52 | <div className="flex items-center gap-2"> |
| 53 | <Lightbulb className="w-4" /> |
| 54 | <span className="font-bold text-vscode-foreground">{t("chat:reasoning.thinking")}</span> |
| 55 | {elapsed > 0 && ( |
| 56 | <span className="text-sm text-vscode-descriptionForeground mt-0.5">{secondsLabel}</span> |
| 57 | )} |
| 58 | </div> |
| 59 | <div className="flex items-center gap-2"> |
| 60 | <ChevronUp |
| 61 | className={cn( |
| 62 | "w-4 transition-all opacity-0 group-hover:opacity-100", |
| 63 | isCollapsed && "-rotate-180", |
| 64 | )} |
| 65 | /> |
| 66 | </div> |
| 67 | </div> |
| 68 | {(content?.trim()?.length ?? 0) > 0 && !isCollapsed && ( |
| 69 | <div |
| 70 | ref={contentRef} |
| 71 | className="border-l border-vscode-descriptionForeground/20 ml-2 pl-4 pb-1 text-vscode-descriptionForeground break-words"> |
| 72 | <MarkdownBlock markdown={content} /> |
| 73 | </div> |
| 74 | )} |
nothing calls this directly
no test coverage detected