Skip to content

fix(subagent): stop background lanes from flickering and flooding the transcript - #229

Merged
Uking-xxx merged 2 commits into
mainfrom
fix/subagent-background-tui
Oct 9, 2026
Merged

Uking-xxx merged 2 commits into
mainfrom
fix/subagent-background-tui

Conversation

@Uking-xxx

Copy link
Copy Markdown
Collaborator

Problem

User feedback: while background subagents run, the TUI "flickers enough to hurt the eyes", and the transcript fills with [agent-notification] blocks of raw internal data.

Flicker. Each background lane had its own aboveEditor widget (step-agent:<id>), republished on every streamed delta with the child's live text (~ general | <last line of output>). The host deletes and re-inserts a widget on every setWidget, so whichever lane updated last moved to the bottom: lanes kept swapping places. Long lines wrapped, so the block's height changed too. The blocking call's list widget had already been fixed for the same issues; background lanes never got the fix.

Notification flood. With subscribe: "progress", every lane sent a background_progress notification every 15s with display: true. agent-notification has no message renderer, so each one showed up as a purple box of raw pseudo-XML (<agent-notification agentId="…" event="background_progress" …>step 1/1; tool write_file; turns 107, in:188830 out:46766</agent-notification>).

Changes

  • One shared list for all background lanes (step-agent-lanes), reusing the blocking call's SubagentListWidget with the title background agents:
    • fixed spawn order, task as the row title, no live text or hex ids;
    • republished only when status or token counts change (same signature check as the blocking list);
    • stays listed until the whole batch settles, so the header reads 1/3 complete, 2 running and doesn't shrink as lanes finish, then clears;
    • a 1s tick keeps elapsed moving while the parent is idle. Background lanes usually run with no working indicator to drive redraws.
  • background_progress stays model-only (display: false); the parent model still receives it.
  • Renderer for agent-notification: one status line plus up to 3 preview lines, with Ctrl+O to expand:
    ✓ background agent f4a0ede4 (general) finished
      B_DONE
    
    The renderer reads new structured details (label, agents, unescaped detail). Messages from older sessions without them fall back to the host's default rendering.
  • Settled rows drop the token readout and keep only the final elapsed. This applies to the blocking list as well, since it's the same widget.

The content the model receives is unchanged.

Testing

  • New test/subagent-background-tui.test.ts (4 cases): shared widget with stable order and no republish on text-only deltas, clearing when the batch settles; progress hidden from the transcript but still sent; notification rendering collapsed/expanded; legacy fallback. All 4 fail on main.
  • New list-widget case: completed/failed rows show only elapsed.
  • Existing mock ExtensionAPIs gained a no-op registerMessageRenderer.
  • Subagent tests 55/55; pnpm run check passes.
  • Manual tmux run from source against step-5-preview with 3 background lanes (subscribe: "progress"): one stable list, clock advancing while the parent was idle, no progress entries in the transcript, and three one-line completion entries at the end.

Note

This PR and #227 both touch SubagentListWidget in rendering.ts (#227 changes the header counts; this one adds a title parameter and the settled-row metric). The changes don't overlap; whichever lands second may need a trivial rebase.

… transcript

Each background lane had its own widget, republished on every streamed
delta with the child's live text. The host re-inserts a widget on every
set, so lanes swapped places, and wrapping text changed the block height.
Progress notifications were displayed in the transcript every 15s per
lane as raw <agent-notification> pseudo-XML.

- Render all background lanes in one shared list widget, reusing the
  blocking call's SubagentListWidget: fixed spawn order, task titles
  instead of live text, republished only on status/token changes, and
  cleared once the whole batch settles. A 1s tick keeps elapsed moving
  while the parent is idle.
- Keep background_progress notifications for the model only
  (display: false).
- Render the remaining agent-notification events as a status line with
  a collapsible preview; notifications without structured details keep
  the host's default rendering.
- Drop the token readout from settled rows in the list widget.
# Conflicts:
#	packages/coding-agent/src/features/subagent/rendering.ts
@Uking-xxx
Uking-xxx merged commit 7a687e3 into main Oct 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant