Skip to content

Add interactive ask_user tool across TUI and Dashboard - #406

Draft
maxscheurer wants to merge 2 commits into
aebrer:masterfrom
maxscheurer:feature/issue-396-interactive-ask-user-tool
Draft

Add interactive ask_user tool across TUI and Dashboard#406
maxscheurer wants to merge 2 commits into
aebrer:masterfrom
maxscheurer:feature/issue-396-interactive-ask-user-tool

Conversation

@maxscheurer

Copy link
Copy Markdown
Contributor

Addresses #396

Plan a first-class ask_user experience with TUI and Dashboard parity. The draft deliberately starts with a UX prototype/sign-off stage before wiring the tool into the runtime.

The latest issue discussion recommends strict one-question-at-a-time behavior for the first release; the plan comment calls out the resulting scope decision for maintainer confirmation.

Implementation plan posted as a comment below.

@maxscheurer

Copy link
Copy Markdown
Contributor Author

Implementation Plan

Problem analysis

dreb already has blocking user-input primitives and RPC/Dashboard transport, but built-in tools are wrapped without an extension context, so a native tool cannot currently reach ctx.ui. The existing selector/input composition can cover a basic question, but it cannot present choices and free text together or express multiSelect and multiline with true TUI/Dashboard parity. A unified ask request is therefore the cleanest path if those schema fields remain in scope.

The current TUI can host only one extension dialog at a time; concurrent requests overwrite the visible component and can orphan a promise. Following the latest maintainer discussion and re-assessment, this plan recommends strict FIFO, one-question-at-a-time behavior for the first release. The tabbed concurrent view and askUserMode setting are excluded unless maintainers explicitly restore them before implementation.

The Dashboard already marks any pending blocking extension-UI request as needing attention and already turns that state into fleet styling, a title badge, and a service-worker notification. Routing the new request through that pipeline should satisfy the notification requirement without parallel notification infrastructure.

Deliverables

Stage 1 — UX prototype and sign-off

  1. Build a development-only live browser harness showing the proposed interaction in both Dashboard styling and a terminal-faithful TUI frame.
  2. Cover the important states: single choice, multiple choice, free-text entry, multiline entry, selected/disabled controls, timeout/abort, and explicit skip/cancel.
  3. Define one shared interaction contract: options remain visible while custom text is entered, free text is available by default, multi-select answers can be combined with custom text, and every state has an obvious skip route.
  4. Keep the draft PR at this stage until maintainers approve the TUI and Dashboard behavior. Record screenshots and the approved decisions on the PR before wiring.

Stage 2 — Runtime and surface wiring

  1. Add a built-in ask_user definition with the agreed schema, typed details/result data, concise tool rendering, a prompt snippet, and guidelines that restrict use to genuine ambiguity rather than routine confirmation.
  2. Register it consistently in allTools, allToolDefinitions, createAllToolDefinitions, createAllTools, and ToolName, so --tools and runtime selection behave like other built-ins.
  3. Give base definitions a per-execution extension context by passing an ExtensionRunner.createContext() factory at the AgentSession wrap site. Preserve extension overrides and ensure absent/no-op UI returns a clear non-blocking result.
  4. Add a typed ask operation to ExtensionUIContext, its no-op implementation, TUI binding, and RPC request/response protocol. Reuse one cross-surface request/result shape rather than reconstructing answers independently in each host.
  5. Implement a dedicated TUI question component matching the approved prototype: radio/checkbox selection, inline free text, multiline mode, keyboard navigation, visible timeout, and Esc/skip behavior. Ensure abort disposes the component and restores the editor/focus exactly once.
  6. Implement the matching Dashboard dialog and response handling with accessible radio/checkbox controls, text input/textarea, submit and skip actions, Escape dismissal, and timeout state. Continue using the existing uiRequests and attention pipeline so pending questions trigger the existing notification behavior.
  7. Serialize ask_user calls with a FIFO queue scoped to each tool-definition/session instance. A queued call whose signal aborts must resolve as skipped without opening UI; completion, cancel, timeout, and failure must always release the next item.
  8. Document the tool, protocol, availability in headless modes, result semantics, and the deliberate sequential behavior.

Acceptance criteria

  • ask_user is available as a selectable built-in and appears in the generated system prompt with narrow usage guidance.
  • The approved TUI and Dashboard designs provide equivalent single-select, multi-select, optional free-text, and multiline behavior.
  • Choosing options, entering custom text, or combining both produces an unambiguous structured result plus model-readable text.
  • Skip, Escape, tool abort, timeout, host teardown, and unavailable UI all resolve gracefully; none can leave the agent awaiting an unreachable promise.
  • Concurrent calls are displayed strictly in FIFO order, never overwrite one another, and resolve independently.
  • RPC transports the unified request and response without losing selection, custom text, cancellation, or timeout semantics.
  • A Dashboard question sets needsAttention, displays the existing waiting-for-input reason, and triggers the existing hidden-page notification path when permission is granted.
  • Root and package documentation list the correct built-in tool count and explain ask_user behavior.
  • Focused tests, the full test suite, build, formatting checks, and workspace-link verification pass.

Files to create or modify

Core tool and session wiring

  • packages/coding-agent/src/core/tools/ask-user.ts — new schema, queue, execution/result mapping, prompt metadata, and TUI transcript rendering.
  • packages/coding-agent/src/core/tools/index.ts — exports, registries, factories, ToolName, and default tool construction.
  • packages/coding-agent/src/core/agent-session.ts — pass the base-tool context factory when definitions are wrapped.
  • packages/coding-agent/src/core/extensions/types.ts — shared typed ask request/result and ExtensionUIContext.ask contract.
  • packages/coding-agent/src/core/extensions/runner.ts — safe no-op implementation for print/headless contexts.

TUI

  • packages/coding-agent/src/modes/interactive/components/ask-user.ts — new approved question component.
  • packages/coding-agent/src/modes/interactive/interactive-mode.ts — bind the new UI operation and manage focus, abort, timeout, and cleanup.
  • packages/coding-agent/test/ask-user-component.test.ts — keyboard/state/render tests for the component.

RPC and Dashboard

  • packages/coding-agent/src/modes/rpc/rpc-types.ts — typed ask request and response variants.
  • packages/coding-agent/src/modes/rpc/rpc-mode.ts — request creation, response parsing, timeout, abort, and cleanup.
  • packages/dashboard/src/client/screens/session.tsx — render and submit the unified ask dialog.
  • packages/dashboard/src/client/state/reducer.ts — only if normalization is needed for the new request shape; retain generic attention derivation.
  • packages/dashboard/test/client/ask-user.browser-harness.tsx — live Stage-1 comparison/prototype for Dashboard and terminal-faithful TUI states.
  • packages/dashboard/test/client/screens.test.tsx — interaction and accessibility coverage for choices, free text, multiline, skip, and Escape.
  • packages/dashboard/test/reducer.test.ts — request queue and attention lifecycle coverage for the new method.
  • packages/dashboard/test/client/pwa.test.tsx — verify an ask request uses the existing waiting-for-input notification reason.

Tests and documentation

  • packages/coding-agent/test/tools/ask-user.test.ts — schema validation, prompt metadata, answer formatting, headless fallback, cancellation/timeout, and FIFO/abort behavior.
  • packages/coding-agent/test/tools.test.ts — registry/factory inclusion and tool shape.
  • packages/coding-agent/test/agent-session-dynamic-tools.test.ts or a focused new session-context test — prove base tools receive live ctx.ui while extension overrides still work.
  • packages/coding-agent/test/rpc.test.ts — ask request/response, cancellation, timeout, and abort round trips.
  • README.md — public capability summary and corrected built-in count/list.
  • packages/coding-agent/README.md — default tool list, CLI selection behavior, and usage summary.
  • packages/coding-agent/docs/extensions.md — document the new public UI-context operation.
  • packages/coding-agent/docs/rpc.md — document the new request and response variants.

Testing approach

  • Tool unit tests: validate 2–4 option bounds, defaults, invalid combinations, selected/custom/combined answers, skip text, no-UI behavior, prompt guidance, and renderer details.
  • Queue/error tests: start multiple executions, prove only one reaches the UI, then cover answer, cancel, timeout, pre-open abort, active abort, thrown host errors, and release of later calls.
  • TUI component tests: exercise arrows, Space/Enter, text-edit transitions, multiline submission, Esc/skip, countdown, disposal, and focus restoration at narrow and normal widths.
  • RPC tests: assert exact emitted JSON and parsed results for all answer modes, malformed/mismatched responses, cancel, timeout, and signal abort.
  • Dashboard tests: mount a session with an ask request, interact with every control, verify accessible checked state and payloads, and prove dismissal clears attention. Add an explicit PWA assertion for the question title in the notification body.
  • Integration: run focused Vitest files during development, then npm run build, npm test, Biome on every changed file, and npm run verify-workspace-links. After building, manually invoke the real binary in TUI and Dashboard/RPC modes and verify answer, skip, timeout, notification, and sequential-call flows.

Risks and open questions

  1. Scope confirmation required: the issue body still specifies tabbed concurrent questions and askUserMode, while the latest discussion recommends dropping both. This plan follows the latest recommendation; maintainers should confirm before Stage 2 starts.
  2. Unified widget versus composed primitives: this plan recommends a unified RPC/UI operation because it is the only direct way to retain multiSelect, multiline, and simultaneous custom text with parity. If the accepted MVP is selector-then-input composition, those richer fields should be removed from this PR rather than partially supported.
  3. Prototype form: the Stage-1 TUI design is proposed as a live terminal-faithful HTML frame alongside the Dashboard mockup. Confirm whether maintainers instead want a runnable TUI harness.
  4. Timeout policy: confirm whether the model may set a bounded timeout, the host applies a default, or both. Regardless, timeout must map to the same graceful skipped result as explicit cancel.
  5. Public API surface: adding ExtensionUIContext.ask is cleaner for cross-surface parity but expands the extension API. If it should remain built-in-only, the equivalent host contract needs an internal interface rather than being exposed to extensions.

Plan created by mach6

@maxscheurer

Copy link
Copy Markdown
Contributor Author

Progress Update — Stage 1 (UX prototype)

Landed the development-only UX prototype for ask_user, holding at the Stage-1 sign-off checkpoint before any runtime wiring.

What's included

  • Live comparison harness (packages/dashboard/test/client/ask-user.browser-harness.tsx) rendering the Dashboard and a terminal-faithful TUI frame side by side, driven by a Solid/Vite entry with an accompanying HTML shell.
  • State coverage: single choice, multiple choice, free-text, multiline, selected/disabled controls, timeout, and explicit skip/abort — each with an obvious skip route.
  • Shared interaction contract: options stay visible while custom text is entered, free text is available by default, multi-select answers combine with custom text, and Skip/Escape/timeout/abort all resolve to a safe "continue" outcome.
  • Runnable locally: npm run prototype:ask-user --workspace @dreb/dashboard, then open /ask-user.browser-harness.html.
  • Browser tests (ask-user.browser.test.ts, Playwright) assert the single/multi-select, free-text, multiline, skip, timeout, abort, and Escape-to-skip behavior on both surfaces.

Maintainer feedback addressed

  • Selection controls: the Dashboard now uses visible native radio/checkbox inputs with a themed accent color instead of the ASCII glyphs. Terminal glyphs ((●), [x]) are retained for the TUI panel only. There is no dedicated radio component in the Dashboard framework — it uses native controls styled via shared CSS (e.g. .checkbox-control) — so native inputs are the idiomatic choice.
  • Answer/field overlap: the result readout now renders as a full-width block below the input, eliminating the overlap.

Scope note

This follows the latest re-assessment: strict one-question-at-a-time for the first release. The tabbed concurrent view and askUserMode setting remain out of scope unless restored before Stage 2.

Screenshots of the updated single-choice and answered states are attached below (drag-drop from local run; not committed as repo binaries).

Verification

  • Focused browser tests: 4/4 pass
  • Full Dashboard suite: 836/836 pass
  • Full npm run build, Biome, git diff --check, workspace-link verification: all pass

Commit: 3425a06


Progress tracked by mach6

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