fix(acp): stream engine-triggered follow-up turns - #2769
Conversation
🦋 Changeset detectedLatest commit: c3660a1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3660a186a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const driver = this.driverFor(event.turnId); | ||
| if (driver === undefined) return; | ||
| const error = event.error as { readonly code: string; readonly message?: string } | undefined; | ||
| this.settleDriver(driver, () => { | ||
| // Auth failures must surface as a JSON-RPC `auth_required` error | ||
| // so the client triggers its re-auth flow, not a silent `end_turn`. | ||
| if (event.reason === 'failed' && isAuthError(error)) { | ||
| driver.reject(RequestError.authRequired(undefined, error?.message)); | ||
| return; | ||
| } | ||
| driver.resolve({ stopReason: turnEndReasonToStopReason(event.reason, error) }); | ||
| }); | ||
| if (driver !== undefined) { |
There was a problem hiding this comment.
Track driverless turns for cancellation
When a background completion starts a long engine-triggered follow-up after the originating session/prompt has settled, driverFor is undefined here and the turn is intentionally allowed to keep streaming, but its turn ID is never retained. Consequently, cancel() returns immediately whenever this.driver is undefined, so a subsequent ACP session/cancel cannot stop the visible model or tool execution. Track active engine turns via turn.started/turn.ended, or otherwise issue an unaddressed cancel when a driverless turn is active.
Useful? React with 👍 / 👎.
Related Issue
No related issue.
Problem
When Kimi starts a detached background task, the client-initiated
session/promptfinishes after Kimi reports that the task started. When the task later completes, the engine starts another turn for the main agent.The TUI displays that follow-up turn, but ACP clients receive nothing. The messages are persisted in the Kimi session but missing from the live ACP stream.
AcpSessiondiscarded assistant, thinking, tool, and turn-end events unless their turn ID matched an activeTurnDriver. Because engine-triggered follow-up turns have no client prompt driver, their events were silently dropped.What changed
turn.endedevent to settle an activesession/prompt.This separates prompt-request settlement from delivery of the session’s agent event stream.
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.