Agent chat: tool rows line their verbs up in one column; scrolling tool output fades at its bottom

Merged
TE
7d ago
+701-32

Leo, 2026-10-29, on Codex's tool rows: "fade is nice ish too on these tool calls... having stuff aligned is nice".

What changed

  • Aligned verb column. A turn's tool rows put their verb ("Ran", "Read", "Edited", "Searched", a folded run's or group's first word) in one column as wide as the widest verb among that turn's rows, so every subject starts at the same x, as Codex lines its rows up. Applies to ToolRow, CommandRow, ToolRun summaries, ToolGroupRow lines, MCP rows and Write lines (ToolVerb.tsx).
    • No measuring: the turn's verbs are one CSS string (--cv-tool-verbs, a verb per line) on the turn's .cv-tools element, and each verb's hidden zero-height ::after lays them out under it, so the verb box takes the widest width.
    • Each row registers its verb once, on mount or when its verb changes, never per streamed token. Only the .cv-tools element re-renders, and only when a new verb appears or the last row with a verb goes. Its rows are the same elements, so React skips them. No timers or observers.
    • Only languages whose tool line leads with the verb ("Ran {command}") get the column. Japanese, German and other verb-final strings read as before. An MCP plain name ("Hub · read chat") and one-word titles stay whole.
  • Output fade. An MCP call's request/response box and a Markdown tool result scroll at a fixed height and used to cut a line in half at their bottom edge. They now fade that edge out over 28px while more lies under it, the same fade a cut Shell/output preview already has, and the edge goes hard again once scrolled to the end (moreBelow.ts). Stop condition: one passive scroll listener and one ResizeObserver per opened box, removed when the box unmounts or its content changes.
  • Not touched: colours and glass, delivery, grouping, the incoming-message disclosure rows (#27312), reply action rows (#27313), Markdown rendering.

Gallery

New entry agent-pane.tool-row-column with five variants: before (no column, hard edge), column / column-dark (shipped: widest-verb column, 28px fade), fixed (a fixed 4.6em column), tall-fade (48px fade). I shipped the widest-verb column: the fixed column wastes width on short verbs and still breaks on a long one, and a 48px fade hides more than a line of a 240px box.

Gallery: agent-pane.tool-row-column, agent-pane.tool-group-alignment

Before/after stills: the gallery advisory run at the head, https://github.com/manaflow-ai/cmux/actions/runs/40876646803 (artifact gallery-advisory-27386-bbd7ec7…, in diff/head/agent-pane.tool-row-column--{before,column,column-dark,fixed,tall-fade}--*.png; light and dark app themes). before shows each subject starting right after its own verb, and the MCP response cut hard through a line. column lines up "Read / Ran / Searched / Edited" with the subjects at one x, and the response fades over its last 28px.

Tests

webviews/src/agent-session/acpmux/conversation/ToolVerb.test.tsx (committed before the fix in 8bf658532d4):

  • Red at the test commit (fix set aside): run https://github.com/manaflow-ai/cmux/actions/runs/40856963245. The verb-column tests fail ([] verbs, no data-tool-verbs), and so do the CSS-rule and MCP fade tests.
  • Green at the head (781aa1db346, after the base merge): bun test ToolVerb.test.tsx gives 10 pass, 0 fail. The neighbouring suites, each run on its own, also pass with 0 fail: BackgroundMark 16, ContinueAfterStop 13, TurnFooter 6, TurnRows 6, toolGroups 19, SessionStartNote 4, toolResultMarkdown 1, toolResult 33, FindPillParity 3. bun run check (fmt, lint, type check, design tokens) passes. All of these ran on fleet Linux fast checks.
  • Tests added after review cover:
    • Find skips a command row's verb and the space after it.
    • A Find phrase that spans the verb and the subject highlights as one range (chatFind.ts findRuns joins the text nodes inside one data-find-join label).
    • MCP Called … verbs join the column, and a plain MCP name stays whole.
    • Running → Ran updates the column.
    • Under StrictMode each verb counts once.
    • A label splits only at one plain space.

Observed / Not run

  • Observed: the runs above. vp fmt and vp lint are clean on the changed folder, and the prepush gate reports no new violations.
  • CI: the only red at bbd7ec7ed09 is cmux-next checks › No new SwiftUI, which flags CmuxNextHome/ChatColors/HomeChatColors*.swift. Those files came from base, and this PR changes no Swift.
  • Review: Codex gpt-6-astra (high, fast) returned SHIP at bbd7ec7ed09 (and at each earlier head since 781aa1db346) after two FIX rounds. The FIX rounds produced the Find-skip, MCP-verb, Find cross-node highlight, whitespace and gallery-covers fixes.
  • Not run: a native capture. This is webview-only UI, so the gallery stills stand in.

Changelog

Changed: Agent chat tool rows line their verbs up in one column, and a tool output box that scrolls fades at its bottom edge instead of cutting a line.

Agent session: agent session

🤖 Generated with Claude Code