Skip to content

feat(tui): show subagent's latest tool call and elapsed time #36099

Description

@kitlangton

Problem

The v2 TUI subagent row only shows a spinner and title while a sub-agent runs. V1 streamed the child session's tool calls into the task part and rendered them beneath the entry, so you could see what the sub-agent was actually doing. That signal is gone, and there is no indication of how long a sub-agent has been running.

Decided design

While a subagent is running, render one indented line beneath its header showing the child's most recent tool call, plus a live elapsed timer at the end of the header line:

∴ Explore Subagent — Explore V2 multi-client readiness · 42s
  ∟ Grep "session.status" packages/tui

The sub-line swaps in place as the child moves between tools (no scrollback growth):

∴ Explore Subagent — Explore V2 multi-client readiness · 58s
  ∟ Read packages/tui/src/routes/session/index.tsx

On completion the sub-line disappears and the timer freezes in place on the header:

✓ Explore Subagent — Explore V2 multi-client readiness · 1m 12s

Multiple concurrent subagents stay scannable — one tight pair per task:

∴ Explore Subagent — Explore V1 server/TUI client model · 1m 03s
  ∟ Read src/session/index.ts

∴ Explore Subagent — Explore V2 multi-client readiness · 42s
  ∟ Grep "session.status" packages/tui

Decisions

  • Last tool call only — not a trailing log of the last N calls (V1 showed all of them). History is one click away by entering the child session; a single line keeps stacked subagents scannable.
  • Timer on the main line, not the sub-line. The sub-line dies at completion but the header lives forever, so the timer ticks and freezes in the same place — no relocation. It also reads correctly as the task's elapsed time (∟ Grep ... · 42s would misread as the grep's duration), and it separates rhythms: header ticks 1/sec, sub-line changes per tool call.
  • glyph (V1 heritage), indented one step (2 spaces, aligned under the header text) — same depth the Execute component uses for its child lines.
  • Sub-line content: raw resolved tool call (∟ Grep "session.status" packages/tui); while the child's current call is still pending, the humanized action label ("Searching content…") may be shown, matching V1 behavior.

Open question

Completed-header stat: · 1m 12s alone vs · 14 toolcalls · 1m 12s. The dead helper formatCompletedSubagentDetail (packages/tui/src/routes/session/index.tsx:2422) already produces the latter string.

Implementation notes

  • Current rendering: Subagent component, packages/tui/src/routes/session/index.tsx:2379 — header row + spinner only, running state derived from part state or data.session.status(childSessionID).
  • The pattern to copy exists next door: the Execute component (~index.tsx:2440) renders indented child tool-call lines from metadata.toolCalls.
  • Two ways to source the child's latest tool call:
    1. Client-side derivation from already-synced child session parts (data.session.message.list(childID)) — no server change; likely preferred.
    2. Server-side metadata streaming like old V1 task.ts, which bus-subscribed to child PartUpdated events and mirrored child tool parts into the task part's metadata.summary.
  • Dead helpers referenced only by tests that this work may revive or replace: formatSubagentToolcalls (index.tsx:2410), formatSubagentRetry (:2418), formatCompletedSubagentDetail (:2422).

V1 reference

Upstream v0.6.3 Go TUI (packages/tui/internal/components/chat/message.go, since removed): task tool rendered metadata.summary as one ∟ <tool title> line per child call, pending calls shimmered with humanized action labels. Server side (packages/opencode/src/tool/task.ts) mirrored child tool parts into task metadata on every child part update. No duration was shown in V1 — the timer is new.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions