Skip to content

feat: argument pickers for slash commands (/model, /resume, …) - #5

Merged
wowi42 merged 4 commits into
mainfrom
feat/slash-argument-pickers
Sep 8, 2026
Merged

feat: argument pickers for slash commands (/model, /resume, …)#5
wowi42 merged 4 commits into
mainfrom
feat/slash-argument-pickers

Conversation

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor

What

Slash commands with known options now complete their arguments in the same themed panel as the /, @ and . pickers — no more typing model ids or session ids by hand.

Typing /model (or accepting /model from the / menu) opens the panel with live catalog rows; Enter/Tab inserts (canonical id + trailing space), a second Enter executes, Escape dismisses without executing.

Coverage

Providers gate on already-typed args: consumed positions close the menu, nested positions offer the next stage.

  • /model, /model-subagent (+default), /pierre model — catalog, honoring ui.hidden_models, current marker
  • /resume — sessions newest-first (current / in-use markers); --delete completes targets, but --delete is never offered by default
  • /thinking /reasoning /permissions /mode /notifications /tutor /memory /help — literal choices
  • /rewind (recent turns), /drop (pending attachments), /mcp (subcommands, then server names), /wt-exit (flags, in-worktree only)
  • Free-text/path commands untouched — path completion still works (/loop plan.md), and path completion is suppressed while an argument picker owns the token (/model vendor/x is a model ref, not a file)

Details

  • SlashCommand.arg_completions provider + arg_empty_hint (registry), routing completer + arg context detection (pickers), panel inert rows ("no models available (catalog still loading?)", "no matching options"), Escape dismissal per typed text, single-slot row cache keyed by typed text (cleared when the background catalog fetch lands)
  • All handler validation stays authoritative; selecting never executes
  • Ambiguous /mod still closes the menu (existing behavior kept, test still green)

Testing

  • 20 new tests (picker unit + interactive), ruff clean
  • Full suite: 1143 passed (only pre-existing telemetry failures from the missing optional extra)

🤖 Generated with lecode

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor Author

The macos-latest 3.14 failure was a pre-existing harness race, not a regression: pty drivers sent their first keystroke after a fixed asyncio.sleep(0.8), but prompt_toolkit only enters raw mode (and flushes pre-start input) as app.run takes over the terminal. On a slow runner the byte landed early — echoed by the line discipline (the stray / below the statusline in the dump) and never delivered.

Fixed at the root in _run_pty_app: drivers now start only after the first real render (dir: on screen ⇒ raw mode active). Linux can't reproduce (5× passes before and after); the gate makes the race impossible on any runner.

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor Author

Second CI hit investigated to ground truth. Both dumps decode the same way:

  • The failing test's screen shows the "Session …: tokens 0 in / 0 out" exit-totals line printed below the frozen UI — that line only prints when the TUI exits (print_totals in TuiApp.run's finally). So the app exited on its own right after startup, before the driver typed anything. The / that follows was echoed by the line discipline into a now-cooked, appless tty — never delivered, hence the 15s timeout with a misleading "timed out waiting for 'commands'" dump.
  • The traceback (return await driven reached) proves the app task finished early and cleanlyrun() swallows EOFError | KeyboardInterrupt, so the harness never learned why.

Not reproducible locally: 15+ plain runs, single-core + CPU-load runs, Python 3.14.7 isolated, 21+ instrumented stress rounds (wrapping run_async and PosixStdinReader to log the real exception), full suite concurrently. The trigger only exists on CI runners.

Three changes now shipped on this branch:

  1. TuiApp.run names the swallowed exception on stderr ("lecode: exiting on EOFError/KeyboardInterrupt") — previously a silent swallow; the next occurrence is diagnosable in CI logs.
  2. The pty harness fails fast: driver and app task are raced; if the app dies mid-flow, the test aborts immediately with _AppExitedEarly instead of stalling 15s on a dead tty. A real app crash still re-raises with its full traceback (no retry masking).
  3. One retry on exactly that signature (_run_pty_app wrapper) so the unreproducible environment flake stops blocking the PR; it prints loudly to stderr and does not retry real failures.

Verified: new fail-fast/retry regression test passes, full pty file 10/10, full suite 1144 passed (telemetry failures pre-existing), ruff clean.

@wowi42
wowi42 merged commit 2419ec5 into main Sep 8, 2026
4 checks passed
@wowi42
wowi42 deleted the feat/slash-argument-pickers branch September 8, 2026 10:10
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.

2 participants