Skip to content

feat(ui): add thinking ui to mothership#4254

Open
TheodoreSpeaks wants to merge 3 commits intodevfrom
feat/display-thinking
Open

feat(ui): add thinking ui to mothership#4254
TheodoreSpeaks wants to merge 3 commits intodevfrom
feat/display-thinking

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

@TheodoreSpeaks TheodoreSpeaks commented Apr 22, 2026

Summary

Added thinking blocks. This allows users to understand llm's thinking process and also let them be assured we're actually running stuff in the background when thinking is displayed.

Thinking blocks are only displayed after 3 seconds of thinking.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Tested with refresh, subagent thinking, long pauses, short pauses, aborts.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 22, 2026 3:17am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 22, 2026

PR Summary

Medium Risk
Touches core chat streaming/persistence and stop/cancel logic; incorrect ordering or missing endedAt stamping could regress message rendering or leave blocks/tool calls stuck as active.

Overview
Adds a new thinking/subagent_thinking content-block type and a ThinkingBlock UI component that renders collapsible reasoning panels (auto-shown only after ~3s, with "Thought for Ns" timing) both at the top level and inside agent groups.

Updates streaming + persistence to carry per-block timestamp/endedAt, flushes open thinking blocks before tool/subagent boundaries (and on abort), and stamps endedAt on stop/cancel so partial generations persist and reload in the correct order. Also tweaks auto-scroll to keep the viewport pinned during expand/collapse height animations.

Reviewed by Cursor Bugbot for commit 7f3b7ed. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

This PR introduces a collapsible thinking-block UI that surfaces LLM reasoning to users during and after streaming. Timestamps are threaded through the full content-block lifecycle — streaming context, persistence, and display — so elapsed time can be calculated and blocks shorter than 3 seconds can be suppressed as visual noise.

Confidence Score: 5/5

Safe to merge; only P2 style findings remain

All remaining findings are P2 (a stale comment that says "5s" while the constant is 3000 ms, and overflow-y-scroll vs overflow-y-auto). No logic errors, data-loss risks, or broken code paths were found. Timing propagation, flush ordering, and auto-scroll extension all look correct.

thinking-block.tsx — stale "5s" comment and overflow-y-scroll style choice

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/thinking-block/thinking-block.tsx New component; minor stale comment ("5s" vs 3 s constant) and prefer overflow-y-auto over overflow-y-scroll
apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx Correctly parses thinking/subagent_thinking blocks into segments and applies the 3 s filter before rendering ThinkingBlock
apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts Adds ensureThinkingBlock, stampBlockEnd helpers and timestamps thinking/tool/compaction/subagent lifecycle blocks correctly through the stream
apps/sim/hooks/use-auto-scroll.ts Adds animationstart listener that drives 500 ms RAF follow-scroll window for CSS height animations; cleanup is handled correctly
apps/sim/lib/copilot/request/go/stream.ts Flushes open thinking blocks at subagent lifecycle boundaries and on abort/error, preventing ordering or silent-drop issues
apps/sim/lib/copilot/chat/display-message.ts Correctly maps persisted lane+channel combinations to subagent_thinking/thinking/text content block types
apps/sim/lib/copilot/request/handlers/types.ts Adds stampBlockEnd helper and wires it into flushThinkingBlock/flushSubagentThinkingBlock to close open blocks before persisting
apps/sim/lib/copilot/chat/persisted-message.ts Propagates timestamp/endedAt through mapContentBlock and normalizeBlock for both canonical and legacy persisted blocks

Sequence Diagram

sequenceDiagram
    participant Stream as Stream (go/stream.ts)
    participant Handler as tool.ts / handlers
    participant Context as StreamingContext
    participant UseChat as use-chat.ts
    participant MsgContent as message-content.tsx
    participant ThinkBlock as ThinkingBlock

    Stream->>Context: text event (channel=thinking) → ensureThinkingBlock()
    Note over Context: currentThinkingBlock accumulates content + timestamp
    Stream->>Handler: tool or subagent lifecycle event
    Handler->>Context: flushThinkingBlock() — stampBlockEnd + push to contentBlocks
    UseChat->>UseChat: toRawPersistedContentBlockBody (type=text, channel=thinking)
    UseChat->>UseChat: withBlockTiming adds timestamp/endedAt
    UseChat-->>DB: persist contentBlocks with timing
    Note over DB: On reload
    DB-->>UseChat: PersistedContentBlock (lane, channel, timestamp, endedAt)
    UseChat->>MsgContent: toDisplayBlock → ContentBlockType.thinking
    MsgContent->>MsgContent: parseBlocks → ThinkingSegment (startedAt, endedAt)
    MsgContent->>MsgContent: elapsedMs ≤ 3000ms? → return null
    MsgContent->>ThinkBlock: render ThinkingBlock(isActive, isStreaming, startedAt, endedAt)
    ThinkBlock->>ThinkBlock: thresholdReached gate (3 s for active blocks)
    ThinkBlock->>ThinkBlock: rAF expand animation once threshold hit
Loading

Reviews (1): Last reviewed commit: "fix lint" | Re-trigger Greptile

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7f3b7ed. Configure here.


const stampBlockEnd = (block: ContentBlock | undefined, ts?: string) => {
if (block && block.endedAt === undefined) block.endedAt = toEventMs(ts)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Premature endedAt stamp breaks subagent end matching

Low Severity

The stampBlockEnd helper in ensureTextBlock and ensureThinkingBlock indiscriminately stamps endedAt on whatever the previous block is. When the previous block is a subagent marker, this sets a premature endedAt. Later, the subagent span-end handler's backward search for blocks matching b.endedAt === undefined fails to find the marker, so the subagent block retains an incorrect endedAt timestamp (time of the first content event rather than the actual subagent end time). The same issue exists in stream.ts. While parseBlocks doesn't currently use endedAt on subagent markers for display, the persisted timing data is inaccurate.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7f3b7ed. Configure here.

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.

1 participant