Skip to content

Commit 8ca8343

Browse files
committed
Fix thinking block collapse/expansion
1 parent 35d77a7 commit 8ca8343

File tree

5 files changed

+38
-70
lines changed

5 files changed

+38
-70
lines changed

cli/src/chat.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ export const Chat = ({
286286
): ContentBlock[] => {
287287
let foundTarget = false
288288
const result = blocks.map((block) => {
289-
// Handle thinking blocks (grouped text blocks)
289+
// Handle thinking blocks - just match by thinkingId
290290
if (block.type === 'text' && block.thinkingId === id) {
291291
foundTarget = true
292292
const wasCollapsed = block.isCollapsed ?? false
@@ -330,7 +330,7 @@ export const Chat = ({
330330
}
331331
}
332332

333-
// Recursively update nested blocks
333+
// Recursively update nested blocks inside agent blocks
334334
if (block.type === 'agent' && block.blocks) {
335335
const updatedBlocks = updateBlocksRecursively(block.blocks)
336336
// Only create new block if nested blocks actually changed

cli/src/components/blocks/thinking-block.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ const NESTED_WIDTH_OFFSET = 10
1010

1111
interface ThinkingBlockProps {
1212
blocks: Extract<ContentBlock, { type: 'text' }>[]
13-
keyPrefix: string
14-
startIndex: number
1513
onToggleCollapsed: (id: string) => void
1614
availableWidth: number
1715
isNested: boolean
@@ -20,28 +18,28 @@ interface ThinkingBlockProps {
2018
export const ThinkingBlock = memo(
2119
({
2220
blocks,
23-
keyPrefix,
24-
startIndex,
2521
onToggleCollapsed,
2622
availableWidth,
2723
isNested,
2824
}: ThinkingBlockProps) => {
29-
const thinkingId = `${keyPrefix}-thinking-${startIndex}`
25+
const firstBlock = blocks[0]
26+
const thinkingId = firstBlock?.thinkingId
3027
const combinedContent = blocks
3128
.map((b) => b.content)
3229
.join('')
3330
.trim()
3431

35-
const firstBlock = blocks[0]
3632
const isCollapsed = firstBlock?.isCollapsed ?? true
3733
const offset = isNested ? NESTED_WIDTH_OFFSET : WIDTH_OFFSET
3834
const availWidth = Math.max(10, availableWidth - offset)
3935

4036
const handleToggle = useCallback(() => {
41-
onToggleCollapsed(thinkingId)
37+
if (thinkingId) {
38+
onToggleCollapsed(thinkingId)
39+
}
4240
}, [onToggleCollapsed, thinkingId])
4341

44-
if (!combinedContent) {
42+
if (!combinedContent || !thinkingId) {
4543
return null
4644
}
4745

cli/src/components/message-block.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,8 @@ const AgentBody = memo(
421421

422422
nodes.push(
423423
<ThinkingBlock
424-
key={`${keyPrefix}-thinking-${start}`}
424+
key={reasoningBlocks[0]?.thinkingId ?? `${keyPrefix}-thinking-${start}`}
425425
blocks={reasoningBlocks}
426-
keyPrefix={keyPrefix}
427-
startIndex={start}
428426
onToggleCollapsed={onToggleCollapsed}
429427
availableWidth={availableWidth}
430428
isNested={true}
@@ -1234,10 +1232,8 @@ const BlocksRenderer = memo(
12341232

12351233
nodes.push(
12361234
<ThinkingBlock
1237-
key={`${messageId}-thinking-${start}`}
1235+
key={reasoningBlocks[0]?.thinkingId ?? `${messageId}-thinking-${start}`}
12381236
blocks={reasoningBlocks}
1239-
keyPrefix={messageId}
1240-
startIndex={start}
12411237
onToggleCollapsed={onToggleCollapsed}
12421238
availableWidth={availableWidth}
12431239
isNested={false}

cli/src/components/thinking.tsx

Lines changed: 18 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -44,70 +44,35 @@ export const Thinking = memo(
4444
}}
4545
onClick={onToggle}
4646
>
47+
<text style={{ fg: theme.foreground }}>
48+
<span></span>
49+
<span attributes={TextAttributes.BOLD}>Thinking</span>
50+
</text>
4751
{isCollapsed ? (
4852
lines.length > 0 && (
49-
<box
50-
style={{
51-
flexDirection: 'row',
52-
gap: 0,
53-
alignItems: 'stretch',
54-
marginTop: 0,
55-
}}
56-
>
57-
<box
58-
style={{
59-
width: 1,
60-
backgroundColor: theme.muted,
61-
marginTop: 0,
62-
marginBottom: 0,
63-
}}
64-
/>
65-
<box
66-
style={{
67-
paddingLeft: 1,
68-
flexGrow: 1,
69-
}}
70-
>
71-
<text
72-
style={{
73-
wrapMode: 'word',
74-
fg: theme.muted,
75-
}}
76-
attributes={TextAttributes.ITALIC}
77-
>
78-
{hasMore ? '...' + lines.join(' ') : lines.join(' ')}
79-
</text>
80-
</box>
81-
</box>
82-
)
83-
) : (
84-
<box
85-
style={{
86-
flexDirection: 'row',
87-
gap: 0,
88-
alignItems: 'stretch',
89-
marginTop: 0,
90-
}}
91-
>
92-
<box
93-
style={{
94-
width: 1,
95-
backgroundColor: theme.muted,
96-
marginTop: 0,
97-
marginBottom: 0,
98-
}}
99-
/>
100-
<box style={{ paddingLeft: 1, flexGrow: 1 }}>
53+
<box style={{ paddingLeft: 2 }}>
10154
<text
10255
style={{
10356
wrapMode: 'word',
10457
fg: theme.muted,
10558
}}
10659
attributes={TextAttributes.ITALIC}
10760
>
108-
{content}
61+
{hasMore ? '...' + lines.join(' ') : lines.join(' ')}
10962
</text>
11063
</box>
64+
)
65+
) : (
66+
<box style={{ paddingLeft: 2 }}>
67+
<text
68+
style={{
69+
wrapMode: 'word',
70+
fg: theme.muted,
71+
}}
72+
attributes={TextAttributes.ITALIC}
73+
>
74+
{content}
75+
</text>
11176
</box>
11277
)}
11378
</Button>

cli/src/utils/block-operations.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import type {
1313
} from '../types/chat'
1414
import { logger } from './logger'
1515

16+
let thinkingIdCounter = 0
17+
const generateThinkingId = (): string => {
18+
thinkingIdCounter++
19+
return `thinking-${thinkingIdCounter}`
20+
}
21+
1622
type AgentTextUpdate =
1723
| { type: 'text'; mode: 'append'; content: string }
1824
| { type: 'text'; mode: 'replace'; content: string }
@@ -91,12 +97,14 @@ const isOpenThinkingBlock = (block: ContentBlock | undefined): boolean => {
9197
const createReasoningBlock = (
9298
content: string,
9399
thinkingOpen: boolean,
100+
thinkingId: string,
94101
): TextContentBlock => ({
95102
type: 'text',
96103
content,
97104
textType: 'reasoning',
98105
isCollapsed: true,
99106
thinkingOpen,
107+
thinkingId,
100108
})
101109

102110
/**
@@ -242,7 +250,7 @@ const appendTextWithThinkParsingToBlocks = (
242250
const thinkingOpen =
243251
isLastSegment && !textToParse.endsWith(THINK_CLOSE_TAG)
244252
if (thinkingOpen) {
245-
nextBlocks.push(createReasoningBlock(segment.content, thinkingOpen))
253+
nextBlocks.push(createReasoningBlock(segment.content, thinkingOpen, generateThinkingId()))
246254
}
247255
} else {
248256
const prevBlock = nextBlocks[nextBlocks.length - 1]
@@ -295,6 +303,7 @@ export const appendTextToRootStream = (
295303
content: delta.text,
296304
textType: 'reasoning',
297305
isCollapsed: true,
306+
thinkingId: generateThinkingId(),
298307
}
299308

300309
return [...nextBlocks, newBlock]

0 commit comments

Comments
 (0)