Files

7.5 KiB

/queue Slash Command & Auto-Queue Toggle — Technical Spec

Problem

Users need a way to queue a follow-up prompt while the agent is mid-response. This requires a new slash command, an auto-queue toggle in the status bar, validation logic, a workspace action to route the prompt, and updates to the pending user query block to support dismissal.

Relevant Code

  • app/src/search/slash_command_menu/static_commands/commands.rs (288-297)QUEUE static command definition
  • app/src/terminal/input/slash_commands/mod.rs (739-768)/queue execution handler
  • app/src/terminal/input.rssubmit_queued_prompt (re-submits queued prompts through slash/skill/plain-text routing) and maybe_queue_input_for_in_progress_conversation (auto-queue toggle bottleneck)
  • app/src/workspace/action.rs (453-456)QueuePromptForConversation workspace action variant
  • app/src/workspace/view.rs (19634-19658) — workspace-level handler that routes to TerminalView
  • app/src/terminal/view/pending_user_query.rs — pending query block insertion, removal, and auto-send logic
  • app/src/ai/blocklist/block/pending_user_query_block.rs — pending block view with dismiss button
  • app/src/ai/blocklist/block/status_bar.rs — auto-queue toggle button in the warping indicator
  • app/src/ai/blocklist/context_model.rsqueue_next_prompt_enabled state
  • app/src/terminal/view.rs:18101active_ai_block helper (skips pending query blocks)
  • app/src/terminal/view.rs:20044last_ai_block helper (skips pending query blocks)
  • app/src/terminal/view/init.rsTOGGLE_QUEUE_NEXT_PROMPT_KEYBINDING (Cmd+Shift+J)

Current State

The codebase already has a PendingUserQueryBlock and send_user_query_after_next_conversation_finished mechanism used by /compact-and and /fork-and-compact. These commands queue a prompt that fires after summarization completes. The /queue command reuses this infrastructure for a simpler case: queue a prompt during any in-progress conversation (no summarization involved).

Prior to this change, PendingUserQueryBlock had no dismiss functionality, and active_ai_block/last_ai_block did not account for pending query blocks at the tail of the rich content list.

Proposed Changes

1. Slash command registration

New QUEUE static command in commands.rs with:

  • Required argument (the prompt text).
  • Availability: AGENT_VIEW | ACTIVE_CONVERSATION | NO_LRC_CONTROL.
  • requires_ai_mode: true.
  • Gated behind FeatureFlag::QueueSlashCommand (dogfood). The command only appears in the slash command menu when the flag is enabled.

2. Command execution (slash_commands/mod.rs)

The handler validates two preconditions:

  1. Active conversation exists (else error toast).
  2. Prompt argument is non-empty (else error toast).

Then checks conversation status:

  • If is_in_progress() or is_blocked(): dispatches WorkspaceAction::QueuePromptForConversation { prompt }.
  • If idle (conversation finished): sends the prompt immediately via submit_queued_prompt, which routes through slash command / skill / plain-text detection.

3. Workspace action routing (action.rs, view.rs)

New QueuePromptForConversation { prompt } variant on WorkspaceAction. The workspace handler resolves the active terminal view and calls terminal.send_user_query_after_next_conversation_finished(prompt, interruptible: true, ctx). The interruptible parameter controls whether the pending block shows a "Send now" button; /queue and auto-queue set this to true, while summarization-triggered queuing (/compact-and, /fork-and-compact) sets it to false.

4. Dismiss and Send-now support on PendingUserQueryBlock

  • Block now owns a ViewHandle<ActionButton> close button (X icon, ButtonSize::XSmall, NakedTheme) and an optional ViewHandle<ActionButton> send-now button (Play icon), created only when the block is constructed with interruptible: true.
  • New PendingUserQueryBlockAction::{Dismiss, SendNow} and PendingUserQueryBlockEvent::{Dismissed, SendNow}.
  • PendingUserQueryBlock implements TypedActionView to translate actions → events.
  • The button column ("Remove queued prompt" + optional "Send now") is positioned top-right via Stack + OffsetPositioning.
  • The caller in pending_user_query.rs subscribes to Dismissed (→ remove_pending_user_query_block) and SendNow (→ send_queued_prompt_now, which removes the block and immediately submits the queued prompt through the input) events.

5. Skip pending blocks in active_ai_block / last_ai_block

Both methods use Iterator::rfind to skip all trailing non-AI items (usage footers and pending query blocks) rather than checking only the last entry.

6. Auto-queue toggle (context_model.rs, status_bar.rs, input.rs)

  • queue_next_prompt_enabled: bool on BlocklistAIContextModel tracks the toggle state.
  • toggle_queue_next_prompt() flips the flag and emits QueueNextPromptToggled.
  • The status bar renders a ClockPlus icon button gated behind FeatureFlag::QueueSlashCommand. The icon is accent-colored when active.
  • Keybinding Cmd+Shift+J maps to TerminalAction::ToggleQueueNextPrompt.
  • maybe_queue_input_for_in_progress_conversation in input.rs is the bottleneck: when the toggle is on and the active conversation is in progress, it captures the input buffer, clears it, and dispatches QueuePromptForConversation.
  • The toggle persists across exchanges (same semantics as fast-forward).

End-to-End Flow

sequenceDiagram
    participant User
    participant Input as TerminalInput
    participant WS as WorkspaceView
    participant TV as TerminalView
    participant PUQ as PendingUserQueryBlock

    User->>Input: /queue fix the tests
    Input->>Input: Validate conversation, prompt, status
    Input->>WS: dispatch QueuePromptForConversation
    WS->>TV: send_user_query_after_next_conversation_finished
    TV->>PUQ: insert_pending_user_query_block
    Note over PUQ: Shows queued prompt with dismiss button

    alt Agent completes successfully
        TV->>TV: on_next_conversation_finished(Complete)
        TV->>Input: submit_queued_prompt("fix the tests")
        Note over Input: Routes through slash/skill/plain-text detection
        TV->>PUQ: remove block
    else Agent errors/cancelled
        TV->>TV: on_next_conversation_finished(Error|Cancelled)
        TV->>TV: restore prompt to input buffer
        TV->>PUQ: remove block
    else User dismisses
        User->>PUQ: click X
        PUQ->>TV: PendingUserQueryBlockEvent::Dismissed
        TV->>TV: remove_pending_user_query_block (cancels callback)
    end

Risks and Mitigations

  • Only one queued prompt at a time: calling /queue again while one is pending replaces the previous one (via remove_pending_user_query_block in insert_pending_user_query_block). This is acceptable for v1.
  • Pending indicator behind feature flag: the PendingUserQueryIndicator flag gates the visual block (dogfood). Without the flag, the prompt is still queued and auto-sent — just without visual feedback. This is the same behavior as /compact-and.
  • Queue command behind feature flag: the QueueSlashCommand flag gates the /queue command registration (dogfood). The command handler, workspace action, and pending block infrastructure are always compiled in but only reachable when the flag is enabled.

Testing and Validation

  • Manual testing of the five error/success paths described in the product spec.
  • Code review of the active_ai_block / last_ai_block skip logic to ensure pending blocks don't break conversation state detection.