Skip to content

fix(coding-agent): answer ACP prompts only once the session admits the next turn - #800

Merged
snimu merged 4 commits into
mainfrom
fix/acp-prompt-waits-for-idle
Aug 20, 2026
Merged

fix(coding-agent): answer ACP prompts only once the session admits the next turn#800
snimu merged 4 commits into
mainfrom
fix/acp-prompt-waits-for-idle

Conversation

@parkerpettit

@parkerpettit parkerpettit commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Linear: ENG-5376

ACP could answer session/prompt after its first idle check even though injected work had restarted the session. An immediate follow-up was then rejected as Agent is already processing.

Without this change:

  1. The current ACP turn finishes.
  2. waitForHeadlessCompletion() observes an idle session.
  3. Injected work, such as a subagent message, starts another turn.
  4. ACP returns end_turn.
  5. The client sends its next prompt and Prime Agent rejects it because the session is busy.

Re-check connection.waitForIdle() before returning the ACP response. This closes the admission race seen in multi-turn Verifiers runs.

#881 fixes a different gap: waitForIdle() did not include a continuation already scheduled by compact.run. One makes the idle check complete; this PR puts a final check at the response boundary.

Verification:

  • ACP response waits for the final admission check
  • an immediate second prompt is accepted

Note

Queue ACP follow-up prompts behind in-flight work and cancel queued turns before delivery

  • ACP prompt handler no longer throws when a prompt is admitted before cancellation; it returns stopReason="cancelled" and passes streamingBehavior:"followUp", queueIfBusy:true to promptAndWait
  • AgentSession.promptAndWait accepts an optional AbortSignal via options.signal; on abort it cancels queued session-owned turn actions matching the agentMessageId before delivery and rejects the completion
  • New daemon server capability owned_prompt_cancellation (default-on) and cancelOwned flag on cancel_prompt_admission commands allow cancelling session-owned prompts that have not started; gated by protocol 7, schema revision 20
  • Daemon schema bumped from 19 to 20 in daemon-protocol.ts; DaemonAgentConnection sends cancelOwned:true when the server advertises the capability
  • Behavioral Change: cancel_prompt_admission with cancelOwned=true now aborts an owned admission's controller in daemon-mode.ts; clients below protocol 7 / schema 20 will not send the flag and owned cancellation is a no-op for them

Macroscope summarized 7ce5609.


Note

Medium Risk
Changes daemon worker lifecycle, persisted launch environment, and ACP turn-boundary semantics that verifiers and embedders depend on; behavior is heavily tested but mis-timed idle or env handling could still break reconnect or scoring.

Overview
ACP session/prompt now awaits connection.waitForIdle() before returning end_turn, so clients are not told the turn finished while injected work (e.g. subagent messages) has already restarted the session and would reject an immediate follow-up with “Agent is already processing.”

ACP session lifecycle and scoring metadata: session/new reserves the single-session slot before the first await, subscribes before getInitialSnapshot(), and fails setup cleanly if the snapshot read errors. After headless completion, a session_info_update carries namespaced quiescence (outstandingSubagents, remainingAutonomousContinuations) plus autonomous state from a live roster snapshot; snapshot failures at emission time propagate instead of reporting a false zero.

Daemon / ACP residency: Normal ACP sessions (with a session file) use resident workers so disconnect/reconnect can reattach; --no-session ACP stays client-owned. Resident creates always forward launchEnv from the caller (model endpoint, tokens, proxy, etc.). The supervisor persists launchEnv on resident worker descriptors for recovery after restart and strips it when promoting to client-owned, with integration tests for env across worker recovery and live IPython namespace across ACP reconnect.

Reviewed by Cursor Bugbot for commit ac97743. Bugbot is set up for automated code reviews on this repo. Configure here.

@parkerpettit
parkerpettit marked this pull request as ready for review August 7, 2026 20:22
@parkerpettit
parkerpettit force-pushed the fix/acp-prompt-waits-for-idle branch from 6a6ab06 to ac97743 Compare August 7, 2026 20:40
@parkerpettit
parkerpettit changed the base branch from main to feat/acp-quiescence-meta August 7, 2026 20:40
@parkerpettit
parkerpettit marked this pull request as draft August 7, 2026 20:40
Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
@parkerpettit
parkerpettit marked this pull request as ready for review August 7, 2026 20:42
@snimu

