From 5f37c9e85ce4341cf6bee2349319260f54037273 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Mon, 13 Jul 2026 18:00:43 -0400 Subject: [PATCH] refactor(desktop): tighten reasoning part typing, drop dead useRef Self-review nits on the Thinking-widget fix: - type ReasoningTextPart as ReasoningMessagePartComponent and read the typed useMessagePartReasoning() directly, dropping the ad-hoc cast (the hook already returns text/status). - remove useRef, now unused after deleting useSmoothReveal. - trim the autopsy comments; the PR body carries the narrative. --- .../components/assistant-ui/markdown-text.tsx | 10 +++----- .../assistant-ui/thread/message-parts.tsx | 25 ++++++++++--------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/desktop/src/components/assistant-ui/markdown-text.tsx b/apps/desktop/src/components/assistant-ui/markdown-text.tsx index 883c3bd7ccb..694a94e78c7 100644 --- a/apps/desktop/src/components/assistant-ui/markdown-text.tsx +++ b/apps/desktop/src/components/assistant-ui/markdown-text.tsx @@ -15,7 +15,6 @@ import { useDeferredValue, useEffect, useMemo, - useRef, useState } from 'react' @@ -588,12 +587,9 @@ interface MarkdownTextContentProps extends MarkdownTextSurfaceProps { } export function MarkdownTextContent({ isRunning, text, ...surfaceProps }: MarkdownTextContentProps) { - // Render through the same path as the assistant answer (DeferStreamingText → - // surface). The previous SmoothStreamingText/useSmoothReveal wrapper stalled - // at empty for reasoning: the reasoning part stays isRunning for the whole - // message while the answer streams and thrashes re-renders, and the reveal - // never advanced past 0 — so the Thinking widget rendered blank even though - // the part carried text. Chunked (per-delta) reveal matches the answer. + // Same path as the assistant answer. A reasoning-only smoothing wrapper used + // to sit here but stalled its char-reveal at empty (the part stays running + // the whole message), blanking the Thinking widget. return ( diff --git a/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx b/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx index 17acfac7903..0e1a2e7e088 100644 --- a/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx +++ b/apps/desktop/src/components/assistant-ui/thread/message-parts.tsx @@ -1,4 +1,9 @@ -import { type ToolCallMessagePartProps, useAuiState, useMessagePartReasoning } from '@assistant-ui/react' +import { + type ReasoningMessagePartComponent, + type ToolCallMessagePartProps, + useAuiState, + useMessagePartReasoning +} from '@assistant-ui/react' import { type ComponentProps, type FC, type ReactNode, useEffect, useRef, useState } from 'react' import { ClarifyTool } from '@/components/assistant-ui/clarify-tool' @@ -174,23 +179,19 @@ const ReasoningAccordionGroup: FC<{ children?: ReactNode; endIndex: number; star ) } -const ReasoningTextPart: FC = () => { - // Read the reasoning text from the assistant-ui part context (same contract - // as MarkdownText's useMessagePartText). The `Reasoning` component is NOT - // handed a `text` prop — the runtime provides the part via context — so the - // previous prop-based read rendered an empty string and the Thinking widget - // showed blank even though the part carried text. - const part = useMessagePartReasoning() as { text?: string; status?: { type?: string } } +// Read the part from context, same contract as MarkdownText's +// useMessagePartText — the reasoning-only smoothing wrapper (removed) stalled +// the char-reveal at empty, blanking the widget. +const ReasoningTextPart: ReasoningMessagePartComponent = () => { + const { status, text } = useMessagePartReasoning() const messageRunning = useAuiState(s => s.message.status?.type === 'running') - const isRunning = part.status?.type === 'running' || messageRunning - const displayText = (part.text ?? '').trimStart() return ( } - isRunning={isRunning} - text={displayText} + isRunning={status.type === 'running' || messageRunning} + text={text.trimStart()} /> ) }