Conversation
Provider adapters already normalize thinking deltas to reasoning_text / reasoning_summary_text, but ingestion dropped them. Reasoning now rides the assistant message pipeline as an optional channel field: one segment slot per thread, buffered/streamed with the same delivery switch as assistant text, stamped with per-thread monotonic timestamps so live and reloaded order agree, and excluded from answer semantics (turn binding, checkpoints, titles, search, minimap). Web renders collapsible Thinking rows; mobile filters reasoning at derivation. Schema change ships as migration 044, idempotent for databases that predate it. Design debated with GPT-5.6 sol; implementation by GPT-5.6 sol via Codex CLI, Claude Opus 5, and Claude Fable 5. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the timeline
Claude Code 2.1.248+ runs SDK sessions in the redacted-thinking phase:
thinking deltas stream with empty text and only estimated_tokens, so the
reasoning pipeline had nothing to ingest. Pass thinking: { type:
"adaptive", display: "summarized" } (the SDK's --thinking-display
flag) to request API-side thinking summaries, skipped when the thread's
thinking toggle is off.
Debugged and fixed by Claude Fable 5 in Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Warning Your free Security trial is over. An organization admin can activate Security or dismiss this notice. Comment |
There was a problem hiding this comment.
Reviewed the web timeline changes for reasoning rows (MessagesTimeline.tsx, MessagesTimeline.logic.ts). The disclosure control matches the file's existing raw-button row pattern (TurnFoldTimelineRow), reasoning rows are correctly kept out of terminal-assistant meta, duration boundaries, minimap previews, and getItemType recycling buckets. One finding on the expanded thought body.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding in the web timeline fold logic; details inline.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding on the timeline fold derivation: reasoning entries now win the "first assistant entry stays visible" slot. Details inline.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding on the active-turn "Thinking" indicator. The two items flagged in earlier runs (turn-fold anchoring around a leading thought, and the missing break rule on the expanded thought body) are addressed in the current head.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Effect service conventions review: service definitions, layer wiring, dependency acquisition, and error modeling in this change look consistent with the repository conventions. One minor note on a contracts type that is now duplicated locally.
Posted via Macroscope — Effect Service Conventions
There was a problem hiding this comment.
UI consistency review of the web timeline changes. One finding on the new reasoning disclosure row; the earlier turn-fold, showThinking, and wrap-break-word findings look addressed in this head.
Posted via Macroscope — UI Consistency
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This is a substantial cross-cutting feature that adds persisted provider reasoning, new timeline UI, lifecycle handling, and recovery logic across server and clients. It also changes Claude and Codex provider behavior by enabling detailed reasoning summaries by default, making the product-default impact material. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
One finding in the web timeline: the new empty-completed-reasoning skip is applied in the row loop and in deriveTurnFolds, but not before work-entry grouping, so a dropped row can still split an adjacent tool group. Details inline.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
One finding on the new empty-reasoning filtering in MessagesTimeline.logic.ts.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7abafca. Configure here.
Codex otherwise emits empty reasoning items when no summary mode is configured. Request detailed summaries on turn/start so the reasoning transcript receives summary text deltas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Superseded by #11784 (feat(chat): show provider thinking traces), which landed on main. |

Provider reasoning output never reached any client. Ingestion forwarded only
assistant_text. It droppedreasoning_textandreasoning_summary_text, so Claude, Codex, and OpenCode all lost their reasoning.This implements the fix discussed in discussion #8625 and addresses open issue #5542.
What changed
Reasoning now rides the existing assistant message pipeline through an optional
channel: "reasoning"field on assistant messages. There is no parallel message type or second store. One burst of thinking becomes one message keyedreasoning:<threadId>:<turnId>:segment:<n>. Events without a turn ID useturnlessin the turn slot.Reasoning delivery follows the existing
enableLegacyTokenStreamingsetting. There is no new delivery mode. Per-thread monotonic timestamps keep live ordering and reload ordering identical.The web client nests each reasoning message under the turn's
Worked for Nsgroup as a collapsible row. A completed burst that took at least one second readsThought for Ns. A shorter burst readsThought.Reasoning is excluded from answer semantics. It never settles a turn, lands in a checkpoint, supplies a thread title, appears in search, or appears in the minimap.
Migration
044_ProjectionThreadMessagesChanneladds a nullablechannelcolumn toprojection_thread_messages. APRAGMA table_infocheck guards the alteration. This makes the migration idempotent, which means running it twice has the same effect as running it once.The Claude adapter now sends
thinking: { type: "adaptive", display: "summarized" }unless thinking is explicitly disabled. Recent Claude Code versions otherwise stream redacted thinking that carries token estimates and no text. This removes the--thinking-display summarizedlaunch-argument workaround described in #5542.Evidence
Before: the timeline on current
mainhas no reasoning row.After: the timeline on this branch has an expanded
Thought for 7.7srow.Demo video: https://youtu.be/VuzwmRg24uM
Surfaces
Entry points: Only passive rendering in the chat view applies. There is no action to mirror in Settings, the command palette, or a keybinding.
Clients: Web renders the rows. Desktop gets them by wrapping web. Mobile filters reasoning out during derivation because it has no reasoning UI yet.
Providers: Claude, Codex, and OpenCode already normalize thinking deltas to
reasoning_textandreasoning_summary_text. This change consumes both stream kinds. Cursor and Grok expose no reasoning stream, so there is nothing to show.Contracts: The optional
channelfield crosses the typed message, command, event, persistence, and snapshot contracts.Reverse states: Each row can be expanded and collapsed. There is no persisted one-way state.
Connection modes and version skew: The existing assistant message path serves local, remote/relay, and tunnel connections. Schema decoding strips the unknown
channelfield for older clients, so they render reasoning as ordinary assistant text instead of failing. An older server rolled back onto events carryingchannelstill replays and starts.Docs:
docs/user/reasoning.mdexplains the shipped behavior,docs/user/providers-claude.mdcovers Claude's adaptive summarized thinking, anddocs/internals/glossary.mddefines the channel.Verification
Claude is verified end to end in a real client. Codex and OpenCode use the same ingestion path, and tests cover both reasoning stream kinds. Neither provider was manually driven.
Tests: focused runs of
threadActivity.test.ts,CheckpointReactor.test.ts,ProjectionPipeline.test.ts,ProjectionSnapshotQuery.test.ts,ProviderCommandReactor.test.ts,ProviderRuntimeIngestion.test.ts,projector.test.ts,044_ProjectionThreadMessagesChannel.test.ts,ClaudeAdapter.test.ts,MessagesTimeline.logic.test.ts, andthreadReducer.test.ts, plus scoped typechecks for the touched packages. All passed.Known boundary
The Claude adapter's
content_block_starthandler still does not registerthinkingblocks, so thinking deltas still carry noitemId. This design does not need that ID because it keys reasoning bursts by thread, turn, and segment. I can fix this at the source if maintainers prefer.Scope and split option
This PR is larger than the usual one-concern ideal. It has 906 additions and 65 deletions across 32 files, with roughly half of the additions in tests. It is rebased on current
main.The change splits into three pieces: the two-line Claude
thinking.displayoption, the server pipeline, and the web rows. I will reshape or split it on request.Model: GPT-5.6 Sol. Harness: Codex, orchestrated from Claude Code.
Note
Show provider reasoning messages in the chat timeline
channel: "reasoning"discriminator to orchestration messages, persisted via migration 44 and threaded through the projection, projector, decider, and client reducercreatedAttimestamps are now strictly increasing per threadassistantMessageIdbinding, revert retention counting, thread title generation, and terminal assistant tracking across server and clientthinking: { type: "adaptive", display: "summarized" }by default; Codex turn-start params includesummary: "detailed"hasAssistantMessageForTurnandderiveTerminalAssistantMessageIdsnow skip reasoning messages — any code that assumed all assistant-role messages count toward a turn may need the sameisReasoningMessageguard; migration 44 adds a nullablechannelcolumn toprojection_thread_messagesMacroscope summarized 612deb2.
Note
Medium Risk
Touches orchestration ingestion, projection revert retention, checkpoints, and a DB migration; incorrect reasoning/answer separation could mis-bind turns or drop messages on revert, but behavior is heavily test-backed.
Overview
Adds first-class reasoning assistant messages via optional
channel: "reasoning", wired from providerreasoning_text/reasoning_summary_textthrough ingestion, events, SQLite projection (migration 044), and snapshots.Server ingestion segments reasoning per thread/turn (
reasoning:<thread>:<turn|turnless>:segment:n), honors buffered vs streaming like normal assistant text, finalizes segments at answers, tools, pauses, and turn/session boundaries, and uses monotonic per-thread message stamps. Reasoning is excluded from answer semantics: turn settlement, checkpointassistantMessageId, revert assistant fallback/counting, and thread-title context all skip it viaisReasoningMessage.Clients: Web shows collapsible “Thought” rows inside turn folds and filters empty completed reasoning from timeline grouping; mobile drops reasoning in
buildThreadFeed. Providers: Claude requests summarized adaptive thinking; Codex turn starts requestsummary: "detailed"so reasoning items carry text.Large regression test coverage for ingestion, projection revert, checkpoints, and timeline logic.
Reviewed by Cursor Bugbot for commit 612deb2. Bugbot is set up for automated code reviews on this repo. Configure here.