Skip to content

simplify prompt bar controls - #2183

Open
kevinjosethomas wants to merge 21 commits into
mainfrom
feat/ui-prompt-bar
Open

simplify prompt bar controls#2183
kevinjosethomas wants to merge 21 commits into
mainfrom
feat/ui-prompt-bar

Conversation

@kevinjosethomas

@kevinjosethomas kevinjosethomas commented Sep 10, 2026

Copy link
Copy Markdown
Member

Show muted conversation detail status directly above the prompt, with recap on the left and ellipsis truncation reserving room for the status. A blank line separates this row from the chat; there is no gap before the prompt surface. Empty extension widgets add no extra separator.

  • Show the provider-free model ID and lowercase reasoning effort as glm-5.3:high, followed by fast mode when active and live context usage, in the bottom-right tray. Keep manage navigation on the bottom left.
  • Remove unsolicited feature-discovery tips during agent runs, startup example prompts, and the fresh-chat shortcut hint. Explicit help and picker instructions remain available.
  • Keep the lower tray and subagent summary visible during slash-command autocomplete; hide them only for actual pickers and restore them on dismissal. Show depth only for subagent sessions.
  • Keep slash autocomplete completion-only: Tab or Enter completes, and a subsequent Enter runs the command.
  • Preserve drafts, custom editor headers, narrow layouts, configurable detail shortcuts, and live context tracking through streaming and compaction.

Validation: 216 focused prompt layout, startup, status/context usage, and recap regression tests passed after the final position swap; 61 startup tests, including 24 composed layout combinations and actual autocomplete/picker overlay transitions, passed after the final visibility fix; npm run check passed.

Fixes ENG-6113.
Design: Prime Agent UI/UX Improvements.

Note

Remove feature hints and reorganize prompt bar labels and completion in InteractiveMode

  • Deletes the entire feature-hint system: FeatureHintComponent, the hint deck, scheduling, animation, and suppression logic are removed from InteractiveMode and its tests.
  • Adds PromptContextLine to render the session recap and a right-aligned conversation-detail status above the prompt with a blank separator row. renderRecap now uses this component instead of directly prefixing recap text.
  • Replaces the old model tray formatter with getModelContextLabel, which combines the normalized model ID, reasoning level, priority tier, and context usage into one dimmed, width-limited label. Tray location and context labels are simplified to show only the manage hint and non-root session depth.
  • SubagentSummaryLine now hides entirely while a picker is open and drops the bold escape from the subagents label.
  • Slash-command completion no longer appends a trailing space for no-argument commands like /model; CANONICAL_BUILTIN_SLASH_COMMANDS removes takesArgument: true from the model entry. Editor confirm handling now falls through to Enter when a completion leaves text unchanged.
  • Behavioral Change: no-argument slash commands complete bare (cursor directly after the name) and require a second Enter to submit; argument-taking commands still get a separating space. Tray labels no longer show new-chat shortcuts or model metadata in the location section.

Macroscope summarized 129fa2c.


Note

Low Risk
Mostly terminal UI layout and input completion behavior; no auth, data, or session persistence changes beyond display logic.

Overview
Reworks the interactive prompt area so recap and conversation detail status (Collapsed / Details / All output mode) share one muted row directly above the input via new PromptContextLine, with a blank line separating that row from the chat. Model name, effort, fast mode, and live context usage move into the bottom tray (modelId:effort · tokens), while the upper row no longer duplicates token usage.

Removes the feature-discovery hint stack (animated hints during agent runs, startup splash/editor example prompts, and the fresh-chat shortcut hint in the tray). Session navigation in the tray is renamed to manage; depth shows only for subagent sessions. The tray and subagent summary hide while real pickers/overlays are open but stay visible during slash-command autocomplete.

Slash autocomplete is completion-only: Tab/Enter completes without auto-submit; a second Enter runs the command. No-argument commands (including /model) complete without a trailing space; argument-taking commands still open a parameter slot. /model is no longer treated as a free-form argument command at the builtin metadata level.

Reviewed by Cursor Bugbot for commit 129fa2c. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown

Prime Agent performance — partial

PR 129fa2c6 compared with main 5255a6b8.

Overall: 3 regressed · 0 improved · 10 no clear change · 4 unavailable.

Metric Main This PR Change
Cold startup 3,094.6 ms
Warm startup 1,787.7 ms
Installation 27.01 s 27.60 s ≈ +0.59 s (+2.20%)
Compressed release artifacts 11.13 MB 11.09 MB ≈ -0.04 MB (-0.35%)
Installed footprint
Idle memory, summed RSS 1,131.37 MB

Python runtime

