@@ -4,37 +4,43 @@ import { useTranslation } from "react-i18next"
44import MarkdownBlock from "../common/MarkdownBlock"
55import { vscode } from "@src/utils/vscode"
66
7+ interface ReasoningMeta {
8+ startedAt ?: number
9+ elapsedMs ?: number
10+ }
11+
712interface ReasoningBlockProps {
813 content : string
914 ts : number
1015 isStreaming : boolean
1116 isLast : boolean
12- metadata ?: Record < string , any >
17+ metadata ?: { reasoning ?: ReasoningMeta } | Record < string , any >
1318}
1419
1520/**
1621 * Render reasoning with a heading and a persistent timer.
1722 * - Heading uses i18n key chat:reasoning.thinking
18- * - Timer shown as "(⟲ 24s)" beside the heading and persists via message.metadata.reasoning { startedAt, elapsedMs }
23+ * - Timer shown beside the heading and persists via message.metadata.reasoning { startedAt, elapsedMs }
1924 */
2025export const ReasoningBlock = ( { content, ts, isStreaming, isLast, metadata } : ReasoningBlockProps ) => {
2126 const { t } = useTranslation ( )
2227
23- const persisted = ( metadata ?. reasoning as { startedAt ?: number ; elapsedMs ?: number } | undefined ) || { }
28+ const persisted : ReasoningMeta = ( metadata ?. reasoning as ReasoningMeta ) || { }
2429 const startedAtRef = useRef < number > ( persisted . startedAt ?? Date . now ( ) )
2530 const [ elapsed , setElapsed ] = useState < number > ( persisted . elapsedMs ?? 0 )
31+ const postedRef = useRef < boolean > ( false )
2632
27- // Initialize startedAt on first mount if missing (persist to task)
33+ // Initialize startedAt on first mount if missing (persist to task) - guard with postedRef
2834 useEffect ( ( ) => {
29- if ( ! persisted . startedAt && isLast ) {
35+ if ( ! persisted . startedAt && isLast && ! postedRef . current ) {
36+ postedRef . current = true
3037 vscode . postMessage ( {
3138 type : "updateMessageReasoningMeta" ,
3239 messageTs : ts ,
3340 reasoningMeta : { startedAt : startedAtRef . current } ,
34- } as any )
41+ } )
3542 }
36- // eslint-disable-next-line react-hooks/exhaustive-deps
37- } , [ ts ] )
43+ } , [ ts , isLast , persisted . startedAt ] )
3844
3945 // Tick while active (last row and streaming)
4046 useEffect ( ( ) => {
@@ -58,7 +64,7 @@ export const ReasoningBlock = ({ content, ts, isStreaming, isLast, metadata }: R
5864 type : "updateMessageReasoningMeta" ,
5965 messageTs : ts ,
6066 reasoningMeta : { startedAt : startedAtRef . current , elapsedMs : finalMs } ,
61- } as any )
67+ } )
6268 }
6369 wasActiveRef . current = active
6470 } , [ isLast , isStreaming , ts ] )
@@ -73,13 +79,13 @@ export const ReasoningBlock = ({ content, ts, isStreaming, isLast, metadata }: R
7379
7480 return (
7581 < div className = "py-1" >
76- < div className = "flex items-center justify-between mb-[10px] " >
82+ < div className = "flex items-center justify-between mb-2.5 " >
7783 < div className = "flex items-center gap-2" >
78- < span className = "codicon codicon-light-bulb" style = { { color : "var(-- vscode-charts-yellow)" } } />
84+ < span className = "codicon codicon-light-bulb text- vscode-charts-yellow" />
7985 < span className = "font-bold text-vscode-foreground" > { t ( "chat:reasoning.thinking" ) } </ span >
8086 </ div >
8187 < span className = "text-vscode-foreground tabular-nums flex items-center gap-1" >
82- < span className = "codicon codicon-clock" style = { { fontSize : "inherit" } } />
88+ < span className = "codicon codicon-clock text-base" />
8389 { secondsLabel }
8490 </ span >
8591 </ div >
0 commit comments