diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 23ec50af37..a6e1f4c638 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -1090,6 +1090,8 @@ export const ChatRowContent = ({ isStreaming={isStreaming} isLast={isLast} metadata={message.metadata as any} + isExpanded={isExpanded} + onToggleExpand={handleToggleExpand} /> ) case "api_req_started": diff --git a/webview-ui/src/components/chat/ReasoningBlock.tsx b/webview-ui/src/components/chat/ReasoningBlock.tsx index 3c981126ef..85767fd25e 100644 --- a/webview-ui/src/components/chat/ReasoningBlock.tsx +++ b/webview-ui/src/components/chat/ReasoningBlock.tsx @@ -2,7 +2,8 @@ import React, { useEffect, useRef, useState } from "react" import { useTranslation } from "react-i18next" import MarkdownBlock from "../common/MarkdownBlock" -import { Clock, Lightbulb } from "lucide-react" +import { Clock, Lightbulb, ChevronDown, ChevronUp } from "lucide-react" +import { ToolUseBlock } from "../common/ToolUseBlock" interface ReasoningBlockProps { content: string @@ -10,19 +11,33 @@ interface ReasoningBlockProps { isStreaming: boolean isLast: boolean metadata?: any + isExpanded?: boolean + onToggleExpand?: () => void } /** * Render reasoning with a heading and a simple timer. * - Heading uses i18n key chat:reasoning.thinking * - Timer runs while reasoning is active (no persistence) + * - Content can be collapsed/expanded for better performance */ -export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockProps) => { +export const ReasoningBlock = ({ + content, + isStreaming, + isLast, + isExpanded: externalIsExpanded, + onToggleExpand, +}: ReasoningBlockProps) => { const { t } = useTranslation() const startTimeRef = useRef(Date.now()) const [elapsed, setElapsed] = useState(0) + // Use internal state if no external control is provided + const [internalIsExpanded, setInternalIsExpanded] = useState(false) + const isExpanded = externalIsExpanded !== undefined ? externalIsExpanded : internalIsExpanded + const toggleExpand = onToggleExpand || (() => setInternalIsExpanded(!internalIsExpanded)) + // Simple timer that runs while streaming useEffect(() => { if (isLast && isStreaming) { @@ -35,26 +50,33 @@ export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockP const seconds = Math.floor(elapsed / 1000) const secondsLabel = t("chat:reasoning.seconds", { count: seconds }) + const hasContent = (content?.trim()?.length ?? 0) > 0 return ( -
-
+ +
{t("chat:reasoning.thinking")}
- {elapsed > 0 && ( - - - {secondsLabel} - - )} +
+ {elapsed > 0 && ( + + + {secondsLabel} + + )} + {hasContent && + (isExpanded ? : )} +
- {(content?.trim()?.length ?? 0) > 0 && ( -
+ {hasContent && isExpanded && ( +
)} -
+
) }