Agent chat: a turn that ended on work folds its interim text under Worked for (cx-iwqox)

Merged
TE
23d ago
+107-15

Summary

When a turn finishes, everything between the prompt and the final answer should fold into one "Worked for Xs" row, as in the Codex and Claude desktop apps. That broke whenever a turn ended on work instead of text. The answer was simply the turn's last text, so:

  • A turn that ran a tool after its last text kept that interim text open as if it were the answer, with the later tool rows drawn unfolded below it.
  • A turn stopped mid-tool (text, tool, Stop) showed no fold at all: its text and tool rows stayed open.
  • An earlier turn without a summary that ended on a tool kept its interim text and tool rows open in the same way.

Now the answer is the last text only when no tool call follows it (decided per call, so a step that edited and then ran something counts as work) (answerAt in conversation/turns.ts, used by both shapeTurn and settledWithoutSummary). Otherwise the whole body folds, and its label reads "Worked for" or "You stopped after", as before. Other rows after the answer keep the answer open, as today: edits still join the turn's edit card, and render cards, plans, subagent groups, background tasks, notices and thoughts after it don't count as work. Running turns are unchanged.

Testing

  • webviews/test/transcript-worked-fold.test.ts (new) drives turnView, the transcript's turn-shaping seam. Covered:
    • answer after work folds the work (control)
    • ended on a tool: everything folds
    • stopped mid-tool: everything folds
    • an edit after the answer still joins the card
    • an earlier turn without a summary that ended on a tool folds
    • expanding shows the interim text and tools in order
    • a step that edits and then runs a command, in one activity row, still folds (added after review)
  • Red on each test commit (4 of 6 fail, then the mixed-step case alone), green on each fix (7/7), and green after merging current feat-cmux-next.
  • Known edges, left as is: a TodoWrite that clears the list after the final text arrives as a plain tool call, so it folds the answer; a render call still pending at turn end counts as work until its update lands.
  • Locally green: the jsdom transcript tests that use turnView (thread-turn-keys, long-chat-updates, range-content, minimap-current, jump-latest, viewport-resize, hidden-follow, scroll-restore, turn-error-details), plus the layers, type-scale, status-glyphs, system-blue and text-focus ratchets.
  • Not run locally: vp check and the browser tests (agent-pane-turn-footer, chat-find). Big-red is under memory pressure; CI runs them on this PR.

Changelog

Fixed: Agent chat folds a finished turn's work under "Worked for" even when the turn ended on a tool or was stopped mid-tool

Proof

Same fixture rendered on base and head through the transcript gallery (Chromium, page only).

beforeafter
ended on a tool (text, tool, text, tool)beforeafter
stopped mid-tool (text, tool, Stop)beforeafter

Before, the interim text stands as the answer with a tool row open below it, and the stopped turn has no fold at all. After, only the fold row shows. Its time now spans the whole turn (36s against 24s, when the fold ended at the interim text). The footer drops Copy because the turn has no answer; before, Copy copied the interim text.

Bead: cx-iwqox

🤖 Generated with Claude Code