Skip to content

feat: [TBB] render streaming thinking blocks in chat turns (Thinking Part 3)#157

Open
ethanyhou wants to merge 5 commits into
mainfrom
ethan/thinking-ui
Open

feat: [TBB] render streaming thinking blocks in chat turns (Thinking Part 3)#157
ethanyhou wants to merge 5 commits into
mainfrom
ethan/thinking-ui

Conversation

@ethanyhou
Copy link
Copy Markdown
Contributor

@ethanyhou ethanyhou commented May 8, 2026

Should be reviewed after: #156

Renders the model's thinking deltas in a collapsible banner above each assistant turn (Copilot and subagent), backed by the LSP plumbing added in the previous PR.

Test:

  1. Chat using Claude or GPT advance model and let the model think.

  2. On thinking, the spinner should rotate with thinking body appending (The subtitle is selectable, GPT model prefers it):

    • GPT: image
    • Claude: image
  3. The thinking block should auto collapse once thinking is finished but user can click to check the thinking content:

    • image
  4. Cancel an ongoing thinking:

    • image
  5. If you are lucky, sometimes the GPT model will think twice a time. This is a mock:

    • image

Adds the protocol surface for streaming model-thinking content from the language server:

- Thinking record + ThinkingTypeAdapter (tolerates the server's mixed wire shape for 	ext: string delta or array of fragments).
- ChatProgressValue.thinking field (with equals/hashCode/toString updates).
- thinking/generateTitle JSON request (GenerateThinkingTitleParams/Response, server interface, connection wrapper).
- Register ThinkingTypeAdapter.Factory in CopilotLauncherBuilder.

No behavior change yet; UI plumbing follows in a stacked PR.
@ethanyhou ethanyhou changed the title feat: render streaming thinking blocks in chat turns feat: [TBB] render streaming thinking blocks in chat turns (Thinking Part 3) May 8, 2026
@ethanyhou ethanyhou force-pushed the ethan/thinking-ui branch from 63c65c1 to a55b8af Compare May 8, 2026 14:37
Renders the model's thinking deltas in a collapsible banner above each assistant turn (Copilot and subagent), backed by the LSP plumbing added in the previous PR.

- ThinkingBlock: collapsible streaming banner (spinner -> generated title / cancelled), markdown body parsed into titled sections.
- ThinkingSection: gutter dot + bold title + markdown body for each parsed section.
- ThinkingTurnWidget: extends BaseTurnWidget, accumulates Thinking deltas, seals on first reply/agent round, fires thinking/generateTitle, and finalizes on cancel.
- BaseTurnWidget: onChatMessageCancelled hook (default no-op) so subclasses can react to cancel events.
- CopilotTurnWidget / SubagentTurnWidget / SubagentMessageBlock: re-parented onto ThinkingTurnWidget.
- ChatContentViewer: routes thinking deltas to the active turn, seals before reply/agent rounds, seals at WorkDoneProgressKind.end.
- ChatView: don't drop progress reports that carry only thinking content.
- Messages / messages.properties: NLS keys for the in-progress / cancelled / expand / collapse strings.
- dark.css / light.css: shared secondary-text color rule for the new ThinkingBlock selector.
@ethanyhou ethanyhou force-pushed the ethan/thinking-ui branch from a55b8af to f7e9bd0 Compare May 8, 2026 15:08
@jdneo
Copy link
Copy Markdown
Member

jdneo commented May 10, 2026

Why not directly merge into main? Then we can roll out it first in nightly

@ethanyhou
Copy link
Copy Markdown
Contributor Author

ethanyhou commented May 10, 2026

@jdneo, because this PR is based on the branch ethan/thinking-lsp, if I merge it to main, the branch ethan/thinking-lsp's change in PR #156 will also be included in this PR and hard for you to review. That’s why I noted in the PR description that this PR should be reviewed after #156, since once #156 is merged, the target branch will automatically switch to main.

Base automatically changed from ethan/thinking-lsp to main May 11, 2026 01:57
@jdneo
Copy link
Copy Markdown
Member

jdneo commented May 11, 2026

ethanyho

I see. #156 is merged, pls update the pr to resolve conflict

Co-authored-by: Copilot <copilot@github.com>
Copilot AI review requested due to automatic review settings May 11, 2026 09:01
@ethanyhou
Copy link
Copy Markdown
Contributor Author

@jdneo Conflict is resolved.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds UI support in the chat view to render streaming “thinking” deltas from the language server as collapsible banners on assistant/subagent turns, leveraging the LSP protocol surface introduced in the prior PR.

Changes:

  • Introduces ThinkingBlock/ThinkingSection UI components and a ThinkingTurnWidget base class to manage streaming, sealing, and cancellation.
  • Wires thinking deltas into turn processing (ChatContentViewer, ChatView) and adds NLS + CSS styling for the new UI.
  • Updates Copilot/subagent turn widgets to use the new thinking-enabled base type.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ThinkingTurnWidget.java New base widget to accumulate thinking deltas, manage blocks, and seal/finalize with generated titles.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ThinkingBlock.java New collapsible “Thinking” banner UI with spinner, parsing into sections, and finalize/cancel visuals.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ThinkingSection.java New section widget (gutter + markdown body) used by ThinkingBlock during streaming.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CopilotTurnWidget.java Switches Copilot assistant turn to ThinkingTurnWidget base.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SubagentTurnWidget.java Switches subagent turn to ThinkingTurnWidget base.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SubagentMessageBlock.java Updates stored/returned subagent widget type to ThinkingTurnWidget.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatContentViewer.java Plumbs thinking deltas into turn rendering; seals thinking when reply/tool output begins and on turn end.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatView.java Avoids dropping “thinking-only” progress events by extending the empty-report guard.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/BaseTurnWidget.java Adds cancel hook (onChatMessageCancelled) and clarifies reset behavior relative to thinking/subagent blocks.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/messages.properties Adds localized strings for thinking banner titles/tooltips.
com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/Messages.java Adds NLS fields for the new thinking banner strings.
com.microsoft.copilot.eclipse.ui/css/light.css Extends secondary-text styling to thinking widgets in light theme.
com.microsoft.copilot.eclipse.ui/css/dark.css Extends secondary-text styling to thinking widgets in dark theme.

Comment on lines +185 to +187
if (hasRenderableOutput(value)) {
// Seal before appending the reply so the spinner stops and the title is fetched.
thinkingTurn.sealThinking();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Q:

the thinking will be sealed when WorkDoneProgressKind.end comes, why do we need this logic?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the mid-turn seal to kick off the title fetch and prevent subsequent thinking stream from being appended to the same block (a new block will be opened instead).

The WorkDoneProgressKind.end seal is a safety net for turns where the mid-turn seal never fired(ex. the model only produced thinking with no renderable output), so the block doesn't stay spinning forever.

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