Skip to content

Cursor plan-mode approval relayed to agent as "User cancelled" #79

Description

@heavygee

Summary

In a Cursor-flavor session over HAPI, approving a plan-mode CreatePlan request from the web UI relays User cancelled back to the agent instead of an approval. The plan → execute handoff never fires, so plan mode is effectively unusable for Cursor sessions.

Reproduction (3/3)

  1. Start a Cursor session, switch to plan mode.
  2. Agent calls the CreatePlan tool. HAPI renders an approval prompt: "Waiting for approval..." with Yes / Yes For Session / Abort (tool card Create Plan / CursorCreatePlan).
  3. Click Yes. The tool card shows a green success checkmark (hub records the request as approved).
  4. The agent's CreatePlan tool call returns Error: User cancelled.

Root cause

Cursor's ACP blocking extension methods require the JSON-RPC result to nest the outcome under an outcome key (see https://cursor.com/docs/cli/acp):

interface CursorCreatePlanResponse {
  outcome:
    | { outcome: "accepted"; planUri?: string }
    | { outcome: "rejected"; reason?: string }
    | { outcome: "cancelled" };
}

cli/src/cursor/utils/cursorExtensionAdapter.ts responded with the outcome flat, e.g. { outcome: "accepted" }. Cursor then reads response.outcome.outcome, sees undefined, and falls back to a cancellation — so an approved plan is relayed to the agent as User cancelled.

The same flat shape was used for cursor/ask_question responses, which is the identical latent bug for that method.

Note: the standard ACP session/request_permission responses already use the nested { outcome: { outcome: ... } } shape in AcpSdkBackend, so the cursor extension responses were the outlier.

Fix

Wrap all cursor/ask_question and cursor/create_plan responses in the nested { outcome: { ... } } envelope. Regression tests assert the exact nested wire shape for the affirmative approval → CreatePlan path (plus approved_for_session, reject, and abort).

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