MoonshotAI / MoonshotAI/kimi-cli

ACP: AskUserQuestion/QuestionRequest resolves empty — structured questions unusable over ACP

Open Beginner friendly
#2,495 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
11.4k
Forks
1.3k
Avg merge
9h 47m
Merged PRs (30d)
2

Description

Summary

In ACP server mode (kimi acp), AskUserQuestion cannot work: the ACP session resolves every QuestionRequest with an empty answer dict, so the model always receives {"answers": {}, "note": "User dismissed the question without answering."} — even when the user is present and willing to answer. ACP clients (Paseo, Zed, JetBrains AI Chat, …) therefore can never render the question's options or return a selection.

Observed downstream effect (kimi-code 0.23.6 driven by Paseo over ACP): the tool call surfaces as a generic permission card containing the raw {"questions": [...]} JSON with only Reject/Accept buttons — the user has no way to pick an option, and if the card is ignored the agent turn hangs indefinitely.

Current behavior

src/kimi_cli/acp/session.py (~line 211):

case QuestionRequest():
    logger.warning("QuestionRequest is unsupported in ACP session; resolving empty answer.")
    msg.resolve({})

The empty resolve is indistinguishable from a genuine user dismissal, so the model gets no signal that the client was the problem and may retry the tool.

Why this matters

  • AskUserQuestion is the documented way for the agent to collect decisions mid-task; over ACP it is silently broken.
  • The Wire protocol already solves this (QuestionRequest + supports_question capability negotiation in initialize); ACP has no equivalent path at all.
  • The ask_user tool already contains a graceful fallback for unsupported clients (except QuestionNotSupported → ToolError: "Do NOT call this tool again. Ask the user directly in your text response instead."), but the ACP layer never raises it.

Proposals

Short-term (one line, helps every ACP client immediately):

case QuestionRequest():
    msg.set_exception(QuestionNotSupported())

This routes into the existing ToolError fallback, so the model asks its question in plain text — far better than a phantom dismissal or a hang.

Full support (either or both):

  1. Map QuestionRequest to session/request_permission, encoding each question option as a permission option (option id = label, kind allow_once), and translate the selected option id back into answers. Covers the common single-question case; multi-question could be sequential requests. Multi-select has no clean mapping.
  2. Add an ACP extension method (e.g. _kimi/questionRequest) carrying the full QuestionItem[] payload with a structured response, so capable clients can render multi-question / multi-select panels; clients advertise support via an extension capability.

References

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/kimi_cli/acp/session.py around the QuestionRequest case, then read the QuestionNotSupported fallback in src/kimi_cli/tools/ask_user/init.py and its definition in src/kimi_cli/wire/types.py. Determine which supported behavior the issue should use: the short-term fallback or a full ACP question mapping. Done means ACP no longer resolves an unanswered question as an empty answer and the model receives the intended fallback or structured response.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.