Repository navigation
Conversation
…ams them last Provider streaming assembles message.content in arrival order, so turns that flush the reasoning stream after the answer text rendered the thinking block below the answer while other turns rendered it above. Normalize the render path: when no thinking block precedes the first answer block, hoist thinking ahead of the answer in both the pi and step skins. Alternating runs are left untouched.
li-xiu-qi
requested review from
MelodyVAR,
Uking-xxx,
ZouR-Ma and
liuedcson
as code owners
October 21, 2026 15:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #286
Problem
Within one conversation, the collapsed thinking block is painted below the
answer in some turns and above it in others. The transcript renders an
assistant message strictly in the order of
message.content, and that arrayis assembled by the provider streaming layer in event arrival order
(
packages/providers/src/api/openai-responses-shared.tspushes each thinking/ text / toolCall block as it arrives). Most turns deliver the reasoning
stream first, but some turns flush it only after the answer text, so the same
conversation ends up with the thinking block on both sides of the answer.
The inconsistent placement was reproduced end-to-end in a live terminal
against real model streams; the repro screenshot is attached to the issue.
Changes
withThinkingBeforeAnswer()inapps/cli/src/ui/view/transcript/assistant-message.ts: when no thinkingblock precedes the first answer block, hoist every thinking block ahead of
the answer (stable within each group). This is the only normalization
applied: alternating runs (thinking, answer, thinking, answer) already lead
with thinking and are returned untouched, preserving segmented reasoning.
AssistantMessageComponent.updateContent()so the pi skinrenders thinking above the answer.
partitionAssistantContent()instep-message.tsso the stepskin gets the same placement through its existing run partitioning.
The normalization is a pure function over the content array and runs on every
updateContentcall, so it applies to both fresh messages and sessionreplay.
Behavior and compatibility
change appearance; the common shape (thinking first) and the alternating
shape are byte-for-byte unchanged.
message.contentitself is not mutated and no provider response shape,config key, or CLI surface changes, so history
sent back to the API keeps its original order.
components and still act as run boundaries in the step skin.
Validation
model streams (screenshot attached to issue [Bug] Thinking block position is inconsistent across turns: sometimes above the answer, sometimes below it #286); the fix targets exactly
that rendering path.
last" in both
apps/cli/test/assistant-message.test.tsandapps/cli/test/step-message.test.ts, plus "keeps segmented reasoning inplace when thinking already leads" in the former.
npx vitest run apps/cli/test/assistant-message.test.ts apps/cli/test/step-message.test.tsResult: 28/28 pass (25 pre-existing + 3 new).
npx tsgo -p tsconfig.build.json --noEmitinapps/cli: clean.npx biome checkon the four changed files: clean.check:ui-layer,check:layer-direction,check:ts-relative-imports: pass.apps/clisuite: 727 passed, 13 failed. The 13 failures reproduceidentically on a stashed (unmodified) tree. These are clipboard / suspend / path
formatting tests that are environment-dependent on Windows and are not
touched by this change.
packages/*suites: 5606 passed, 110 failed. The failures are alllocal Windows environment issues (spawnSync of node.exe failing, timeouts,
path assertions, test-file loading errors) and are flaky (the failure set
differs between runs). Running the same failing files with the change stashed
reproduces the identical failure mode, confirming they are unrelated to this
change. The authoritative signal for these suites is the fork CI (ubuntu).
Limitations
Not applicable: the change is a display-only rendering normalization covered
by unit tests on both skins; no unresolved boundary is known.