diff --git a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx index a95572378e..01bff0c253 100644 --- a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx @@ -273,6 +273,10 @@ Reasoning.displayName = 'Reasoning'; type ReasoningCompactProps = { reasoning: string; label: string; + /** The host's thoughts-visible preference, supplied by the group rather + * than read from the app store, so a grouped thought stays movable with + * the feature that renders it. */ + showThinking: boolean; isAfterTool?: boolean; /** True while this is the reasoning part currently streaming. Drives the * collapsed grok-style live peek. */ @@ -287,11 +291,16 @@ type ReasoningCompactProps = { * a floating collapse + copy bar inside the rounded content panel. */ export const ReasoningCompact = memo( - ({ reasoning, label, isAfterTool = false, isStreaming = false }: ReasoningCompactProps) => { + ({ + reasoning, + label, + showThinking, + isAfterTool = false, + isStreaming = false, + }: ReasoningCompactProps) => { const contentId = useId(); const localize = useLocalize(); const fontSize = useAtomValue(fontSizeAtom); - const showThinking = useAtomValue(showThinkingAtom); const [isExpanded, setIsExpanded] = useState(showThinking); const [isBarVisible, setIsBarVisible] = useState(false); const [isCopied, setIsCopied] = useState(false); diff --git a/client/src/components/Chat/Messages/Content/Parts/__tests__/ReasoningCompact.test.tsx b/client/src/components/Chat/Messages/Content/Parts/__tests__/ReasoningCompact.test.tsx index c41d4161f7..2a9f2e9cb7 100644 --- a/client/src/components/Chat/Messages/Content/Parts/__tests__/ReasoningCompact.test.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/__tests__/ReasoningCompact.test.tsx @@ -36,7 +36,7 @@ jest.mock('lucide-react', () => ({ describe('ReasoningCompact', () => { it('reveals its own Thoughts chevron instantly on row hover or focus', () => { - render(); + render(); const button = screen.getByRole('button', { name: 'Thoughts' }); const chevron = screen.getByTestId('thoughts-chevron'); @@ -55,7 +55,14 @@ describe('ReasoningCompact', () => { }); it('removes the extra top margin when Thoughts follows a tool', () => { - render(); + render( + , + ); const row = screen .getByRole('button', { name: 'Thoughts' }) @@ -69,9 +76,27 @@ describe('ReasoningCompact', () => { /** Collapsed is the default whenever thoughts are hidden, and a streaming * THINK part re-renders on every delta, so keeping the whole text mounted * behind the invisible panel cost layout work for nothing. */ - render(); + render( + , + ); expect(screen.getByRole('button', { name: 'Thoughts' })).toBeInTheDocument(); expect(screen.queryByText('A long stream of reasoning')).not.toBeInTheDocument(); }); + + it('opens from the host preference rather than the app store', () => { + render( + , + ); + + expect(screen.getByText('A long stream of reasoning')).toBeInTheDocument(); + }); }); diff --git a/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx b/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx index a72b52d9c8..7c7a107ce7 100644 --- a/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx +++ b/client/src/components/Chat/Messages/Content/ToolCallGroup.tsx @@ -672,6 +672,7 @@ export default function ToolCallGroup({ key={`reasoning-${idx}`} reasoning={reasoning} label={label} + showThinking={showThinking} isAfterTool={isAfterTool} isStreaming={streaming} />