Skip to content

Keep following chat panes filled while output streams #201

@dnouri

Description

@dnouri

When I keep one chat pane at the bottom and another pane on earlier context, new assistant output should keep the bottom pane useful. It should not show a few new lines followed by a big empty area while the real tail is already visible.

A tmux-driven emacs -nw validation run found one way this can still happen. The thinking-collapse rewrite itself is fixed, but the next streamed output can leave a split tail-following pane underfilled.

What the user sees

In terminal Emacs with the chat buffer split into two stacked windows:

  • the top window is following the chat tail;
  • the bottom window is reading earlier context;
  • after a thinking display toggle and the next assistant output starts, the top pane can show only a handful of new lines and then blank space.

The pane is technically at the tail, but it does not feel like a chat tail pane because it is not filled.

Observed during the visual run:

== after display-agent-start ==
tail: start L125  S10 after line 046
      point L134  row 8
      tail=t      blank=9  body=17

== after display-message-delta ==
tail: start L138  S10 streamed tail line after toggle 005
      point L146  row 8
      tail=t      blank=9  body=17

The context pane stayed anchored correctly. The problem is only the tail-following pane being underfilled.

Expected behavior

A following chat window should stay pinned to the useful tail view. If there is enough buffer text to fill the pane, it should leave at most the normal small amount of blank space below the tail.

A non-following sibling window should still keep its reading position.

Likely cause

The normal streaming scroll helper is weaker than the rewrite-preservation helper.

In pi-coding-agent-ui.el, pi-coding-agent--with-scroll-preservation detects following windows with pi-coding-agent--window-following-p. After the insert, it restores following windows with only:

(set-window-point win (point-max))

That puts point at the buffer end, but Emacs only has to make point visible. In a split window it may leave point around the middle of the pane, which leaves blank rows below it.

The new rewrite-preservation path in pi-coding-agent-render.el does the stronger thing for tail windows:

(goto-char point-max)
(recenter -1)

That is why the collapse/toggle rewrite stays filled, but the next normal stream can underfill the tail pane again.

A likely fix

Make following windows in pi-coding-agent--with-scroll-preservation bottom-pin themselves instead of only moving point.

The shape is probably a small helper in pi-coding-agent-ui.el:

(defun pi-coding-agent--scroll-window-to-tail (window)
  "Move WINDOW to the current buffer tail and keep the view filled."
  (when (and (window-live-p window)
             (eq (window-buffer window) (current-buffer)))
    (with-selected-window window
      (goto-char (point-max))
      (recenter -1))))

Then the following-window loop in pi-coding-agent--with-scroll-preservation can use that helper under save-selected-window. The existing non-following-window preservation should stay as-is.

Suggested test

A good red test would use a real windowed ERT setup:

  1. create a chat buffer with enough content to fill split windows;
  2. split the buffer into two stacked windows;
  3. put the top window at the tail;
  4. put the bottom window on earlier content;
  5. append a short assistant header or call pi-coding-agent--display-agent-start;
  6. assert the top window still reaches the tail and has at most one blank row;
  7. assert the bottom window's start/point did not move.

A slightly fuller regression can include the path that found the issue: whole-chat thinking display toggle, then pi-coding-agent--display-agent-start, then pi-coding-agent--display-message-delta.

The important red assertion appears immediately after pi-coding-agent--display-agent-start, before any long stream is needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions