Skip to content

fix(agent): width-aware interactive prompt/status line (#209) - #211

Open
justrach wants to merge 1 commit into
mainfrom
fix/209-width-aware-prompt
Open

fix(agent): width-aware interactive prompt/status line (#209)#211
justrach wants to merge 1 commit into
mainfrom
fix/209-width-aware-prompt

Conversation

@justrach

Copy link
Copy Markdown
Owner

Problem

Agent.prompt emitted the full model/effort/provider/mode/cwd/context status line with no width budget, so a narrow terminal pane soft-wrapped it mid-badge (e.g. splitting codex) and left the cursor visually inside a label:

[gpt-5.6-sol · High · co

readline.zig only reacts afterward by moving the input to a fresh row; by then the status string has already wrapped.

Fix

prompt() budgets each segment against termCols():

  • The model plus the settings that disambiguate the cursor (effort, provider, mode badges) are offered first; cwd/context/cache/cost are dropped when they no longer fit.
  • The context meter outranks cwd for the budget (it is the urgent, changing signal near the compaction threshold) but still renders after cwd, so the familiar left-to-right order is kept when both fit.
  • The line reserves the fixed frame ([] › ) plus a column of slack, so nothing but a model name longer than the pane can wrap; readline then gives the input its own row as before.

Progressive disclosure at increasing widths (captured from a real PTY):

cols=28   [deepseek-v4-pro] ›
cols=34   [deepseek-v4-pro · Medium] ›
cols=50   [deepseek-v4-pro · Medium · codegraff] ›
cols=120  [deepseek-v4-pro · Medium · codegraff · cwd /…] ›

The wcwidth-style dispWidth/codepointWidth table moves from repl.zig into term.zig (the shared terminal-utilities leaf) so the TUI table math and this budgeting share one definition; repl.zig delegates and keeps its #142 test.

Tests

  • New scripts/test-pty-narrow-prompt.py — drives a real 28-col PTY and asserts the line fits, badges stay whole, and cwd is dropped, while a wide pane still shows cwd.
  • scripts/test-pty-repl.py widened to 200 cols so its badge-state session fits the full line.
  • zig build test 184/184, zig fmt clean, full PTY suite green.

Closes #209

Agent.prompt emitted the full model/effort/provider/mode/cwd/context status line
with no width budget, so a narrow terminal pane soft-wrapped it mid-badge (e.g.
splitting `codex`) and left the cursor visually inside a label. readline.zig only
reacts after the fact by moving the input to a fresh row; the status string had
already wrapped.

prompt() now budgets each segment against termCols(): the model plus the settings
that disambiguate the cursor (effort, provider, mode badges) come first, and
cwd/context/cache/cost are dropped when they no longer fit. The context meter
outranks cwd for the budget (the urgent, changing signal near the compaction
threshold) but still renders after cwd so the familiar order is kept when both
fit. The line reserves the fixed frame plus a column of slack, so nothing but a
model name longer than the pane can wrap; readline then gives the input its own
row as before.

The wcwidth-style dispWidth/codepointWidth table moves from repl.zig into
term.zig (the shared terminal-utilities leaf) so the TUI table math and this
budgeting share one definition; repl.zig delegates and keeps its #142 test.

Tests: new scripts/test-pty-narrow-prompt.py drives a real 28-col PTY and asserts
the line fits, badges stay whole, and cwd is dropped, while a wide pane still
shows cwd; test-pty-repl.py widened to 200 cols so its badge-state session fits
the full line; zig build test 184/184, zig fmt clean, full PTY suite green.

Refs #209

Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
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.

CLI prompt/status line is cut off or splits badges in narrow terminal panes

1 participant