fix(chat): render correct line count under each parallel bash marker#4003
Closed
CnsMaple wants to merge 1 commit into
Closed
fix(chat): render correct line count under each parallel bash marker#4003CnsMaple wants to merge 1 commit into
CnsMaple wants to merge 1 commit into
Conversation
Back-to-back tool dispatches with DeepSeek-style call_N ids rendered
the second and subsequent markers as '⎿ -1 lines' (or, with a prior
defensive guard, a blank slot) because:
* streamToolOutput resets m.toolLineCount whenever it switches to a
new tool id, losing the previous id's count.
* collapseShellSlot's late path was the only place the count could be
recovered, and it derived it from m.shellOutputs[id] — which is
only populated for shell-prefixed ids (string-gated at the
streamToolOutput write site). call_N ids never made it into the
map, so n fell through to -1.
Fix:
* Add a per-id line-count stash (m.toolLineCountByID). When
streamToolOutput is about to switch active id, it captures the
current (toolLineCount + (toolPartial != '')) so the old id's
value survives.
* Thread the ToolResult's final output through collapseToolOutput
and collapseShellSlot as a last-resort source of truth for the
line count. This handles a tool that never streamed (the result
is the only signal) and lets the active path use the larger of
the live line count and the final output (so a slow tool's last
chunk arriving in the same event as the result isn't lost).
* collapseShellSlot's late path now falls back through
shellOutputs -> toolLineCountByID -> resultOutput -> 0, and the
n<0=0 guard replaces the previous '⎿ -1 lines' rendering.
Regression coverage (internal/cli/consecutive_tool_markers_test.go):
* TestParallelBashMarkersKeepOwnLineCount: 3 parallel Bash(ls)
dispatch with 22 lines of streaming output each, verifying each
card's marker slot reports '⎿ 22 lines' and the transcript
contains no '-1 lines'.
* TestNonShellToolLateResultShowsCorrectCount: 2 back-to-back bash
tools with no ToolProgress between them, verifying the result's
own output drives the marker line count.
The new fields are initialized in newChatTUI and the test helper
newTestChatTUI.
Owner
|
Thanks for this — the fix is correct and the regression tests are exactly what this needed. CI was only red on a |
esengine
added a commit
that referenced
this pull request
Jun 11, 2026
…4010) Parallel call_N-style bash tools lost their per-call line count: streamToolOutput reset the active id's count on every switch and collapseShellSlot's late path only recovered it from shellOutputs (shell- ids only), so call_N ids rendered '-1 lines'. Stash the per-id count before reset and accept the ToolResult output as a last-resort source. Closes #4003
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated by AI (CnsMaple + Reasonix)
Summary
Follow-up to #3951 + #3973. Rebased onto current
main-v2(c5c3093); preserves both merged fixes in place. Adds two targeted changes tocollapseShellSlot's late path:m.toolLineCountByID). WhenstreamToolOutputis about to switch active id, it captures(toolLineCount + (toolPartial != ""))keyed by the old id, so the count survives the reset that used to drop it on the floor.ToolResultoutput threaded through.collapseToolOutput/collapseShellSlotnow take the result's finalOutputand use it as the last-resort source for the line count, aftershellOutputsandtoolLineCountByIDhave had their say.Why this exists
After #3951 + #3973, the
-1 linesrendering is gone and late-collapsed slots repaint immediately. But the visual result for a back-to-back bash dispatch with real output is now a blank line under every tool that was overtaken —● Bash(ls) / [empty] / ● Bash(ls) / [empty] / ● Bash(ls) / ⎿ 22 lines. The third tool's marker is correct (it never got overtaken) but the first two lose their line count even though the run actually produced 22 lines each.I want to flag this as a behavioural choice, not an oversight: the
#3951review comment by @esengine explicitly says "clearing the slot instead of fabricating a count is the right call" and accepts "a blank line — visible but harmless" as the trade-off. This PR takes the opposite trade-off — always show a real line count when one can be recovered, blank only when there's truly no signal. Either is defensible; the test below is the tripwire that makes the choice explicit so the next person reading the code can see what's being committed to.Repro before this PR
Transcript on
main-v2(post-#3951 + #3973):Transcript with this PR
Fallback chain in
collapseShellSlot's late pathActive path uses
max(toolLineCount, len(resultOutput))— the live state is sometimes lower than the result's actual end-state if the last chunk of a slow tool arrived in the same event as the result, and we'd rather render the authoritative count.Regression tests (in
internal/cli/consecutive_tool_markers_test.go)TestParallelBashMarkersKeepOwnLineCount— 3 parallelBash(ls)× 22 lines, asserts no-1 linesanywhere and that each card's marker slot reports⎿ 22 lines. Pre-fix onmain-v2: fails withc1 marker at transcript[1] should contain ⎿, got "". With this PR: passes.TestNonShellToolLateResultShowsCorrectCount— 2 back-to-back bash tools with noToolProgressbetween them; the result is the only signal. Verifies the slot ends with⎿ N linesdriven bye.Tool.Output, not blank.The pre-existing
TestConsecutiveNonShellToolsDoNotRenderNegativeLineCount(from #3951) andTestConsecutiveToolCallsKeepMarkersUnderOwnCard(from #3951) both continue to pass.Scope notes
collapseToolOutput/collapseShellSlotsignature change:id, idx→id, idx, resultOutput. The new param is plumbed fromingestEvent'sToolResultcase (where we havee.Tool.Outputin hand) and the other three call sites pass""(no result available in those flows).toolLineCountByIDis initialised in bothnewChatTUIand the test helpernewTestChatTUI. Map entries are written only on id switches where the outgoing count is > 0; the entry is read once and discarded after the matchingToolResultis collapsed.transcriptDirty = trueinsidecollapseShellSlot(fix(chat): repaint late-collapsed tool slots immediately #3973) is preserved. The duplicatetranscriptDirtyI originally added incollapseToolOutput's active path was dropped during the rebase — the function-body assignment covers both callers and is the cleaner location.Label
tui— Terminal UI / CLI (internal/cli, internal/control).