Metric Main This PR Change
Python kernel startup 131.6 ms 165.2 ms $\textcolor{#b9615f}{\textsf{↑ +33.6 ms (+25.57\%)}}$
Python cell round trip 0.545 ms 0.657 ms $\textcolor{#b66360}{\textsf{↑ +0.112 ms (+20.49\%)}}$
Empty bash command 12.8 ms 14.6 ms ≈ +1.8 ms (+14.22%)
Bash git status 18.7 ms 21.0 ms ≈ +2.3 ms (+12.33%)
Bash 32 KiB output 12.5 ms 14.6 ms ≈ +2.1 ms (+16.97%)
35 cells / 9 shell calls 177.5 ms 221.9 ms $\textcolor{#b9625f}{\textsf{↑ +44.3 ms (+24.97\%)}}$
Python interrupt to done 1.536 ms 1.743 ms ≈ +0.207 ms (+13.47%)
Python state snapshot 27.0 ms 30.5 ms ≈ +3.5 ms (+12.82%)
Python state restore 393.9 ms 450.2 ms ≈ +56.3 ms (+14.29%)
Python idle RSS 33.68 MB 34.56 MB ≈ +0.88 MB (+2.62%)
Python RSS after pandas workload 95.79 MB 96.70 MB ≈ +0.91 MB (+0.95%)

Sandbox cost: ~$0.1823 — no inference calls.
Run, logs, and downloadable raw results

Methodology and samples

Main resolved at 2026-09-11T20:17:26.909790+00:00. Harness 5255a6b8.
Linux x64, 4 vCPU, 8 GB RAM, 20 GB disk; region us.
Image: node:24-bookworm@sha256:be23f54a88d34e8824c741b19b91064094f92c1c97b194144bfc8b50d67258e2.
Stock tools, skills, daemon, and Python bootstrap enabled; fresh homes and a fixed Git fixture.
Onboarding is dismissed; the editor starts without a selected model or submitted prompt.
Medians shown. Arrows require a 20% timing/memory change plus absolute floors and IQR.
These practical noise floors are not a statistical significance test.
Cold means stopped Prime processes; OS filesystem caches are not flushed.
No model requests or credentials. Installation excludes build/setup time.
Installer tarballs use loopback; npm/Python downloads use the network with fresh caches.
Artifact size counts release tarballs; footprint after first use includes registry packages.
MB is decimal. Summed RSS can double-count shared pages; PSS is recorded when available.
Provisioning, setup, and build durations are recorded separately in the raw results.
Kernel probes use the installed JSONL runtime, outside the TUI/TypeScript host.
Per trial: 50 Python cells, 5 calls per shell case, and one 35-cell mix (9 git status calls).
Cell/shell values are batch means; other runtime timings are single operations.
State fixture: a 10,000-row × 8-column integer DataFrame and a 10,000-integer list.
Restore runs in a fresh kernel, including pandas imports; kernel startup is excluded.
Kernel RSS covers the isolated Python process; loaded RSS follows the pandas workload.
Costs estimate full sandbox lifetimes at configured rates, including setup and build.
Budget target: $1; not a billing cap. Checks are informational.

Metric Main successful/attempted PR successful/attempted Main spread PR spread
Cold startup 10/10 0/10 IQR 572.4 ms
Warm startup 9/9 0/10 IQR 110.5 ms
Installation 3/3 3/3 range 1.12 s range 1.09 s
Compressed release artifacts 1/1 1/1
Installed footprint 0/0 0/0
Idle memory, summed RSS 10/10 0/0 IQR 112.77 MB
Python kernel startup 10/10 10/10 IQR 7.1 ms IQR 25.2 ms
Python cell round trip 10/10 10/10 IQR 0.062 ms IQR 0.067 ms
Empty bash command 10/10 10/10 IQR 1.6 ms IQR 0.7 ms
Bash git status 10/10 10/10 IQR 3.1 ms IQR 3.9 ms
Bash 32 KiB output 10/10 10/10 IQR 1.3 ms IQR 2.8 ms
35 cells / 9 shell calls 10/10 10/10 IQR 13.0 ms IQR 17.2 ms
Python interrupt to done 10/10 10/10 IQR 0.087 ms IQR 0.161 ms
Python state snapshot 10/10 10/10 IQR 4.2 ms IQR 3.7 ms
Python state restore 10/10 10/10 IQR 29.7 ms IQR 29.7 ms
Python idle RSS 10/10 10/10 IQR 3.47 MB IQR 3.76 MB
Python RSS after pandas workload 10/10 10/10 IQR 3.77 MB IQR 3.97 MB

Failures:

  • main measure 0: RuntimeError
  • main: CalledProcessError: Command '['/usr/sbin/runuser', '-u', 'benchmark1', '--', 'prime-agent', 'stop', '474e3236dd52', '--json']' returned non-zero exit status 1.
  • PR cold trial 0: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 1: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 2: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 3: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 4: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 5: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 6: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 7: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 8: TimeoutError: Timed out waiting for the expected terminal state
  • PR cold trial 9: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 0: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 1: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 2: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 3: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 4: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 5: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 6: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 7: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 8: TimeoutError: Timed out waiting for the expected terminal state
  • PR warm trial 9: TimeoutError: Timed out waiting for the expected terminal state

Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts Outdated
kevinjosethomas added a commit that referenced this pull request Sep 10, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

private readonly getLocationLabel: () => string | undefined = () => undefined,
private readonly getContextLabel: () => string | undefined = () => undefined,
private readonly getOverrideLabel: () => string | undefined = () => undefined,
private readonly getPickerOpen: () => boolean = () => false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hidden summary remains focusable

Low Severity

render now returns no rows while a picker is open, but isSelectable still treats the summary as available. focusSubagentSummary only gates on isSelectable and getTrayOverrideLabel, and the override label is now forced off during pickers, so focus can move onto an invisible row and swallow input.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9aff542. Configure here.

Comment thread packages/coding-agent/.changes/ui-prompt-bar.md Outdated
);
const isSlashCommand = slashContext?.kind === "name" && slashContext.prefix === prefix && command !== undefined;
if (isSlashCommand) {
const takesArgument =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium src/autocomplete.ts:401

Commands that provide getArgumentCompletions but omit takesArgument are completed as /deploy without a separator, so typing an argument produces /deployprod and the command's argument completion cannot trigger. The fallback must treat getArgumentCompletions as indicating that the command takes an argument.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/tui/src/autocomplete.ts around line 401:

Commands that provide `getArgumentCompletions` but omit `takesArgument` are completed as `/deploy` without a separator, so typing an argument produces `/deployprod` and the command's argument completion cannot trigger. The fallback must treat `getArgumentCompletions` as indicating that the command takes an argument.

Evidence trail:
Commit 9391a70b8561e05374b4083d8548f2640d71e956: packages/tui/src/autocomplete.ts:231-239, 345-360, 396-415; packages/tui/src/slash-command-context.ts:14-35; packages/coding-agent/docs/extensions.md:1423-1439; packages/coding-agent/src/modes/interactive/interactive-mode.ts:1377-1387.

this.autocompletePrefix.startsWith("/"));
const shouldSubmitSlashCommand =
isSlashCommandCompletion && slashContext?.kind === "name" && slashContext.isAtPromptStart;
const isTypedExactSlashCommand = this.isSlashNameCompletionAtPromptStart();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium components/editor.ts:756

Accepting an already typed no-argument slash command such as /model with Tab leaves it in the editor instead of submitting it, so the user must press Enter again. The tui.input.tab branch applies the completion, cancels autocomplete, and unconditionally returns; apply the same exact-match check used for Enter and fall through to submission when the completion is a no-op.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/tui/src/components/editor.ts around line 756:

Accepting an already typed no-argument slash command such as `/model` with `Tab` leaves it in the editor instead of submitting it, so the user must press `Enter` again. The `tui.input.tab` branch applies the completion, cancels autocomplete, and unconditionally returns; apply the same exact-match check used for `Enter` and fall through to submission when the completion is a no-op.

Evidence trail:
Reviewed commit 9391a70. Inspect: packages/tui/src/components/editor.ts:732-750,753-780,857-870; packages/tui/src/autocomplete.ts:399-415; packages/tui/test/editor.test.ts:2242-2264,2356-2374. Commands: git_diff MERGE_BASE REVIEWED_COMMIT -- packages/tui/src/components/editor.ts; git_grep -F 'isSlashNameCompletionAtPromptStart' -- packages/tui/src/components/editor.ts.

}
} else {
this.cancelAutocomplete();
if (!isTypedExactSlashCommand || !completedExistingText) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium components/editor.ts:774

Pressing Enter on a partially typed no-argument slash command inserts the completion but does not submit it, so /mod becomes /model and requires a second Enter. The completedExistingText check rejects any completion that changes the line; submit should instead follow the existing slash-command-at-prompt-start and selected.takesArgument rules.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/tui/src/components/editor.ts around line 774:

Pressing Enter on a partially typed no-argument slash command inserts the completion but does not submit it, so `/mod` becomes `/model` and requires a second Enter. The `completedExistingText` check rejects any completion that changes the line; submit should instead follow the existing slash-command-at-prompt-start and `selected.takesArgument` rules.

Evidence trail:
Reviewed commit 6176c0c: `packages/tui/src/components/editor.ts:753-780`; `packages/tui/src/autocomplete.ts:394-415`; `packages/tui/test/editor.test.ts:2266-2288`. Compare behavior with `git diff MERGE_BASE REVIEWED_COMMIT -- packages/tui/src/components/editor.ts packages/tui/test/editor.test.ts`.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0735532. Configure here.

private renderWidgets(): void {
if (!this.widgetContainerAbove || !this.widgetContainerBelow) return;
this.renderWidgetContainer(this.widgetContainerAbove, this.extensionWidgetsAbove, true, true);
this.renderWidgetContainer(this.widgetContainerAbove, this.extensionWidgetsAbove, false, true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always-false widget spacer parameter

Low Severity

Both renderWidgetContainer call sites now pass false for spacerWhenEmpty, so that flag no longer varies. The parameter and the empty-container spacer branch are leftover ceremony after the extra blank line was removed.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: Review rules

Reviewed by Cursor Bugbot for commit 0735532. Configure here.

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.

1 participant