fix(desktop): answer agent input requests from the composer

Merged
SU
10d ago
+166-8

Links

Summary

  • A composer reply sent while the agent waits on an input request now answers that request, instead of canceling it and queuing the reply.
  • If the reply can't fill the request, the request is still canceled, but the reply is now steered into the running turn instead of sitting in the queue.

Why / Context

SessionView.onSend canceled every pending approval before it sent a prompt. For an input request (a form approval, e.g. an ACP question with options), that cancel failed the tool call. The reply then queued behind the still-running turn, so the user had to click Steer to continue.

How It Works

  • New pure util SessionView/utils/composerAnswer(approval, content) maps the composer text to a form decision when exactly one single-question form is pending:
    • text matches an option label or value (case-insensitive) → pick that option (single, multi, and yes/no for boolean)
    • otherwise, if the question has an "Other" (<id>_custom) field → the text goes there (ACP sends it as the "Other" answer)
    • text field → the text; number/integer → the text if it's a valid number
    • anything else (multi-question forms, unmatched choice without "Other", permission prompts, empty text) → null
  • onSend: if there's an answer, respond with it and send no prompt. If not, cancel the pending approvals as before and send the reply as a steer (expectedTurnId) when any approval was pending.
  • questionPages moved from QuestionForm/utils to ChatSession/utils because SessionView now uses it too (no logic change).

Manual QA Checklist

Run end to end in the desktop dev app over CDP (Claude chat pane, acp-chat flag on, real AskUserQuestion request), with real clicks and typing in the composer:

  • Before (main's SessionView): replying Blue in the composer → "Asking for your input failed", question Skipped, Blue stuck in the queue with Steer (reproduces the report)
  • After: same steps → question answered "Color ✓ Blue", nothing queued, agent continued and replied BLUE
  • After, free text (Purple, actually) → answered through "Other", agent continued and replied PURPLE
  • Multi-question form → reply cancels it and steers into the turn (unit-tested only)
  • Permission prompt + composer reply → canceled and steered (not run)

Testing

  • bun test on composerAnswer and questionPages (7 pass)
  • bun run typecheck (apps/desktop): clean
  • biome check: clean

Design Decisions

  • Only one pending request with one question gets auto-answered. A single composer text can't be reliably split across several fields, so those cases fall back to cancel + steer.
  • Steer on the fallback path, permission prompts included. A reply to an agent that is waiting on you is a redirect. Queuing it behind the turn was the stall reported in the issue.

Summary by cubic

Fixes SUPER-2858: a composer reply sent while the agent waits on an input request now answers that request instead of canceling it and queuing the reply, which previously required the user to click Steer.

  • A reply that matches a single-question form answers it: an option label/value picks that option (including yes/no for booleans), otherwise the text fills the "Other", text, or number field.
  • A reply that can't fill the request (multi-question forms, permission prompts, unmatched choices, empty text) still cancels the approval but is now steered into the running turn instead of queued.
  • If answering the request fails, the reply is restored in the composer and a toast error is shown.
  • questionPages moved from QuestionForm to the shared ChatSession/utils since SessionView now uses it.