Repository navigation
fix(server): Stop ends a Claude thread's background work after the turn settles - #13792
juliusmarminge merged 3 commits into
Conversation
…rn settles Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — The change narrowly fixes Stop handling for settled Claude turns with background work, reusing existing query and roster cleanup paths while preserving active-turn interruption behavior. Targeted tests cover both normal cleanup and a concurrent replacement-process scenario. You can add or adjust custom eligibility rules. Learn more. |
…fix/v2-claude-stop-settled-background
…te alone Stop after the turn settled waits up to 10s for the old CLI to exit. A turn started during that wait can open a replacement query for the same native thread, and the cleanup then cleared that new process's Waiting roster and wake state and marked the thread idle. Only clear it while the stopped query is still the live one (or none is). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On V2, a Claude thread whose turn has finished but still shows Waiting on background task cannot be stopped from that strip. Clicking Stop does nothing: the background shell keeps running and the strip stays up. The server log shows the
provider-turn.interrupteffect failing and retrying:I reproduced it live. I started
node -e "setTimeout(…, 120000)"withrun_in_background, let the turn settle, and clicked Stop. The provider thread'spendingBackgroundTasksstill listed the task 30s later.Cause
39c08e1 ("stop retained background work after a turn settles") let a settled run's Stop through.
ProviderTurnControlService.interruptnow callsinterruptTurnwithrequestRuntimeRestart: truewhen the session still reports background work. Codex handles that case by interrupting its settled turn contexts. Claude'sinterruptTurnstill required the provider turn to be the active one and returned a protocol error otherwise.Fix
When no Claude turn is active,
requestRuntimeRestartis set, and the live query belongs to the thread's native session,interruptTurndoes three things:provider_thread.updatedwith an empty roster.The next message resumes the session in a new process. Stopping an active turn is unchanged.
Verification
ClaudeAdapterV2 background wake turns › stops background work after the turn settled. It uses the wake harness with the recordedlocal_bashtask_startedshape: start a background task, settle the turn, then callinterruptTurn({ requestRuntimeRestart: true })for the settled turn. The test asserts that the query closes, the roster empties,hasPendingBackgroundWorkis false, and no continuation is offered.Claude provider turn … is not the active turn., the same error the live server logged.vp test run src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts: 119/119 pass.OrchestratorReplayFixtures,ClaudeReplayFixtures, andProviderTurnControlServicetests filtered to claude/interrupt/stop: 37 pass.vp exec tsc --noEmit -p .in apps/server: noerror TSorwarning TS.vp linton the touched files: no new findings. The existingno-unused-varswarning onlayeris on the base.knip --workspace apps/server --exports: clean.run_in_backgroundnode timer, let the turn settle, and clicked Stop on the Waiting strip. The node process exited, the provider thread went toidlewithpendingBackgroundTasks: [], the strip and the sidebar Waiting pill cleared, and nois not the active turnerrors were logged. The next message ran normally (AFTER_STOP_OK) on a resumed session.Model: Claude Opus 5.5 (Claude Code)
🤖 Generated with Claude Code