fix(tui): complete sub-agent detail panel state coverage + artifact handles (#4094) - #4197
Conversation
…andles (#4094) Closes out the four items that reopened #4094 after PR #4182 delivered the live-activity trail, tool-call name/status, final summary, and bounded histories. 1. Many-tool-call coverage: a single worker that has fired hundreds of tool calls renders non-empty, carries the live tool-call trail + step count, stays width-bounded, and exposes an inspect-more handle. New test: subagent_expanded_detail_renders_many_tool_calls_without_overflow. 2. Narrow-width readability: every rendered line (header, role-mix, label, dossier, handle) is now clamped to the column. Fixes a real overflow: the old `format!(" {}", truncate(.., width-2))` and the two-tone running/done header both spilled past the column at narrow widths. Adds indented_detail_line() (indent-aware clamp) and a header width-clamp. New test: subagent_detail_readable_and_bounded_across_narrow_widths (widths 1..48, plus status-verb-visible at a usable-narrow width). 3. running/done/failed matrix: asserts each state renders the right marker, status verb, and state color. New test: subagent_status_matrix_renders_marker_verb_and_style. 4. Artifact/receipt handle for full output: instead of dumping the full transcript inline (the freeze/emptiness risk), the panel shows a bounded preview plus a copyable handle to the fuller artifact -- `handle_read agent:<id>/full_transcript` -- reusing the documented sub-agent transcript var-handle (subagent_session_projection / default_subagent_artifacts). Gated so an empty transcript is never advertised, guarded by max_rows, and truncated so it never overflows. New tests: subagent_completed_worker_surfaces_output_handle_not_inline_dump, subagent_output_handle_gated_on_inspectable_output. The handle is the one place a raw agent id is intentionally surfaced in the detail panel (a functional, copyable handle on its own line), keeping the dossier line id-free per #3030. Verified: cargo fmt --all --check; cargo clippy --workspace --all-features --locked -D warnings (gate allows); cargo test --workspace --locked (only the two known pre-existing unrelated failures, confirmed on origin/main); cargo build --release -p codewhale-tui. Authored by Hunter with agent assistance.
|
Claude finished @Hmbown's task in 3m 32s —— View job Review: PR #4197 — sub-agent detail panel state coverage + artifact handles
SummarySingle-file, well-scoped diff to Bug: advertised output handle doesn't exist for running workers (posted inline at
|
| fn subagent_output_handle(row: &SidebarAgentRow) -> Option<String> { | ||
| let has_output = sidebar_agent_status_is_terminal(row.status.as_str()) || row.steps_taken > 0; | ||
| if !has_output { | ||
| return None; | ||
| } | ||
| Some(format!("agent:{}/full_transcript", row.id)) |
There was a problem hiding this comment.
Bug: the advertised handle doesn't exist yet for running workers.
subagent_output_handle returns Some("agent:{id}/full_transcript") whenever steps_taken > 0, even while the worker is still running (see the subagent_expanded_detail_renders_many_tool_calls_without_overflow test, which exercises exactly this: a running row with steps_taken: 247).
But the backing var-handle agent:<id>/full_transcript is only ever inserted by insert_subagent_full_transcript_handle (crates/tui/src/tools/subagent/mod.rs:4551, called only from the Cancelled/Interrupted/BudgetExhausted/end-of-loop terminal branches — mod.rs:5038,5168,5233,5331,5609). The codebase's own subagent_session_projection (mod.rs:3174-3192) is explicit about this: it only looks up the full_transcript handle if snapshot.status != SubAgentStatus::Running; otherwise it inserts a differently-named "transcript" handle instead.
So for a running worker, handle_read on the advertised agent:<id>/full_transcript reference will fail with "handle_read: no payload found for handle agent:<id>/full_transcript" (crates/tui/src/tools/handle.rs:281-286). That directly contradicts the PR's stated guarantee ("gated ... so an empty transcript is never advertised") — it's not empty, it's nonexistent. The new unit tests only assert against the SidebarAgentRow struct in isolation, so they can't catch this mismatch against the real handle store.
Suggested fix: only advertise the handle once the worker is terminal (sidebar_agent_status_is_terminal(row.status)), or point running workers at the live agent:<id>/transcript name instead of full_transcript to match what subagent_session_projection actually inserts while running.
Fixes #4094
Completes the four items the reopen comment listed as still-open after PR #4182 (which shipped the live-activity trail, tool-call name/status, final summary/handoff, and bounded histories). Single-file change to
crates/tui/src/tui/sidebar.rs(the detail-panel renderer #4182 added): three test additions, two small width-safety fixes they exposed, and one bounded artifact-handle feature.The four remaining items
1. Many-tool-call state coverage + tests. A worker that has fired hundreds of tool calls now provably renders correctly — non-empty, carrying the live tool-call trail (name + compact status) and the step count, width-bounded, plus an inspect-more handle. Distinct from #4182's existing many-agents bound test.
subagent_expanded_detail_renders_many_tool_calls_without_overflow— asserts the dossier line carries247 step(s)andgrep_files, no blank lines, and (rendered narrow) no line overflows the column.2. Narrow-width readability + tests. Every rendered line — header, role-mix, label, dossier, handle — is now clamped to the column. This exposed and fixed two real overflows:
format!(" {}", truncate(.., width-2))overflowed by the 2-space indent atcontent_width < 3→ newindented_detail_line()clamps indent + body together;N running / Mheader was never truncated and spilled past narrow columns → it now collapses to a single truncated span when it doesn't fit (status clipped, never spilled).subagent_detail_readable_and_bounded_across_narrow_widths— asserts no line overflows across widths[1,2,3,5,8,12,16,20,24,32,48]and that the status verb stays visible at a usable-narrow width (24).3. Explicit running/done/failed state matrix + tests.
subagent_status_matrix_renders_marker_verb_and_style— forrunning/done/failed/canceled/interrupted, asserts the label renders the right marker ([~]/[✓]/[!]/[-]), the right state color on the span, and that the dossier surfaces the status verb.4. Artifact/receipt handle for full output (vs. inline dump). Instead of dumping the full sub-agent transcript inline (the freeze/emptiness risk this issue tracks), the panel renders a bounded preview plus a copyable handle to the fuller artifact:
▸ full output · handle_read agent:<id>/full_transcript. This reuses the existing, documented sub-agent transcript var-handle — the sameagent:<id>/full_transcripthandle thatsubagent_session_projectionmaterializes and thatdefault_subagent_artifactsdocuments as the inspect path — so it adds no new artifact infrastructure. The handle is gated (subagent_output_handle) so an empty transcript is never advertised, guarded bymax_rows, and truncated so it never overflows.subagent_completed_worker_surfaces_output_handle_not_inline_dump(completed worker shows the transcript handle and still shows the bounded summary; handle line is non-clickable),subagent_output_handle_gated_on_inspectable_output(fresh zero-step worker → no handle; running-with-steps and terminal workers → handle).Scope of item 4 (transparent boundary)
This is a bounded feature per the issue's feasibility gate — a copyable handle reference the user runs via the existing
handle_readtool, reusing existing plumbing. It intentionally does not add a new artifact system. Optional future enhancements (not required by the AC, flagged for the maintainer): making the handle line click-to-open the transcript in-TUI, and surfacing richer receipt kinds (patch / test_result / report) beyond the transcript handle.Notes
DEEPSEEK*env names renamed/removed.Verification
cargo fmt --all --check→ cleancargo clippy --workspace --all-features --locked -D warnings(gate allow-list) → cleancargo test --workspace --locked→ 5996 passed; the only 2 failures are the known pre-existing unrelated ones (git_repo_root_reports_attempted_paths_when_no_repo_found,skill_hotbar_action_activates_skill_through_dollar_alias), confirmed failing on pristineorigin/mainwith this change stashedcargo build --release -p codewhale-tui→ ok