feat(ui): render reasoning as plain italic text to match <thinking> style; remove bounding container

This commit is contained in:
Roo Code 2025-09-07 04:22:58 +00:00
parent 18cf33f96d
commit ab958bf80b
2 changed files with 9 additions and 97 deletions

View file

@ -118,7 +118,6 @@ export const ChatRowContent = ({
const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration } = useExtensionState()
const { info: model } = useSelectedModel(apiConfiguration)
const [reasoningCollapsed, setReasoningCollapsed] = useState(true)
const [isDiffErrorExpanded, setIsDiffErrorExpanded] = useState(false)
const [showCopySuccess, setShowCopySuccess] = useState(false)
const [isEditing, setIsEditing] = useState(false)
@ -1084,14 +1083,7 @@ export const ChatRowContent = ({
</div>
)
case "reasoning":
return (
<ReasoningBlock
content={message.text || ""}
elapsed={isLast && isStreaming ? Date.now() - message.ts : undefined}
isCollapsed={reasoningCollapsed}
onToggleCollapse={() => setReasoningCollapsed(!reasoningCollapsed)}
/>
)
return <ReasoningBlock content={message.text || ""} />
case "api_req_started":
return (
<>

View file

@ -1,99 +1,19 @@
import { useCallback, useEffect, useRef, useState } from "react"
import { CaretDownIcon, CaretUpIcon, CounterClockwiseClockIcon } from "@radix-ui/react-icons"
import { useTranslation } from "react-i18next"
import MarkdownBlock from "../common/MarkdownBlock"
import { useMount } from "react-use"
interface ReasoningBlockProps {
content: string
elapsed?: number
isCollapsed?: boolean
onToggleCollapse?: () => void
}
export const ReasoningBlock = ({ content, elapsed, isCollapsed = false, onToggleCollapse }: ReasoningBlockProps) => {
const contentRef = useRef<HTMLDivElement>(null)
const elapsedRef = useRef<number>(0)
const { t } = useTranslation("chat")
const [thought, setThought] = useState<string>()
const [prevThought, setPrevThought] = useState<string>(t("chat:reasoning.thinking"))
const [isTransitioning, setIsTransitioning] = useState<boolean>(false)
const cursorRef = useRef<number>(0)
const queueRef = useRef<string[]>([])
useEffect(() => {
if (contentRef.current && !isCollapsed) {
contentRef.current.scrollTop = contentRef.current.scrollHeight
}
}, [content, isCollapsed])
useEffect(() => {
if (elapsed) {
elapsedRef.current = elapsed
}
}, [elapsed])
// Process the transition queue.
const processNextTransition = useCallback(() => {
const nextThought = queueRef.current.pop()
queueRef.current = []
if (nextThought) {
setIsTransitioning(true)
}
setTimeout(() => {
if (nextThought) {
setPrevThought(nextThought)
setIsTransitioning(false)
}
setTimeout(() => processNextTransition(), 500)
}, 200)
}, [])
useMount(() => {
processNextTransition()
})
useEffect(() => {
if (content.length - cursorRef.current > 160) {
setThought("... " + content.slice(cursorRef.current))
cursorRef.current = content.length
}
}, [content])
useEffect(() => {
if (thought && thought !== prevThought) {
queueRef.current.push(thought)
}
}, [thought, prevThought])
/**
* Render reasoning as simple italic text, matching how <thinking> content is shown.
* No borders, boxes, headers, timers, or collapsible behavior.
*/
export const ReasoningBlock = ({ content }: ReasoningBlockProps) => {
return (
<div className="bg-vscode-editor-background border border-vscode-border rounded-xs overflow-hidden">
<div
className="flex items-center justify-between gap-1 px-3 py-2 cursor-pointer text-muted-foreground"
onClick={onToggleCollapse}>
<div
className={`truncate flex-1 transition-opacity duration-200 ${isTransitioning ? "opacity-0" : "opacity-100"}`}>
{prevThought}
</div>
<div className="flex flex-row items-center gap-1">
{elapsedRef.current > 1000 && (
<>
<CounterClockwiseClockIcon className="scale-80" />
<div>{t("reasoning.seconds", { count: Math.round(elapsedRef.current / 1000) })}</div>
</>
)}
{isCollapsed ? <CaretDownIcon /> : <CaretUpIcon />}
</div>
<div className="px-3 py-1">
<div className="italic text-muted-foreground">
<MarkdownBlock markdown={content} />
</div>
{!isCollapsed && (
<div ref={contentRef} className="px-3 max-h-[160px] overflow-y-auto">
<MarkdownBlock markdown={content} />
</div>
)}
</div>
)
}