mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-24 00:51:34 +00:00
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { useEffect, useRef, useState } from "react"
|
|
import { useTranslation } from "react-i18next"
|
|
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
|
|
|
import MarkdownBlock from "../common/MarkdownBlock"
|
|
import { Lightbulb, ChevronUp } from "lucide-react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
interface ReasoningBlockProps {
|
|
content: string
|
|
ts: number
|
|
isStreaming: boolean
|
|
isLast: boolean
|
|
metadata?: any
|
|
}
|
|
|
|
export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockProps) => {
|
|
const { t } = useTranslation()
|
|
const { reasoningBlockCollapsed } = useExtensionState()
|
|
|
|
const [isCollapsed, setIsCollapsed] = useState(reasoningBlockCollapsed)
|
|
|
|
const startTimeRef = useRef<number>(Date.now())
|
|
const [elapsed, setElapsed] = useState<number>(0)
|
|
const contentRef = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
setIsCollapsed(reasoningBlockCollapsed)
|
|
}, [reasoningBlockCollapsed])
|
|
|
|
useEffect(() => {
|
|
if (isLast && isStreaming) {
|
|
const tick = () => setElapsed(Date.now() - startTimeRef.current)
|
|
tick()
|
|
const id = setInterval(tick, 1000)
|
|
return () => clearInterval(id)
|
|
}
|
|
}, [isLast, isStreaming])
|
|
|
|
const seconds = Math.floor(elapsed / 1000)
|
|
const secondsLabel = t("chat:reasoning.seconds", { count: seconds })
|
|
|
|
const handleToggle = () => {
|
|
setIsCollapsed(!isCollapsed)
|
|
}
|
|
|
|
return (
|
|
<div className="group">
|
|
<div
|
|
className="flex items-center justify-between mb-2.5 pr-2 cursor-pointer select-none"
|
|
onClick={handleToggle}>
|
|
<div className="flex items-center gap-2">
|
|
<Lightbulb className="w-4" />
|
|
<span className="font-bold text-vscode-foreground">{t("chat:reasoning.thinking")}</span>
|
|
{elapsed > 0 && (
|
|
<span className="text-sm text-vscode-descriptionForeground mt-0.5">{secondsLabel}</span>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<ChevronUp
|
|
className={cn(
|
|
"w-4 transition-all opacity-0 group-hover:opacity-100",
|
|
isCollapsed && "-rotate-180",
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
{(content?.trim()?.length ?? 0) > 0 && !isCollapsed && (
|
|
<div
|
|
ref={contentRef}
|
|
className="border-l border-vscode-descriptionForeground/20 ml-2 pl-4 pb-1 text-vscode-descriptionForeground break-words">
|
|
<MarkdownBlock markdown={content} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|