Repository navigation
Description
Summary
deriveTurnFolds keeps exactly one entry visible per settled turn — the last assistant message, per deriveTerminalAssistantMessageIds. With providers that interleave short progress commentary with the actual answer, the last message of a turn is frequently a one-line "now I'll check X" note, so the real answer is folded away under Worked for Ns and the visible remainder is a fragment that reads like a non sequitur.
This is not the "collapse noisy tool calls" case the fold is designed for: the folded content is the response itself.
Environment
- Server
t3@0.0.33(headlesst3 serve, Linux x64, Bun runtime) - Desktop client
T3Code(Alpha)/0.0.33, Electron 41.5.0, macOS - Provider: Grok Build
1.0.4(ACP overgrok agent stdio), modelgrok-4.6
What happens
A Grok turn emits assistant messages as separate segments (assistant:…:segment:N) interleaved with tool calls. The turn commonly ends on a progress note rather than on the answer, e.g. turn a210c1f8:
| segment | time | length | content |
|---|---|---|---|
segment:5 |
10:07:34 | 3178 chars | the actual answer |
segment:6 |
10:10:12 | 146 chars | a progress note ("looks like a shared session — checking where live dev redirects to") |
segment:6 is the terminal message, so it stays visible; segment:5 is hidden behind Worked for ….
How common
One thread, 108 messages, 68 assistant messages across 36 turns. 19 turns had more than one assistant message; in 18 of those 19 the last message was not the longest. Terminal notes clustered at 77–146 chars while the answers they hid ran to 3178 chars.
Turn size distribution: 17 turns × 1 message, 14 × 2, 3 × 3, 1 × 5, 1 × 9.
Expected
The visible entry after folding should be the turn's substantive response. Folding should not be able to hide every assistant message that carries the answer.
Code
apps/web/src/components/chat/MessagesTimeline.logic.ts
deriveTerminalAssistantMessageIds—lastAssistantMessageIdByResponseKey.set(responseKey, message.id)on every assistant message, so the winner is positional: whichever message came last.deriveTurnFolds— everything in the group exceptterminalEntrygoes intohiddenEntryIds(onlyworkentries withagentSpawnare exempt).
apps/mobile/src/lib/threadActivity.ts appears to carry the same rule, so mobile is affected identically.
Possible directions
- Keep all assistant messages visible and fold only
workentries — the fold then does what its docstring says ("commentary and tool activity") without depending on which message happens to be last. - Treat a trailing assistant message that is immediately followed by tool activity as commentary rather than as the terminal message.
- Pick the terminal message by content rather than position.
Option 1 is the smallest change and does not need heuristics.
Notes
Reproduced against a live grok agent stdio session; the segmentation is the provider's normal output shape, not an error path.
Activity
pantharshit007 commentedon Sep 9, 2026
@juliusmarminge , whenever you/agent re-visit this, #10991 was for antigravity not grok.
beardedarchitect commentedon Sep 25, 2026
Also hits the Claude Code provider: images the agent shows mid-turn get folded under "Worked for …" and I do not know they exist. +1 for merging #8903.
edgan commentedon Oct 1, 2026
I see this with
Claude Code v2.1.286andT3 Code 0.0.44. It is highly frustrating when the final response is something likeI answered your question., but the answer is nowhere to be seen. Given most of the time what is hiding in theWorking/Thoughtexpandables is nothing of use, it trains you not to look in them.sigvardt commentedon Oct 12, 2026
Same with the Claude provider on T3 Code 0.0.45 (headless
t3 serve, macOS arm64, modelclaude-opus-5-5).Pattern from one turn:
After the turn settles, only that one-line note is visible. The answer is folded under "Worked for 1m 19s", and the user had to ask for it again. The user sees this often in long Claude threads, so it is not specific to Grok.
In the same threads, user-facing text written just before a tool call sometimes shows up as a collapsed "Thought" (#18355), which hides responses the same way.
Our workaround is to tell the agent to end every turn with the complete answer and make no tool calls after it. Agents should not need that: the fold should keep a turn's substantive response visible, as #8903 and #14698 aim to do.
Squashed '.repos/effect-smol/' changes from a43c7e244c..e17ecdbe90
nkoynov commentedon Oct 19, 2026
Still happens on 0.1.1-nightly.20261019.3348, with OpenCode 2 and Claude Opus 5.5, and it's not only a Grok thing.
In one run and one provider turn, the agent wrote a 4.3K-character answer, then launched a background subagent and added an 885-character status note. Nothing folds while the run is live, so I was reading the answer. When the run settled 22 seconds later, the answer went under "Worked for 2m 6s" and only the status note was left in view. It looked like the reply had been replaced. Nothing was lost; expanding the fold shows it.
How often, over a week of runs: an earlier assistant message of 1,000+ characters that is more than twice as long as the final one happened in 14 of 1,805 runs on one machine and 3 of 723 on another.
#14698 fixes this case for us.
Model and harness: Claude Opus 5.5 via OpenCode 2 in T3 Code.
McCalebTheSecond commentedon Oct 20, 2026
Additional Claude example observed on October 20, 2026, on a newer nightly.
Environment:
0.1.1-nightly.20261020.3411, verified through the server's environment API.claude-opus-5-5.Observed sequence:
The stored original turn confirms separate assistant messages around the file-change tool activity. No independent synthetic reproduction or root-cause verification was performed. Expected behavior: the substantive answer should remain readable with work activity collapsed. The current workaround is manually expanding the fold.
Screenshots supplied by the reporter:
Default collapsed state: only the later follow-up question is visible.
Expanded state: the detailed explanation, alternatives, and recommendation appear.
We initially added this evidence to closed issue #7518: #7518 (comment). Adding it here because this open issue tracks the same behavior and already includes Claude examples. The Codex screenshot pair in that earlier comment is comparison material: its final answer remains visible, so it is not another demonstrated hidden-answer occurrence.
Prepared with GPT-6.1-Sol through the Codex harness in T3 Code.
mattbolt commentedon Oct 22, 2026
Same here on
0.1.1-nightly.20261020.3386(macOS), with Claude (claude-opus-5-5) and also Codex.My case: the agent wrote a 2,243-character answer, made two tool calls to save a memory note, then ended with an 89-character sentence. The answer was on screen for about 8 seconds. When the run settled, everything except the 89-character line went behind "Worked for 1m 28s". The full text is in the projection DB, so this is only the client fold.
I ran the same rule (last assistant message per completed run stays visible) over a week of my own local history to see how often it happens:
So it's not specific to one provider. Any run where the real answer isn't the last text block loses it from view. In my history about 1 run in 60 hid a substantial message.
I agree that a length cutoff isn't the right fix, per the reasoning on #8075. Folding only tool calls and reasoning, and leaving assistant prose in the timeline, would cover every case above. That looks like what #8903 does. Would it be worth reopening now that it has screenshots and has been moved onto main?
dr-baker commentedon Oct 28, 2026
Confirmed with Codex / gpt-6.1-sol on macOS desktop,
0.1.3-nightly.20261027.3748.Reviewed #14698 with GPT-6.1-Sol, high reasoning. The change looks right for this case: keep assistant messages visible and fold tools/reasoning. This was a code review; we haven't tested the patch against this thread.
Steering can hide a complete answer even with no tool calls or progress notes:
The Codex transcript confirms two
final_answermessages in the same run and provider turn. Both are saved intact. Expanding the fold reveals the first answer.T3 keeps only the last assistant message per run visible. That rule is still on current main, and this build already includes #19023 and #22783.
The tradeoff in #14698 is that progress prose also stays visible, which seems preferable to hiding answers.
A useful regression case: prompt → steer → final answer → final answer, all in one completed run. Both answers should remain visible with work collapsed.
Alb11747 commentedon Oct 31, 2026
Additional confirmed Claude case, with a proposed direction that preserves final answers without exposing every progress message.
What happened
On Windows desktop with the Claude Agent provider, an assistant gave a long answer. Delegated-task notifications then continued the same run, and the assistant posted a shorter status update. The long answer moved inside the collapsed Worked-for fold. Expanding the fold restores it; this case does not involve missing stored text.
The user explicitly rejected keeping all assistant messages visible. The intended behavior is to keep messages identified as final answers visible and continue folding progress commentary.
Evidence and diagnosis
Read-only thread activity on 2026-10-31 shows this sequence (UTC):
Both assistant messages and the intervening activity belong to the same run. The supplied screenshot pair shows the earlier answer inside the expanded Worked-for fold, then absent with the fold collapsed while task cards and the newer reply remain visible. Private conversation text, thread identifiers, and screenshots are omitted.
In the fork checkout at 3967fbf,
deriveTerminalAssistantMessageIdschooses the last assistant message per run, andderiveTurnFoldsexempts only that terminal message from folding. The same rule is present in freshly fetched upstream main at 80a2351. Mobile has analogous last-message-per-run selection. This establishes the presentation cause, rather than a fork-only regression. The installed release version was not established.Proposed direction, not implemented
Preserve provider-reported answer intent through the event/projection contract, and have web/desktop and mobile keep every explicitly classified final answer outside the work fold. Later messages, steers, or task notifications must not demote an already classified answer. Continue folding commentary. Keep unknown distinct from commentary.
There are existing provider signals to investigate and retain:
agentMessage.phasedistinguishesfinal_answerandcommentary.CodexAdapterV2already reads that distinction for internal final-answer handling, but its emitted assistant-message turn item does not include it. An absent phase should not be treated as explicit final-answer evidence.ClaudeAdapterV2already recognizes transcript turn endings, and its tests contain streamingmessage_deltaevents withend_turnversustool_use. The current stream handler processes usage there without retaining answer intent in the assistant-message projection. Associate the eventual stop reason with the correct native message, including separately emitted text blocks. Confirm successful response completion; a completed text block, truncation, interruption, or any arbitrary non-tool stop reason is not sufficient evidence by itself.This is a feasible implementation direction based on source inspection, not a tested patch or proof of the exact native stop reason for the historical answer above. Other providers need an explicit supported/unknown decision. Old persisted history may need to retain existing behavior unless trustworthy provider evidence is available; guessing from length, wording, or position would not solve the distinction reliably.
Meaningful regression coverage would include two explicitly final answers in one run, commentary between them, delayed Claude stop metadata, and interruption/truncation remaining unclassified as successful final answers. A fixture matching this notification sequence should keep both answers visible while work is collapsed, including after reload.
No source changes, database writes, running-app changes, or PR were made. No tests were run because this is investigation only. Adding this evidence to the existing report avoids a duplicate issue. Related: #5297 and #17382. PR #14698 takes the broader keep-all-assistant-text approach; that is not the requested behavior here.
Investigated by GPT-6.1 Sol through the Codex harness in T3 Code.
Alb11747 commentedon Oct 31, 2026
The metadata-based fix is now in #27991. The original Claude SDK log and saved transcript both confirm end_turn for the affected answer; the SDK marker arrives 14 ms after its text snapshot. The patch preserves that provider signal and explicit Codex phases through storage and client folding, keeping confirmed answers visible while commentary still folds. The PR includes before/after captures from an isolated app fixture, focused regressions, known Windows baseline test failures, and the exact-commit CI link. Old history without metadata retains its existing fallback.
guryanov-a commentedon Oct 31, 2026
Another Claude case, this one caused by a steer, plus an ordering problem that may be separate.
What happened (Claude Agent provider, macOS desktop, model
claude-opus-5-5)$learn) started a run, and Claude worked on it for about 80 s.What the timeline shows
So there are two problems:
MessagesTimeline.logic.tsonly decide which messages stay visible, and nothing in the PR sorts or repositions timeline items. With the PR, the answer would stay visible but still appear after the steer, so the ordering needs its own fix.fix(chat): keep provider-confirmed final answers outside work folds
fix(chat): keep provider-confirmed final answers outside work folds
fix(chat): keep provider-confirmed final answers outside work folds
vivekkairi commentedon Nov 8, 2026
Same on the macOS desktop app,
0.1.8-nightly.20261106.4275(server version from/.well-known/t3/environment), Claude Agent provider,claude-opus-5-5.In one run, Claude wrote a 2,311-character answer, then wrote a file (one
file_changeitem), then ended with a 213-character note saying the file was ready. After the run settled, only the 213-character note was visible. The answer was under "Worked for 1m 42s", with nothing to show that the actual reply was in there. Both messages are inorchestration_v2_projection_messageswith the samerun_id, so this is the client fold, not lost data.deriveTerminalAssistantMessageIdsis unchanged onmainas of 2026-11-08, so it is still present. +1 for landing #14698 or #27991.Filed via
t3 triageby Claude Code (Opus 5.5).Alb11747 commentedon Nov 13, 2026
Part of this is fixed in #36026, which replaces the stale-closed #27991 with only what
mainstill needs after #34501. Mobile keeps afinal_answeroutside "Worked for" only when a steer follows it directly, while web keeps everyfinal_answer. So a Codex run that continues in the same run without a steer still hides its earlier answer on mobile. The mobile feed test there fails onmainand passes with the fix.I already have more open PRs than the open PR limit allows, so the limit check may close #36026 on arrival. If you'd like it reviewed, a maintainer can reopen it, add
triage:keep-openso I can reopen it, or add me to the PR limit exemptions.🤖 Generated with Claude Code
lol2x commentedon Nov 13, 2026
Another Claude + steer case, on
0.1.10-nightly.20261113.4630(server version recorded by the running server; Windows 11 x64; Claude Agent provider). This one is not covered by #34501.What happened
status: "interrupted"at 14:12:16.153; the steer user message followed 25 ms later.command_executionitems, then a short closingassistant_message(completed).After the run settled, the answer to my question sat under "Worked for 16s" with an
interruptedpill, and only the closing note after "Continued for 8.8s" was visible. I had to go looking for my answer.Why it folds
deriveTurnFoldskeeps only the run's last assistant message (deriveTerminalAssistantMessageIds). The steer exemption from #34501 (retainedAssistantReplyEntryIds) keeps a reply only if it hasphase: "final_answer", or if it is the last output of a superseded attempt withstatus: "completed". The Claude item here has nophaseand its status isinterrupted, so neither branch applies and it is hidden.Items of the run (from
orchestration_v2_projection_turn_items):MessagesTimeline.logic.tsis unchanged onmainsince this nightly, so it still reproduces there as far as I can tell. An assistant message that a steer cut off mid-stream is almost always the reply the user is waiting for, so it probably should stay outside the fold regardless ofphase/status. #14698 would also cover it.Diagnosed with
t3 triageby Claude Opus 5.5 (Claude Code).EtanHey commentedon Nov 13, 2026
Same cause on
0.1.10-nightly.20261113.4616(macOS, Apple silicon, Claude provider), plus one thing not mentioned here yet: Zen.After a steer, Claude asked me to resend some answers, then kept running tools. When the run settled, that question sat under "Continued for 17m 53s" and I missed it (#35977, closed as a duplicate of this).
In Zen there's no fold to open.
timelineRowEntriesdrops every assistant message except the onesderiveTerminalAssistantMessageIdskeeps, andderiveTimelineTurnFoldsreturns no folds in Zen. From the code, the only way back to the message is Find in thread, which switches Zen to Hide all while it's open. So whichever fix lands for the terminal pick needs a check in Zen too.The hidden message was a question to me in the middle of the run, not a final answer. Keeping
final_answermessages visible, as web does since #34501, doesn't bring it back. Keeping assistant text across tool calls (#14698) would.Filed by Claude Opus 5.5 in T3 Code, for EtanHey.
bompus commentedon Nov 13, 2026
Another Claude case, this time with a Stop hook, plus a minimal repro for the images case.
Build: dev server run from the source at tag v0.1.10-nightly.20261113.4656 (0517d15), Linux x64, web client, Claude provider, claude-sonnet-5-5.
Tool call: one reply with text and two Markdown images, then one Bash call, then a short final message, all in one run. After the run ended, only the final message was visible. The first message and its images were under "Worked for 3.7s", and expanding the row showed both images. Same result in 3 of 3 attempts in the stored data (the browser view checked on one of them).
Stop hook: the same first message, then a Claude Stop hook that blocks the first stop, so Claude writes one more reply. Only that reply was visible after the run ended. The first message was folded the same way, and expanding showed it. 3 of 3 attempts in the stored data (browser view checked on one).
Control: the same first message with no tool call and no hook stayed visible with no fold (1 of 1).
Nothing was lost in any case; the folded messages were intact.
Alb11747 commentedon Nov 13, 2026
The Claude part of this still happens on current
mainat eb14ddb. #36116 changed only mobile.Web keeps an earlier answer outside "Worked for" only when its turn item has
phase: "final_answer"(retainedAssistantReplyEntryIdsinMessagesTimeline.logic.ts). Codex sets that phase.ClaudeAdapterV2never does: nofinal_answerappears anywhere in the file. So a Claude answer that is followed by more work in the same run (a tool call, a file write, a steer, a Stop hook) still folds on both web and mobile. That matches the recent Claude reports above.Repro with the fake Claude SDK harness and no login: paste the test below after
const makeWakeHarness = makeWakeHarnessWithOptions();inapps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts, then:All three cases fail. The streamed and snapshot cases fail the same way:
The message that ends with
stop_reason: "end_turn"should get the final-answer phase, and the earliertool_usemessage should not. A server-side fix that does this is on the fork branchAlb11747/t3code:fix/claude-final-answer-visibility. It has no PR yet, and its mobile half now conflicts with #36116.Test
Posted by Claude Opus 5.5 on behalf of Alb11747.
Bibendus83 commentedon Nov 14, 2026
Another Claude + steer case, with several steers in one run.
Server
0.1.9(Windows 10 x64, desktop), Claude Agent provider,claude-opus-5-5.What happened
While the agent was working, I sent four short messages within about a minute. All of them went in as steers in the same run. The agent answered each one as a separate
assistant_messagebetween its tool calls, then made one more tool call and ended with a one-line note about that call.After the run settled, only that last note was visible after "Continued for 40s". Every answer to my four questions was folded. The visible note read as a non sequitur, because nothing it replied to was on screen. Expanding the fold restored the answers, so nothing was lost.
What the stored items show
The answers are ordinary
assistant_messageitems with statuscompleted, in the same run as the steers and the final note. One answer was a promoted:thinking:1item; the others were regular text blocks.Note
With multiple steers, the "last message stays visible" rule hides every reply except one, so the more you talk to the agent during a run, the less of its replies you see. Keeping the agent's reply to each steer visible, or not folding assistant messages at all (#14698), would fix this case.