snimu commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Missing CHANGELOG entry: this fixes a user-visible ACP race (immediate follow-up prompt rejected with "Agent is already processing"). Please add a bullet under ## [Unreleased] in packages/coding-agent/CHANGELOG.md.

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts Outdated
@parkerpettit

Copy link
Copy Markdown
Contributor Author

Reworked per review: ACP prompts now queue behind in-flight work (streamingBehavior: "followUp", queueIfBusy: true) instead of waiting for whole-session idleness; the final waitForIdle() is removed, so the stop reason comes from the status captured after the turn the response gates and the response is never held open by detached work. Regression tests inject real work after the first idle observation; CHANGELOG entry added.

Comment thread packages/coding-agent/src/modes/acp/acp-mode.ts
Comment thread packages/coding-agent/src/modes/daemon/daemon-mode.ts
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
@parkerpettit
parkerpettit force-pushed the fix/acp-prompt-waits-for-idle branch 2 times, most recently from 3f68e8d to bf2c00e Compare August 10, 2026 22:38
@parkerpettit
parkerpettit force-pushed the fix/acp-prompt-waits-for-idle branch from bf2c00e to 5d7d4cf Compare August 19, 2026 20:36
@parkerpettit
parkerpettit changed the base branch from feat/acp-quiescence-meta to main August 19, 2026 20:42
@macroscopeapp

macroscopeapp Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Macroscope has since reviewed this pull request. An earlier review was skipped by a cost limit; a review has now completed, so that notice no longer applies.

snimu added 3 commits August 20, 2026 10:17
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
#	packages/coding-agent/src/modes/acp/acp-mode.ts
#	packages/coding-agent/src/modes/daemon/daemon-protocol.ts
#	packages/coding-agent/test/suite/acp-mode.test.ts
… merge

Renumber owned prompt cancellation to schema revision 20 (17-19 landed on
main), adapt compatibility gating to the requirements-array form, and return
stopReason "cancelled" for a prompt parked behind the terminal lifecycle when
a cancellation drops it before it starts.
@snimu
snimu merged commit 02e217e into main Aug 20, 2026
19 checks passed
@snimu
snimu deleted the fix/acp-prompt-waits-for-idle branch August 20, 2026 09:08
ruttybob added a commit to ruttybob/prime-agent that referenced this pull request Aug 20, 2026
Conflict resolution (3 files, all CHANGELOG):
- packages/{ai,coding-agent,tui}/CHANGELOG.md — keep fork [Unreleased]
  bullets (Z.AI reasoning_effort; mermaid/selection/statusline/cwd/ctrl+c/
  config-scope panes/agents-view fixes), take upstream's finalized
  [0.7.4] sections verbatim

Upstream payload: model search intent ranking (PrimeIntellect-ai#539), ACP resident
session lifecycle hardening (PrimeIntellect-ai#1494), ACP follow-up prompt queueing
(PrimeIntellect-ai#800), v0.7.4 release prep (version bumps, catalogs).

Fork features verified intact after merge: mermaid transform + settings
toggle, tui Markdown transform hook, config scope panes, cwd statusline,
grok-mermaid dependency, Z.AI supportsReasoningEffort catalog entries.
gogoyqj pushed a commit to gogoyqj/prime-agent that referenced this pull request Aug 21, 2026
…e next turn (PrimeIntellect-ai#800)

* fix(coding-agent): queue ACP prompts behind in-flight work

* fix(acp): keep queued-prompt semantics through the resident lifecycle merge

Renumber owned prompt cancellation to schema revision 20 (17-19 landed on
main), adapt compatibility gating to the requirements-array form, and return
stopReason "cancelled" for a prompt parked behind the terminal lifecycle when
a cancellation drops it before it starts.

---------

Co-authored-by: Sebastian <sebastian@primeintellect.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants