Skip to content

[Feature] support agent-initiated questions (ACP elicitation) #792

Description

@OSadovy

Checklist

  • I agree to communicate with the author myself (not AI-generated).
  • I've read the README's Filing issues section.
  • I'm running the latest versions (fill in below).
    • agent-shell version: 0.74.2
    • acp.el version: 20260803.2034
    • ACP package (e.g. claude-agent-acp) version: 0.70.0
    • Agent CLI (e.g. claude, gemini) version: 2.1.234
  • For requesting new agent support, I'm including a link to the ACP-capable agent or related ACP package.
  • For issues, I'm including ACP traffic (as per README).

The problem

Agents can ask the user a structured question mid-turn - "which library
should we use?", "which of these approaches?" - and wait for an answer
before continuing. ACP calls this elicitation.

agent-shell doesn't support it. Elicitation is opt-in - a client has to
advertise it before an agent will use it - so this isn't a visible failure
today. It just never happens.

What agents do in its absence varies. Some disable their question tool
outright, so the model can no longer ask at all. Others degrade it to a
yes/no permission prompt. Questions originating from MCP servers are
auto-declined.

That's a behaviour difference - a decision that would have been put to the
user might get settled by the model some other way instead (more guessing?).
And a fair number of published skills and MCP servers are written assuming
the client can ask a question and wait for the answer.

How this might look in agent-shell

The question appears in the transcript as a normal entry, in place, not as a
popup or a minibuffer prompt. Nothing is modal - the buffer stays usable. A
single request can carry several questions, so one entry may hold more than
one.

Options are listed and numbered, each with a marker showing selection state:

    Which serialization library?

    1. ( ) serde
           Mature, derive macros, largest ecosystem
    2. (*) miniserde
           Smaller, fewer features, faster compiles
    3. ( ) Hand-rolled
           No dependency, more code to maintain

    Other: ________________________________

     Submit   Decline

Round markers for single-choice, square for multiple-choice, so the two are
distinguishable at a glance without reading a label. Selecting an option in a
single-choice question clears the others; in a multiple-choice question it
toggles.

Selecting works three ways: press the option's number, press RET with point
on it, or click it. Options sit on their own lines, so ordinary line movement
already gets between them; TAB and S-TAB jump between questions where
there's more than one. Point lands in the question when it arrives, the same
way it does for permission prompts today.

The "Other" field is editable text inline in the buffer; everything around it
stays read-only. Typing there is how the user answers in their own words.

Submit sends the answer. Decline tells the agent the user skipped - the
turn continues rather than aborting.

Questions coming from MCP servers are more general - small forms of text,
number and yes/no fields alongside choices - but the same entry, selection
and submit model covers them.

After answering

The question stays in the transcript. It stops accepting input and re-renders
to show what happened:

  • answered - the chosen option(s), or the typed answer
  • declined - marked declined
  • cancelled - marked (cancelled), with any typed text preserved

Cancelled happens when the agent abandons the question mid-flight, usually
because the turn was interrupted.

Option previews

When an option carries a preview (Claude is the one in my experience sending those), it should be reachable but not in the way -
present under the option and collapsed by default, expanded on demand, the
way tool call details already fold. Several previews can arrive at once, so
showing them all expanded would bury the question.

Optionally also surfaced through eldoc for the option at point, for people
who prefer that.

Visual appeal

The markers might be worth some polish. Drawn as SVG in a graphical frame - a
real radio button and a real checkbox - falling back to ( ) (*) [ ]
[x] in a terminal.

One request: keep the text characters underneath the graphics rather than
replacing them. The buffer text stays ( ) and (*) while only redisplay
shows the SVG. That keeps the content copyable and searchable, and the
graphical version then costs nothing in accessibility.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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