You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] Many times, it lost my latest session content #1279
Many times, it lost latest session content and it shows "Continue" and "New task" button. I'm sure that the session was normally closed. It lost the critical session content.
Context (who is affected and when)
Reproduction steps
Use Zoocode to do something.
And the session content is ok.
Next time when it open, saveral latest sesson content is gone.
Turn [200] — user: tool_result for that read_file ({"status":"approved","feedback":"Well, you're now trying from OUTSIDE docker to reach INSIDE docker ..."}) + an <environment_details> block. The ACH stops here.
The recovered snapshot ui_messages.1787129799.json (430 events) ends differently from the current ui_messages.json:
event [428]
event [429]
snapshot (crash time)
say:api_req_started{"tokensIn":0,"tokensOut":0,…}
say:reasoning — text cut off mid-sentence: "…to run Cypress INSIDE the docker network (via"
current (reopened)
same
ask:resume_completed_task
So the assistant had started streaming a reasoning block (tokensOut:0 — the request was still in flight), and the provider terminated it mid-stream. The reasoning and any subsequent tool calls/file reads were never persisted to the ACH, and the partial reasoning was later overwritten by the resume ask when the task was reopened.
2. Where this happens in the Zoo-Code source
The root cause is that a mid-stream API termination is never committed to the conversation history. Three spots in Task.ts:
Task.ts:4465-4473 — in attemptApiRequest, the first chunk is wrapped in try/catch (which emits the api_req_failed ask), but the remaining chunks are yield* iteratoroutside the try/catch. The comment at Task.ts:4426 states this explicitly: "if the api failed mid-stream, it could be in any arbitrary state… that error is handled differently and requires cancelling the task entirely."
Task.ts:3577-3581 — the assistant message is saved to the ACH via addToApiConversationHistory(...)only after the streaming loop completes (// Save assistant message BEFORE executing tools). A stream that throws mid-flight never reaches this line, so the partial assistantContent (reasoning + any tool_use blocks) is lost from api_conversation_history.json.
Task.ts:3780-3788 — the catch handler in recursivelyMakeClineRequests just return true (end the task), discarding the partially-streamed assistant content without persisting it.
Summary
The trailing events (reasoning + tool calls/file reads) are lost in both ACH and UIM because a provider-terminated mid-stream response is abandoned: the streaming loop throws, the addToApiConversationHistory save point is skipped, and the catch block ends the task without flushing the partial assistant turn. The only trace is the truncated say:reasoning captured in the crash-time snapshot — which the reopen/resume flow then replaces with the terminal ask:resume_completed_task.
@jiangbing321 can you confirm that it might only have happened in cases where the last entry before closing the task was an API error?
Thanks a lot!
It's not an API error. The session was normally closed. The lost contents are often the critical and important conclusion of the LLM.
This remains reproducible on the v3.78 code path. Three current behaviors combine to lose visible history:
readTaskMessages() maps missing, parse, and transient I/O failures to []; resumeTaskFromHistory() then persists that empty result via overwriteClineMessages().
Resume removes every trailing reasoning row, including finalized (partial: false) rows, and persists the shortened history before showing the resume prompt.
An abandoned history-task instance can finish hydration after eviction and still write because ownership/cancellation is not rechecked after the awaited read.
A completed task also retains terminal completed status after Continue, explaining why later unfinished work reopens with “Continue / New task.”
I have added this issue as a sub-issue of #355. The implementation will proceed test-first with deterministic persistence tests. An extension-host e2e will be added only for behavior that can be asserted without relying on the sub-millisecond disk race. Related roadmap work: #364, #366, #367, #368, and #370.
The canonical regressions are deterministic task/persistence tests covering missing, invalid, and I/O-failed hydration; finalized trailing reasoning; and eviction while hydration is pending. The existing extension-host resume/evict e2e remains smoke coverage because the public test API cannot seed or inspect ui_messages.json or control the sub-millisecond disk-read window.
Fixed by #1319 — reopenParentFromDelegation now reads both UI and API history and saves them under the per-file advisory lock before the lifecycle transition fires. restart-persistence.test.ts is the controlled barrier test.
Activity
martin-rueegg commentedon Aug 19, 2026
I've just experienced this too. with the new Intellij plugin v3.78.0
I've not experienced it with v3.76.0, though.
Still investigating ...
martin-rueegg commentedon Aug 19, 2026
Since I'm regularly syncing my history, I checked a previous version of the
ui_messages.json, and it confirms that the last{ "ts": 1787129798107, "type": "say", "say": "reasoning", "text": "...", "partial": false }which was on disk previously, got replaced by
{ "ts": 1787142723063, "type": "ask", "ask": "resume_completed_task" }however, it is to be noted, that the just preceding node is:
{ "ts": 1787129794658, "type": "say", "say": "api_req_started", "text": "{\"apiProtocol\":\"openai\",\"tokensIn\":0,\"tokensOut\":0,\"cacheWrites\":0,\"cacheReads\":0,\"cost\":0,\"cancelReason\":\"streaming_failed\",\"streamingFailedMessage\":\"Provider ended the request: terminated\"}" },in both version. the text says:
{ "apiProtocol": "openai", "tokensIn": 0, "tokensOut": 0, "cacheWrites": 0, "cacheReads": 0, "cost": 0, "cancelReason": "streaming_failed", "streamingFailedMessage": "Provider ended the request: terminated" }martin-rueegg commentedon Aug 19, 2026
Root-cause analysis: trailing truncation in
01a014e41. The anomaly at the end of the history
The ACH ends with a user turn — there is no assistant response after it:
[199]— assistant:reasoning+tool_use read_file(lib/Listener/AppDisableListener.php, idcall_00_olWL031VWhaWHwYtUikB9896).[200]— user:tool_resultfor thatread_file({"status":"approved","feedback":"Well, you're now trying from OUTSIDE docker to reach INSIDE docker ..."}) + an<environment_details>block. The ACH stops here.The recovered snapshot
ui_messages.1787129799.json(430 events) ends differently from the currentui_messages.json:[428][429]say:api_req_started{"tokensIn":0,"tokensOut":0,…}say:reasoning— text cut off mid-sentence: "…to run Cypress INSIDE the docker network (via"ask:resume_completed_taskSo the assistant had started streaming a reasoning block (
tokensOut:0— the request was still in flight), and the provider terminated it mid-stream. The reasoning and any subsequent tool calls/file reads were never persisted to the ACH, and the partial reasoning was later overwritten by the resume ask when the task was reopened.2. Where this happens in the Zoo-Code source
The root cause is that a mid-stream API termination is never committed to the conversation history. Three spots in
Task.ts:Task.ts:4465-4473— inattemptApiRequest, the first chunk is wrapped intry/catch(which emits theapi_req_failedask), but the remaining chunks areyield* iteratoroutside thetry/catch. The comment atTask.ts:4426states this explicitly: "if the api failed mid-stream, it could be in any arbitrary state… that error is handled differently and requires cancelling the task entirely."Task.ts:3577-3581— the assistant message is saved to the ACH viaaddToApiConversationHistory(...)only after the streaming loop completes (// Save assistant message BEFORE executing tools). A stream that throws mid-flight never reaches this line, so the partialassistantContent(reasoning + any tool_use blocks) is lost fromapi_conversation_history.json.Task.ts:3780-3788— the catch handler inrecursivelyMakeClineRequestsjustreturn true(end the task), discarding the partially-streamed assistant content without persisting it.Summary
The trailing events (reasoning + tool calls/file reads) are lost in both ACH and UIM because a provider-terminated mid-stream response is abandoned: the streaming loop throws, the
addToApiConversationHistorysave point is skipped, and the catch block ends the task without flushing the partial assistant turn. The only trace is the truncatedsay:reasoningcaptured in the crash-time snapshot — which the reopen/resume flow then replaces with the terminalask:resume_completed_task.martin-rueegg commentedon Aug 19, 2026
@jiangbing321 can you confirm that it might only have happened in cases where the last entry before closing the task was an API error?
jiangbing321 commentedon Aug 20, 2026
martin-rueegg commentedon Aug 20, 2026
ok, that means that the analysis above is not the (only) root cause.
zoomote commentedon Aug 21, 2026
Reproduction and implementation update:
This remains reproducible on the v3.78 code path. Three current behaviors combine to lose visible history:
readTaskMessages()maps missing, parse, and transient I/O failures to[];resumeTaskFromHistory()then persists that empty result viaoverwriteClineMessages().reasoningrow, including finalized (partial: false) rows, and persists the shortened history before showing the resume prompt.A completed task also retains terminal
completedstatus after Continue, explaining why later unfinished work reopens with “Continue / New task.”I have added this issue as a sub-issue of #355. The implementation will proceed test-first with deterministic persistence tests. An extension-host e2e will be added only for behavior that can be asserted without relying on the sub-millisecond disk race. Related roadmap work: #364, #366, #367, #368, and #370.
zoomote commentedon Aug 21, 2026
Implementation is ready for review in paired draft PRs:
The canonical regressions are deterministic task/persistence tests covering missing, invalid, and I/O-failed hydration; finalized trailing reasoning; and eviction while hydration is pending. The existing extension-host resume/evict e2e remains smoke coverage because the public test API cannot seed or inspect
ui_messages.jsonor control the sub-millisecond disk-read window.edelauna commentedon Sep 6, 2026
Fixed by #1319 —
reopenParentFromDelegationnow reads both UI and API history and saves them under the per-file advisory lock before the lifecycle transition fires.restart-persistence.test.tsis the controlled barrier test.