Repository navigation
fix(server): messages cut by a restart no longer stay marked as streaming - #28646
Abhishek-B-R wants to merge 1 commit into
Conversation
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Recovery now clears the streaming flag on interrupted turn items already being cancelled, preventing partial replies from continuing to appear live. Existing cancellation rules and message contents are unchanged, keeping the impact narrowly bounded. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Clear streaming state on cancelled items apps/server/src/orchestration-v2/ProviderRuntimeRecoveryService.ts, apps/server/src/orchestration-v2/ProviderRuntimeRecoveryService.test.ts |
Cancellation clears streaming when the item has that property. The test verifies this for assistant_message, reasoning, and proposed_plan items. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Suggested reviewers: juliusmarminge
Merge Risk: 
Minimal · up to 812cc
-
The recovery change correctly clears streaming state for cancelled items and is ready to merge.
Pre-merge checks: 
4
Finishing Touches
-
Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
|
Note Written by Verified in a real dev environmentverified as-is at used repo Playwright 1.60.0 with
read-only runtime transcript ( before, main with the partial reply still marked streaming: after, pr startup recovery of the identical partial reply: real streaming reply, server shutdown, reconnect, and idle state: neighboring stop interaction: Not verifiednative ios/android and electron shells, macos/windows, remote relay/tunnel connections, and other providers were not exercised on this linux vm. real interruption of streaming reasoning and proposed-plan items was not exercised; those types are covered by the passing focused recovery test. startup was checked with a copy of actual in-flight state, rather than a machine crash. automatic restart continuation was disabled for the matching comparison; its existing tests passed. |




Problem
When a server restart or shutdown cuts a run, recovery cancels its open turn items but leaves
streaming: trueonassistant_message,reasoningandproposed_planitems. The item ends upcancelledand still streaming, and nothing clears it later because the run is over. Clients build the assistant row from that flag, so a partial reply keeps rendering as live output.Expected: a cancelled item is not streaming, as already happens on the other terminal paths.
Change
cancelledIteminProviderRuntimeRecoveryService.tsnow setsstreaming: falseon any item that has the field, using the same"streaming" in itemcheck asRunExecutionService. Those three types are the only turn items with the field, and other items keep their shape.Scope and approval
No triaged issue for this code path, under the very small, focused fix for an obvious bug route: a cancelled item cannot still be streaming, and the fix is one spread in one helper.
Related history, stated plainly so nobody has to dig for it:
proposed_plan.Verification
Extended the existing "cancels the complete in-flight subtree" case in
ProviderRuntimeRecoveryService.test.tswith one streaming item of each type.cd apps/server && vp test run src/orchestration-v2/ProviderRuntimeRecoveryService.test.ts -t "cancels the complete in-flight subtree"streaming: true.false.To check the client side, I ran a throwaway test (not committed) that applied a running, streaming
assistant_messageto the real SQLite projection store, ranrecovery.reconcile("startup"), read the row back fromgetThreadProjection, and passed it to the webderiveTimelineEntriesFromVisibleTurnItems:message.streamingcancelled,streaming: truetruecancelled,streaming: falsefalseThe recovery, regression, projection recovery and restart continuation test files pass (75 tests), and so does
vp run check:changed.Not checked: a real provider turn killed mid-stream in a running app, and the rendered result. From reading
TimelineAssistantRows.tsx, a streaming row hides its timestamp and keepsChatMarkdownin streaming mode, but I did not see that on screen. Mobile maps the flag the same way inthreadActivity.ts; I read that and did not run it.Claude Opus 5.5 via Claude Code