Skip to content

fix: complete prompts on newly forked sessions - #466

Open
aiguy110 wants to merge 1 commit into
agentclientprotocol:mainfrom
aiguy110:fix/fork-prompt-lifecycle
Open

fix: complete prompts on newly forked sessions#466
aiguy110 wants to merge 1 commit into
agentclientprotocol:mainfrom
aiguy110:fix/fork-prompt-lifecycle

Conversation

@aiguy110

@aiguy110 aiguy110 commented Sep 3, 2026

Copy link
Copy Markdown

Summary

  • reactivate the Codex app-server subscription before the first direct prompt on a newly forked ACP session
  • preserve the intentional post-fork thread/unsubscribe, so another ACP process can still load the persisted fork
  • add a bounded event-driven regression test that requires both streamed fork output and a resolved prompt response

ACP lifecycle

The ACP session/fork RFD motivates the method with a client flow that forks, issues additional messages, and closes the fork. It also specifies a response shaped like session/new. The draft schema describes the returned ID as the newly created forked session and does not require an intervening session/load or session/resume.

Therefore a successful session/fork response must produce a session that accepts session/prompt directly. Explicit session/load remains valid for a persisted/inactive fork, but it is not a required activation step after a successful fork on the same ACP connection.

Observed behavior

With codex-acp 1.8.0 and Codex 0.152.1:

  1. session/fork(parentSessionId, cwd, mcpServers) returned a fork session ID.
  2. session/prompt(forkSessionId, prompt) was accepted.
  3. Codex completed and persisted the answer internally.
  4. The ACP client received no answer session/update notifications.
  5. The session/prompt request remained pending indefinitely.

A real-Codex reproduction using the repository /run-codex harness timed out the direct sequence after 30 seconds with zero updates. The control sequence fork -> load -> prompt completed in 2.7 seconds.

Root cause

The fork implementation intentionally calls app-server thread/unsubscribe after thread/fork to release the writer for clients such as AIR that may load the fork through another ACP process. codex-acp nevertheless installs the returned fork in its local ACP session map as if it were immediately promptable.

Before this change, a direct prompt started a turn on that unsubscribed thread. Codex executed it, but app-server delivered no thread notifications to this connection. CodexAppServerClient.runTurn consequently never observed turn/completed, so codex-acp emitted no answer updates and never resolved the ACP prompt.

This PR keeps the unsubscribe behavior. The ACP session state records that a new fork needs resubscription, and the first direct prompt resumes the thread before registering prompt handlers and starting the turn. An explicit session/load creates an already-subscribed session state and does not take the lazy-resume path.

Regression test

The new test:

  • creates a fork and immediately prompts its returned session ID;
  • simulates app-server message and completion notifications;
  • requires the ACP agent_message_chunk for the fork;
  • requires the prompt response to resolve with end_turn;
  • uses a one-second timeout so the original indefinite wait fails deterministically.

Verification

  • npm run typecheck
  • npm test — 487 passed, 26 skipped
  • real Codex: fork -> prompt — completed in 3.3 seconds after the fix
  • real Codex: fork -> load -> prompt — completed in 3.8 seconds after the fix

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.

1 participant