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}
/>