Skip to content

fix(tui): make user_prompt elicitation dialog scrollable#2509

Merged
dgageot merged 1 commit intodocker:mainfrom
dgageot:board/fix-docker-agent-github-issue-2495-35d25358
Apr 27, 2026
Merged

fix(tui): make user_prompt elicitation dialog scrollable#2509
dgageot merged 1 commit intodocker:mainfrom
dgageot:board/fix-docker-agent-github-issue-2495-35d25358

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented Apr 25, 2026

Fixes #2495.

When `user_prompt` opens an elicitation pop-up with many enum items (or many fields, or a long message), the dialog overflowed the bottom of the terminal with no way to access the clipped content — neither visually nor for keyboard navigation.

What changed

The body region (message + fields, or message + free-form input) is now rendered inside a scrollview, capped at 80% of the terminal height (max 40 rows). Title/separator stay fixed at the top, the help line stays fixed at the bottom.

  • The scrollview consumes mouse wheel, scrollbar drag, and PgUp/PgDn/Home/End. Up/Down keep their existing role of cycling enum/boolean selections.
  • Auto-scroll keeps the focused field's active line visible:
    • Tab / Shift-Tab brings the new field into view.
    • Up/Down inside an enum/boolean keeps the selected option in view even when the field is taller than the viewport.
    • Submit-with-error focuses and scrolls to the offending field.
  • Mouse clicks translate the absolute Y through the current scroll offset before mapping to a field/option, so clicks on visible options still work when scrolled.
  • The help line gains a `pgup/pgdn scroll` hint when scrolling is active.
  • A single `layout()` method computes geometry (dialog width, viewport, body lines, per-field line offsets) shared by `View()` and `Position()` so layout math lives in one place.
  • `buildBody` tracks line offsets incrementally to stay O(N) in the number of fields.

Tests

New unit tests in `pkg/tui/dialog/elicitation_test.go`:

  • `TestElicitationDialog_LongEnumScrolls` — 30-option enum on a 20-row terminal needs a scrollbar; selecting an option near the end auto-scrolls it into view.
  • `TestElicitationDialog_FieldsBelowFold_AreReachable` — tabbing through 15 fields on an 18-row terminal keeps each focused field visible.
  • `TestElicitationDialog_SmallContent_NoScrollbar` — small dialogs do not show a scrollbar.

All existing tests still pass; `golangci-lint run ./...` is clean.

How to test manually

```yaml

/tmp/triage.yaml

version: "2"
agents:
root:
model: openai/gpt-5
description: Triage tester
instruction: |
As soon as the user says anything, call user_prompt EXACTLY ONCE with a
'category' enum field whose 12 options are long incident-triage labels.
toolsets:
- type: user_prompt
```

```sh
./bin/cagent run /tmp/triage.yaml

type any message → dialog appears with a scrollbar; Up/Down/PgUp/PgDn navigate;

all 12 items are reachable; mouse wheel & scrollbar drag work.

```

Fixes docker#2495.

When `user_prompt` opens an elicitation pop-up with many enum items
(or many fields, or a long message) the dialog overflowed the bottom
of the terminal with no way to access the clipped content — neither
visually nor for keyboard navigation.

The body region (message + fields, or message + free-form input) is
now rendered inside a scrollview, capped at 80% of the terminal
height (max 40 rows). Title/separator stay fixed at the top, the help
line stays fixed at the bottom.

- The scrollview consumes mouse wheel, scrollbar drag, and
  PgUp/PgDn/Home/End. Up/Down keep their existing role of cycling
  enum/boolean selections.
- Auto-scroll keeps the focused field's active line visible: Tab /
  Shift-Tab brings the new field into view, and Up/Down inside an
  enum/boolean keeps the selected option in view even when the field
  itself is taller than the viewport. Submit-with-error focuses and
  scrolls to the offending field.
- Mouse clicks translate the absolute Y through the current scroll
  offset before mapping to a field/option, so clicks on visible
  options still work when the dialog is scrolled.
- The help line gains a "pgup/pgdn scroll" hint when scrolling is
  active.
- A single layout() method computes geometry (dialog width, viewport,
  body lines, per-field line offsets) shared by View() and
  Position(), so layout math lives in exactly one place.
- buildBody tracks line offsets incrementally to stay O(N) in the
  number of fields.

Tests cover long enums (30 options on a 20-row terminal), many
fields below the fold (15 fields on an 18-row terminal), and small
content that should not show a scrollbar.

Assisted-By: docker-agent
@dgageot dgageot requested a review from a team as a code owner April 25, 2026 18:00
@dgageot dgageot merged commit d84a8a6 into docker:main Apr 27, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

user_prompt pop-up truncates long content — no scroll in TUI

2 participants