Skip to content

feat(cli): show full reasoning content when expanding thinking blocks during streaming - #6678

Merged
wenshao merged 2 commits into
QwenLM:mainfrom
huww98:feat/thinking-expanded-streaming
Jul 11, 2026
Merged

feat(cli): show full reasoning content when expanding thinking blocks during streaming#6678
wenshao merged 2 commits into
QwenLM:mainfrom
huww98:feat/thinking-expanded-streaming

Conversation

@huww98

@huww98 huww98 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

When Alt+T (option+t on macOS) expands thinking blocks during streaming, the reasoning content now renders via MarkdownDisplay (same path as assistant messages) instead of the hardcoded 4-line tail preview. This restores the pre-collapsible-feature behavior where reasoning streams in full, bounded only by viewport height. The change also extracts a shared ThinkBody component to deduplicate content rendering logic between ThinkMessage (head block) and ThinkMessageContent (continuation blocks).

Why it's needed

The collapsible thinking blocks feature (introduced in #4598) replaced the full streaming display with a 4-line tail preview. When users expand thinking via Alt+T during streaming, they still only see the last 4 lines — the full reasoning only appears after the block commits. This makes it impossible to follow the model's chain of thought in real-time when expanded, which is the primary use case for expanding thinking blocks.

Reviewer Test Plan

How to verify

  1. Start a session that triggers extended thinking (e.g. a complex code analysis task)
  2. While the model is still thinking (streaming), press Alt+T (option+t on macOS) to expand
  3. Confirm that the full reasoning content streams in real-time (not just the last 4 lines)
  4. Confirm that without Alt+T, the collapsed 4-line tail preview still works as before
  5. Confirm that after the thinking block commits, expand/collapse behavior is unchanged
  6. For long reasoning (>16K chars), confirm that continuation blocks (gemini_thought_content) also expand during streaming

Evidence (Before & After)

Before: Alt+T during streaming still shows only the last 4 visual lines of reasoning via tailVisualLines + <Text wrap="truncate">.

After: Alt+T during streaming renders full reasoning via MarkdownDisplay with isPending=true and viewport-bounded height, matching the assistant message streaming behavior.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

Unit tests only. TUI manual verification needed.

Risk & Scope

  • Main risk or tradeoff: Rendering full streaming reasoning via MarkdownDisplay could cause scroll-to-top lock on very long reasoning if the content exceeds viewport height. However, availableTerminalHeight is passed through, so MarkdownDisplay's pendingRenderedBudget mechanism still bounds the rendered height — same safety net as assistant message streaming.
  • Not validated / out of scope: TUI manual testing on Windows/Linux, very long reasoning edge cases
  • Breaking changes / migration notes: None

Linked Issues

中文说明

本 PR 做了什么

当 Alt+T(macOS 上为 option+t)在流式输出期间展开推理块时,推理内容现在通过 MarkdownDisplay 渲染(与普通助手消息相同的路径),而不是硬编码的 4 行尾部预览。这恢复了折叠功能引入前的行为:推理内容完整流式输出,仅受视口高度限制。同时提取了一个共享的 ThinkBody 组件,消除 ThinkMessage(头部块)和 ThinkMessageContent(续行块)之间内容渲染逻辑的重复。

为什么需要

可折叠推理块功能(#4598 引入)将完整流式显示替换为 4 行尾部预览。当用户在流式输出期间通过 Alt+T 展开推理时,仍然只能看到最后 4 行——完整推理要等块提交后才出现。这使得在展开状态下无法实时跟踪模型的思维链,而跟踪思维链恰恰是展开推理块的主要用途。

审阅者测试计划

如何验证

  1. 启动一个会触发扩展思考的会话(例如复杂的代码分析任务)
  2. 在模型仍在思考(流式输出)时,按 Alt+T(macOS 上为 option+t)展开
  3. 确认完整推理内容实时流式显示(不仅仅是最后 4 行)
  4. 确认不按 Alt+T 时,折叠的 4 行尾部预览仍按原有方式工作
  5. 确认推理块提交后,展开/折叠行为不变
  6. 对于超长推理(>16K 字符),确认续行块(gemini_thought_content)在流式输出时也能展开

前后对比

之前:流式输出期间按 Alt+T 仍然只显示最后 4 行视觉行,通过 tailVisualLines + <Text wrap="truncate"> 实现。

之后:流式输出期间按 Alt+T 通过 MarkdownDisplay 渲染完整推理,传入 isPending=true 和视口限制高度,与助手消息流式行为一致。

测试平台

系统 状态
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

风险与范围

  • 主要风险/权衡:通过 MarkdownDisplay 渲染完整流式推理可能导致超长推理时的 scroll-to-top lock。但 availableTerminalHeight 会透传,MarkdownDisplay 的 pendingRenderedBudget 机制仍会限制渲染高度——与助手消息流式输出相同的安全措施。
  • 未验证/不在范围内:Windows/Linux 上的 TUI 手动测试,超长推理边界情况
  • 破坏性变更/迁移说明:无

… during streaming

When Alt+T (option+t on macOS) expands thinking blocks, the streaming
reasoning now renders via MarkdownDisplay instead of the 4-line tail
preview. This matches the pre-collapsible-feature behavior where
reasoning content streamed in full (bounded by viewport height).

Also extracts a shared ThinkBody component to deduplicate the content
rendering logic between ThinkMessage (head block) and
ThinkMessageContent (continuation blocks).
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR @huww98!

Template looks good ✓

Problem: This is an observed UX gap — when Alt+T is pressed during streaming, expanded=true but the isPending branch unconditionally renders the 4-line tail preview, ignoring the expanded state. No linked issue, but the behavior is verifiable directly from the code path: ThinkMessage hits the if (isPending) branch regardless of expanded.

Direction: Aligned. Thinking/reasoning display is a core TUI feature. Claude Code's CHANGELOG shows extensive work on thinking display (thinking duration, streaming improvements, disabled.display fixes), confirming this is a relevant area. Expanding reasoning during streaming to follow the chain of thought in real-time is a clear user benefit.

Size: Not applicable — changes are in packages/cli/src/ui/components/ (UI layer, not core infrastructure). 152 production lines (additions + deletions in ConversationMessages.tsx), 55 test lines.

Approach: The scope feels right. Extracting ThinkBody to deduplicate the tail-preview and MarkdownDisplay logic between ThinkMessage and ThinkMessageContent is a natural refactor that falls out of fixing the bug — the same rendering logic now needs to branch on expanded in both places. The ThinkMessage label/icon unification (merging the separate isPending and committed branches into one) is clean. One thing to watch: passing isPending={true} to MarkdownDisplay during expanded streaming is new behavior (previously only isPending={false} was ever passed for committed content) — worth confirming the pending rendering style looks right for reasoning content.

Moving on to code review. 🔍

中文说明

感谢贡献 @huww98

模板完整 ✓

问题:这是一个可观测的 UX 缺陷——当流式输出期间按下 Alt+T 时,expanded=trueisPending 分支无条件渲染 4 行尾部预览,忽略了展开状态。没有关联的 issue,但行为可以直接从代码路径验证:ThinkMessage 无论 expanded 值如何都会进入 if (isPending) 分支。

方向:对齐。推理/思考显示是 TUI 的核心功能。Claude Code 的 CHANGELOG 中有大量关于 thinking 显示的工作(思考时长、流式改进、disabled.display 修复),确认这是相关领域。在流式输出期间展开推理以实时跟踪思维链,对用户有明确价值。

规模:不适用——改动在 packages/cli/src/ui/components/(UI 层,非核心基础设施)。152 行生产代码(ConversationMessages.tsx 的增删合计),55 行测试代码。

方案:范围合理。提取 ThinkBody 以消除 ThinkMessageThinkMessageContent 之间尾部预览和 MarkdownDisplay 逻辑的重复,是修复 bug 的自然伴随——两处现在都需要根据 expanded 分支渲染。ThinkMessage 的标签/图标统一(合并独立的 pending 和已完成分支)也很干净。需要注意的是:展开流式时向 MarkdownDisplay 传入 isPending={true} 是新行为(之前只在已完成内容时传 isPending={false})——值得确认推理内容的 pending 渲染样式是否正确。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal (before reading the diff): The ThinkMessage and ThinkMessageContent components both have an isPending branch that renders only the 4-line tail preview, ignoring the expanded prop. To fix this, I'd modify both components to check expanded within the isPending branch and render MarkdownDisplay when expanded, then extract a shared component to deduplicate the tail-preview/MarkdownDisplay logic.

Comparison with the PR: The PR takes exactly this approach. ThinkBody cleanly handles all four state combinations (pending×expanded → MarkdownDisplay, pending×collapsed → tail preview, committed×expanded → MarkdownDisplay, committed×collapsed → null). The ThinkMessage label/icon unification (merging the separate isPending and committed rendering paths into one) is well-executed and preserves behavior.

Correctness: No bugs found. The prop forwarding (availableTerminalHeight, contentWidth - 2, textColor) is correct. The ThinkMessageContent simplification to a direct ThinkBody delegation is clean. One note: passing isPending={true} to MarkdownDisplay during expanded streaming is new (previously only false was passed for committed content) — the author flagged this in the risk section, and pendingRenderedBudget should bound height correctly.

Reuse check: MarkdownDisplay is already the shared component for assistant message rendering — reusing it for expanded thinking is the right call. No new utilities added. ✓

AGENTS.md conventions: No violations. No any types, correct type usage, no unnecessary abstractions.

Tests

Unit Tests (14/14 passed)

 ✓ src/ui/components/messages/ConversationMessages.test.tsx (14 tests) 71ms

 Test Files  1 passed (1)
      Tests  14 passed (14)

New tests cover the key behaviors:

  • ThinkMessage pending + expanded → all content lines visible ✓
  • ThinkMessage pending + collapsed → only tail line visible ✓
  • ThinkMessageContent pending + expanded → all content lines visible ✓

TypeScript Typecheck

Clean — tsc --noEmit passes with no errors.

TUI Real-Scenario Test

Could not verify the Alt+T expand behavior. The available model (qwen3.7-max) does not produce extended thinking blocks, so the thinking UI never appeared during testing. The PR author also noted "TUI manual verification needed" for this reason.

Session capture (default model, no thinking blocks produced):

   ▄▄▄▄▄▄  ▄▄     ▄▄ ▄▄▄▄▄▄▄ ▄▄▄    ▄▄   ┌──────────────────────────────────────────────────────────┐
  ██╔═══██╗██║    ██║██╔════╝████╗  ██║  │ >_ Qwen Code (v0.19.8)                                   │
  ██║   ██║██║ █╗ ██║█████╗  ██╔██╗ ██║  │                                                          │
  ██║▄▄ ██║██║███╗██║██╔══╝  ██║╚██╗██║  │ API Key | qwen3.7-max (/model to change)                 │
  ╚██████╔╝╚███╔███╔╝███████╗██║ ╚████║  │ ~/actions-runner-3/_work/qwen-code/qwen-code             │
   ╚══▀▀═╝  ╚══╝╚══╝ ╚══════╝╚═╝  ╚═══╝  └──────────────────────────────────────────────────────────┘

Response rendered directly without thinking blocks — no Alt+T test possible with this model.

This is not a failure of the PR — it's a limitation of the test environment. The unit tests verify the rendering logic directly, and the code review confirms correctness.

中文说明

代码审查

独立方案(阅读 diff 前):ThinkMessageThinkMessageContentisPending 分支只渲染 4 行尾部预览,忽略了 expanded prop。修复方案是在两个组件的 isPending 分支中检查 expanded,展开时通过 MarkdownDisplay 渲染,然后提取共享组件消除重复。

与 PR 对比: PR 采用了完全相同的方案。ThinkBody 干净地处理了所有四种状态组合。ThinkMessage 的标签/图标统一(合并独立的 pending 和已完成渲染路径)执行良好,保留了原有行为。

正确性: 未发现 bug。Props 转发正确。ThinkMessageContent 简化为直接委托 ThinkBody 是干净的。注意:展开流式时向 MarkdownDisplay 传入 isPending={true} 是新行为——作者在风险部分提到了这一点,pendingRenderedBudget 应正确限制高度。

复用检查: MarkdownDisplay 已经是助手消息渲染的共享组件——复用它来展开推理是正确的选择。未添加新工具。✓

测试

单元测试(14/14 通过)

全部通过,新增测试覆盖了关键行为。

TypeScript 类型检查

通过,无错误。

TUI 真实场景测试

无法验证 Alt+T 展开行为。 可用模型(qwen3.7-max)不产生扩展推理块,测试期间思考 UI 从未出现。PR 作者也注明了"TUI manual verification needed"。这不是 PR 的失败——是测试环境的限制。单元测试直接验证了渲染逻辑,代码审查确认了正确性。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Re-verified 2026-07-11 — no code changes since prior triage (only a main merge). 14/14 tests still pass, typecheck clean, approval intact.


This is a clean, focused PR that solves a real problem. The isPending branch ignoring expanded is a clear gap in the thinking block UI — pressing Alt+T during streaming should show full reasoning, not just the last 4 lines.

The implementation matches the independent proposal: extract ThinkBody to deduplicate the tail-preview/MarkdownDisplay logic, then modify the rendering paths to branch on expanded within the pending state. The label/icon unification in ThinkMessage is a natural cleanup that falls out of merging the two separate rendering paths — not a drive-by refactor.

All 14 unit tests pass, typecheck is clean, and the new tests cover the key behaviors (pending+expanded shows full content, pending+collapsed shows tail preview). The only gap is TUI manual verification — the available test model doesn't produce extended thinking blocks. This is an environment limitation, not a code concern.

The PR is 2 files, 152 production lines, and does exactly one thing.

中文说明

2026-07-11 重新验证 — 自上次审查以来代码无变化(仅合并了 main)。14/14 测试仍通过,类型检查干净,批准有效。


这是一个干净、聚焦的 PR,解决了一个真实问题。isPending 分支忽略 expanded 是思考块 UI 中的一个明确缺陷——流式输出期间按 Alt+T 应该显示完整推理,而不是只有最后 4 行。

实现与独立方案一致:提取 ThinkBody 消除重复,在 pending 状态下根据 expanded 分支渲染。14 个单元测试全部通过,类型检查干净。唯一的缺口是 TUI 手动验证——测试环境中的模型不产生扩展推理块,这是环境限制。

PR 改动 2 个文件,152 行生产代码,只做一件事。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Suggestions — commit ae73504

File Issue Suggested fix
ConversationMessages.test.tsx:114-132, 188-205 Test fixtures too weak to catch the regression. Both pending+expanded tests use exactly 4 lines, but MAX_STREAMING_THINKING_VISUAL_LINES = 4. The old buggy tail preview would show all 4 lines too, so these tests pass on both old and new code. Use 10+ lines (like the pending+collapsed test with 20 lines) and assert early lines appear when expanded.
ConversationMessages.tsx:367-369 Collapse hint hidden during pending+expanded. collapseHint is gated on !isPending && expanded, so when expanded during streaming there's no hint for how to collapse. The toggle works but is undiscoverable. Change condition to expanded so the hint shows whenever expanded: const collapseHint = expanded ? \ ${t('({{keyHint}} to collapse)', { keyHint: toggleKeyHint })}` : '';`
ConversationMessages.test.tsx:148 ThinkMessageContent pending+collapsed test has weak assertion. Only asserts output.not.toBe('') — doesn't verify tail-line truncation. A regression removing truncation would go undetected. Use 20 lines of input and assert last line present, early lines absent (matching the ThinkMessage counterpart at line 134).

— qwen3.7-max via Qwen Code /review

@huww98

huww98 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

This does not work when the reasoning length exceed one screen.

@huww98
huww98 marked this pull request as draft July 10, 2026 17:59
@wenshao
wenshao marked this pull request as ready for review July 11, 2026 01:08
@wenshao

wenshao commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Local verification report (maintainer)

I built and ran this PR locally on macOS and drove the real ThinkMessage / ThinkMessageContent components (via ink-testing-library) against the actual main baseline to capture true before/after behavior. Summary below; details and evidence follow.

Verdict: The core fix is correct, safe, and well-tested — but the reproduction confirms @huww98's own comment: for a streaming reasoning chunk taller than one screen, the expanded view is pinned to the head and no longer follows the newest tokens. Recommend deciding on that tradeoff before merge (details in §3).

1. What I ran

Check Result
vitest run ConversationMessages.test.tsx 14/14 pass (incl. the 3 new cases)
CLI package typecheck of the changed file ✅ clean (pre-existing errors in src/serve/** are unrelated to this PR)
Real component render — main vs PR, identical props ✅ captured, see §2 / §3
Viewport safety net (60-line reasoning, availableTerminalHeight=12) ✅ bounded to 10 rendered lines — no unbounded render

2. Verified — the fix works (reasoning that fits ~one viewport)

Rendering the head block with isPending=true, expanded=true and a 7-line reasoning payload, identical props on both branches:

BEFORE (main) — Alt+T during streaming        AFTER (this PR) — Alt+T during streaming
∵ Thinking…                                    ∵ Thinking…
  Line 4: …keeps the diff smallest.              Line 1: Reading the request…
  Line 5: …tests I will need to add.             Line 2: Identifying the files…
  Line 6: …viewport height bounds.               Line 3: Considering two approaches…
  Line 7: …shared-component extraction.          Line 4: …keeps the diff smallest.
                                                 Line 5: …tests I will need to add.
  ▲ only the last 4 lines                        Line 6: …viewport height bounds.
                                                 Line 7: …shared-component extraction.
                                                 ▲ full reasoning, viewport-bounded

Before vs after — Alt+T during streaming

Confirmed unchanged (no regressions): collapsed streaming still shows the 4-line tail preview; committed expand/collapse (label, option+t to collapse hint, full markdown) is identical to main; the continuation block (gemini_thought_content) behaves the same as the head block.

3. Reproduced — @huww98's concern (reasoning taller than one screen)

MarkdownDisplay bounds a pending block by slicing from the top (allLines.slice(0, keptLines)), which is safe for assistant text because useGeminiStream incrementally commits earlier lines to scrollback. Streaming reasoning is only committed at the STREAM_PENDING_ITEM_MAX_CHARS = 16_384 chunk boundary, so within one pending chunk, expanding shows the head of the chunk and the newest tokens stay off-screen until it commits. I reproduced this directly — a 60-line pending reasoning payload rendered lines 01–10 (the head), not the tail:

[THINK pending+expanded, availableTerminalHeight=12] rendered 10 lines: first=line 01, last=line 10
[THINK pending+collapsed, same height]               rendered  4 lines: the last 4 (tail)

The subtle part: the collapsed 4-line preview follows the tail (latest reasoning), while the expanded view is pinned to the head (oldest). So for long streaming reasoning, expanding currently shows older content than the collapsed preview — the opposite of what a user pressing Alt+T to "follow along" expects.

Long streaming reasoning — collapsed follows the tail, expanded is pinned to the head

This is exactly what @huww98 flagged ("does not work when the reasoning length exceed one screen"). It is not a crash or a safety issue — the render stays viewport-bounded — but it does mean the PR's stated goal ("follow the model's chain of thought in real-time when expanded") is only fully met for reasoning up to ~one viewport.

4. Assessment & recommendation

  • The refactor (shared ThinkBody, label/icon unification) is clean and correct; all tests and typecheck pass.
  • For the common case (reasoning ≤ one screen) this is a clear, unambiguous improvement over the 4-line tail.
  • For long streaming reasoning, expanded is head-pinned. A follow-up could make the pending, expanded branch slice from the tail (mirror the collapsed preview) so expanding follows the newest reasoning while staying viewport-bounded.

Recommendation: either (a) land this as an incremental improvement and track the head-vs-tail follow-up as a separate issue, or (b) address tail-follow for the pending-expanded branch in this PR before merge. I lean (a) — it strictly improves the sub-viewport case and introduces no safety regression — provided we open the follow-up.

中文说明(点击展开)

本地验证报告(维护者)

我在本地(macOS)构建并运行了本 PR,通过 ink-testing-library 驱动真实的 ThinkMessage / ThinkMessageContent 组件,并与 main 基线用完全相同的 props 对比,捕获真实的前后行为。

结论: 核心修复正确、安全、测试充分——但复现确认了 @huww98 自己的评论:当单个流式推理块高度超过一屏时,展开后视图会被钉在“头部”,不再跟随最新的推理内容。 建议合并前先就这个取舍做决定(详见第 3 节)。

1. 我运行了什么

检查项 结果
vitest run ConversationMessages.test.tsx 14/14 通过(含 3 个新增用例)
改动文件的 CLI 类型检查 ✅ 干净(src/serve/** 中的报错是既有的、与本 PR 无关)
真实组件渲染——main vs PR,相同 props ✅ 已捕获,见第 2/3 节
视口安全网(60 行推理,availableTerminalHeight=12 ✅ 限制为 10 行渲染——不会无界渲染

2. 已验证——修复生效(推理不超过约一屏时)

isPending=true, expanded=true 渲染头部块,两个分支使用相同 props:main 只显示最后 4 行;本 PR 显示完整的 7 行推理(视口内有界)。见上方英文代码块与截图。

无回归确认:折叠态流式仍显示 4 行尾部预览;已提交块的展开/折叠(标签、option+t to collapse 提示、完整 markdown)与 main 完全一致;续行块(gemini_thought_content)行为与头部块一致。

3. 已复现——@huww98 的顾虑(推理超过一屏时)

MarkdownDisplaypending 块的限高是从顶部切片allLines.slice(0, keptLines))。对助手文本这是安全的,因为 useGeminiStream 会把较早的行增量提交到滚动区;但流式推理只在 STREAM_PENDING_ITEM_MAX_CHARS = 16_384 的分块边界才提交,所以在单个 pending 块内展开时,只显示该块的头部,最新的 token 在块提交前一直不可见。我直接复现了这一点——60 行的 pending 推理渲染出的是第 01–10 行(头部),而非尾部:

[THINK pending+expanded, availableTerminalHeight=12] 渲染 10 行:首=line 01,尾=line 10
[THINK pending+collapsed, 同高度]                    渲染  4 行:最后 4 行(尾部)

微妙之处:折叠的 4 行预览跟随尾部(最新推理),而展开视图却被钉在头部(最旧)。因此对于长流式推理,展开反而显示比折叠预览更的内容——与用户按 Alt+T “跟读”的预期相反。这正是 @huww98 所指出的问题。它不是崩溃、也不是安全问题(渲染始终视口内有界),但意味着 PR 声称的目标(“展开时实时跟踪思维链”)目前只在推理不超过约一屏时完全达成。

4. 评估与建议

  • 重构(共享 ThinkBody、标签/图标统一)干净且正确;所有测试与类型检查通过。
  • 常见情形(推理 ≤ 一屏)相比 4 行尾部是明确改进。
  • 长流式推理时展开被钉在头部。后续可让 pending + expanded 分支改为从尾部切片(与折叠预览一致),使展开跟随最新推理,同时保持视口内有界。

建议: 要么 (a) 作为增量改进先合入,并把“头/尾跟随”作为独立 issue 跟踪;要么 (b) 在本 PR 内先处理 pending-expanded 分支的尾部跟随。我倾向 (a)——它严格改进了不超一屏的情形,且无安全回归——前提是开一个后续跟进 issue。


Verification performed locally by the maintainer against main. Tests: 14/14. Screenshots are terminal renders of the real components with identical props on each branch.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blockers. Suggestions are inline.

expect(output).toContain('Thought for');
expect(output).toContain('2m 5s');
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The test uses only 4 lines of text, which equals MAX_STREAMING_THINKING_VISUAL_LINES. Both the tail-lines path and the MarkdownDisplay path would show all 4 lines, so this test passes regardless of which branch executes. Use 10+ lines and assert that early lines are present (confirming the full-content path runs) to make the test branch-discriminating.

— qwen3.7-max via Qwen Code /review

return lines.slice(-maxLines).join('\n');
}

const ThinkBody: React.FC<{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] ThinkBody defines its props as an inline React.FC<{...}> type literal. Every other component in this file uses a separately declared interface XxxProps. Consider extracting a ThinkBodyProps interface for consistency — or reusing ThinkMessageContentProps directly, since the shapes are identical.

— qwen3.7-max via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blockers. Suggestions are inline.

? `${t('Thought for')} ${formatDuration(durationMs)}`
: `${t('Thinking')}…`;
const collapseHint =
!isPending && expanded

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The collapseHint is gated on !isPending && expanded, so when a user expands a streaming thinking block via Alt+T, the header shows only "Thinking..." with no "(Alt+T to collapse)" hint. The toggle still works, but the user has no visual affordance to re-collapse. When streaming finishes and isPending flips to false, the hint suddenly appears — inconsistent UX.

Suggested change
!isPending && expanded
const collapseHint =
expanded
? ` ${t('({{keyHint}} to collapse)', { keyHint: toggleKeyHint })}`
: '';

— qwen3.7-max via Qwen Code /review

@wenshao
wenshao added this pull request to the merge queue Jul 11, 2026
Merged via the queue into QwenLM:main with commit eff2a04 Jul 11, 2026
88 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants