Skip to content

Improve agent user-input question UI: collapse dialog and clarify response label #150

Description

@germanescobar

Context

When an agent pauses to ask the user a structured question (currently implemented for Claude's AskUserQuestion tool via the user_input_requested event), the UI renders a single question at a time inside UserInputRequestedBlock in client/src/pages/SessionView.tsx (around line 1855). After the user answers, a separate user_input_response message is appended to the transcript.

Image

Problems with the current UI

  1. One question at a time + "1 / 3" pagination. Multi-question requests (e.g. Claude's AskUserQuestion with multiSelect: true or 2–4 questions in one batch) force the user to click Next/Back through each question. The questions are typically independent and short enough to answer in one view.
  2. Generic "user_input_response" message. When the user submits, a follow-up transcript entry with the raw label user_input_response is appended. It's redundant (the user's selections are already implied by what happens next) and the literal label is confusing — looks like a system token, not the user's answer.
  3. Provider portability is unclear. This was originally wired up for Claude. Codex and Ada may emit the same kind of structured-input events with different shapes (or not at all yet), and the current single-question-at-a-time rendering plus the user_input_response tail message are Claude-specific assumptions we shouldn't carry into other providers.

Proposed solution

  1. Collapse all questions into one scrollable dialog.

    • Render every question in UserInputRequestedBlock together, each with its header label, question text, and option list.
    • Drop the activeQuestionIndex state and the 1 / N counter. Keep the Back button only if it's still meaningful (it likely isn't once questions are not paginated — remove it).
    • The single Continue button submits when every question has a non-empty answer (the existing allAnswered check is already there, just use it as the only gate).
    • Plan-approval mode (claude_exit_plan_mode / header.toLowerCase().includes("plan")) should keep its own treatment — keep the textarea there but render it inline with its question rather than as a paginated step.
  2. Use a real, human label for the response.

    • Replace the user_input_response follow-up transcript entry with a label that reads as the user's choice. Default suggestion: Answered agent request (matches the existing submit button copy and the screenshot).
    • If the question has a clear short summary (e.g. the first option the user picked, or a generated "answered N questions"), use that instead of the generic label.
    • The label should be derived at submit time, not stored on the event, so we don't have to migrate existing transcript history.
  3. Stop appending the redundant trailing message.

    • Once fix: persist active session across reloads and allow all vite hosts #2 lands, the trailing user_input_response entry becomes noise. Remove it from the message list in the render path that handles user_input_response events (SessionView.tsx line ~1019–1028 already filters these out for the pending-request detection — extend that filter or collapse the message rendering for the response event itself).
    • If we keep any visible artifact of the answer, render it as part of the question block (e.g. a small "Your answer: Yes, rename to anita" footnote under each question once submitted), not as a separate transcript entry.
  4. Provider-portability audit.

    • While making the change, verify the rendering for Codex and Ada's equivalent question events. If they don't emit a structured-question event, this UI simply doesn't render for them today and that's fine — call it out in the PR.
    • If they do emit something similar but with a different shape, abstract the question list shape so UserInputRequestedBlock only depends on { id, header, question, options } (which is already the shape of UserInputQuestion in client/src/api.ts).

Acceptance criteria

  • UserInputRequestedBlock renders every question in a multi-question request in a single view, with no Next/Back pagination.
  • The "1 / N" counter is removed.
  • The single submit button is disabled until every question has an answer, and uses the existing allAnswered check.
  • On submit, the transcript no longer shows a separate user_input_response message; the answer is represented inline with each question (or simply omitted if the questions remain in the transcript with the user's choice marked).
  • Plan-approval (claude_exit_plan_mode) still works and keeps its own textarea, just no longer paginated.
  • Verified for Claude; documented whether Codex and Ada need additional work to surface their equivalent events.
  • Existing tests pass; add coverage for: multi-question rendering shows all questions, submit disabled until all answered, user_input_response is filtered out of the transcript.

Files of interest

  • client/src/pages/SessionView.tsxUserInputRequestedBlock (around line 1855), the pending-request selectors at line ~1019 and ~1347, and the message-render path that handles user_input_response.
  • client/src/api.tsUserInputQuestion type (line 133) and the submit/dismiss helpers around line 535 / 603.
  • Server side: server/lib/agents/ (or equivalent) — only relevant if Codex/Ada adapters need a parallel event shape.

Out of scope

  • Changing the question schema or how questions are sent back to the agent.
  • Redesigning the agent-side AskUserQuestion equivalents.
  • Mobile layout (a follow-up issue is fine if the desktop fix needs desktop-only treatment).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions