Compare commits

...
Author SHA1 Message Date
Gnanam d52b26f4db fix(tui): show the queued-message preview above the composer, not below
A message typed while a run is active is queued for the next turn. Its
"[queued] …" preview rendered on the line BELOW the input box; move it to
directly ABOVE the box so it reads as "waiting to send," sitting on top of
what you're currently typing, and doesn't get visually detached from the
composer by the status line beneath it. Footer height is unchanged (the
preview line just moves from below to above the box).

New test: TestQueuedPromptPreviewSitsAboveComposer asserts the preview
line index is above the composer box top border.
2026-07-01 23:22:33 +05:30
2 changed files with 39 additions and 4 deletions

No files matched your search

+7 -4
View File
@@ -2235,15 +2235,18 @@ func (m model) footerView(width int) string {
footer.WriteString(fitStyledLine(joinHeaderLine(" "+left, right, width), width))
}
footer.WriteString("\n")
// A message typed while a run is active is queued for the next turn; show its
// preview directly ABOVE the input box (not below), so it reads as "waiting to
// send" sitting on top of what you're currently typing.
if queued := renderQueuedMessagePreview(m.queuedMessage, width); queued != "" {
footer.WriteString(queued)
footer.WriteString("\n")
}
footer.WriteString(m.composerBox(width))
if hint := m.composerDescriptionHint(width); hint != "" {
footer.WriteString("\n")
footer.WriteString(hint)
}
if queued := renderQueuedMessagePreview(m.queuedMessage, width); queued != "" {
footer.WriteString("\n")
footer.WriteString(queued)
}
footer.WriteString("\n")
footer.WriteString(m.statusLine(width))
return footer.String()
+32
View File
@@ -55,6 +55,38 @@ func TestQueuedPromptPreviewAppearsInView(t *testing.T) {
}
}
// TestQueuedPromptPreviewSitsAboveComposer: the queued-message preview must
// render ABOVE the input box, not below it — a message waiting to send should
// sit on top of what you're currently typing.
func TestQueuedPromptPreviewSitsAboveComposer(t *testing.T) {
m := newQueuedMessageTestModel(t)
m.pending = true
m.activeRunID = 1
m.runID = 1
m.width = 96
m.input.SetValue("summarize the failing test output")
updated, _ := m.Update(testKey(tea.KeyEnter))
next := updated.(model)
footer := plainRender(t, next.footerView(96))
lines := strings.Split(footer, "\n")
queuedLine, composerTopLine := -1, -1
for i, ln := range lines {
if queuedLine < 0 && strings.Contains(ln, "queued") {
queuedLine = i
}
if composerTopLine < 0 && strings.Contains(ln, "╭") { // composer box top border
composerTopLine = i
}
}
if queuedLine < 0 || composerTopLine < 0 {
t.Fatalf("expected both a queued line and a composer box; queued=%d composer=%d\n%s", queuedLine, composerTopLine, footer)
}
if queuedLine >= composerTopLine {
t.Fatalf("queued preview (line %d) must sit ABOVE the composer box top border (line %d):\n%s", queuedLine, composerTopLine, footer)
}
}
func TestAgentResponseLaunchesQueuedPrompt(t *testing.T) {
provider := &scriptedProvider{scripts: [][]zeroruntime.StreamEvent{{
{Type: zeroruntime.StreamEventText, Content: "queued answer"},