fix(coding-agent): prevent duplicate session prefixes and /tree freezes#1672
fix(coding-agent): prevent duplicate session prefixes and /tree freezes#1672w-winter wants to merge 1 commit intobadlogic:mainfrom
Conversation
|
Hi @w-winter, thanks for your interest in contributing! We ask new contributors to open an issue first before submitting a PR. This helps us discuss the approach and avoid wasted effort. Next steps:
This PR will be closed automatically. See https://github.com/badlogic/pi-mono/blob/main/CONTRIBUTING.md for more details. |
|
This papers over the actual issue: somehow a corrupted session was created. I need to understand how that happened. This is not the fix we are looking for. Can report on #contributors on discord. pinged you there. |
…m pre-assistant entry createBranchedSession() wrote the file and set flushed=true even when the branched path had no assistant message. The next _persist() call saw no assistant, reset flushed=false, and the subsequent flush appended all in-memory entries to the already-populated file, duplicating the header and entries. Fix: defer file creation when the branched path has no assistant message, matching the newSession() contract. _persist() creates the file on the first assistant response. closes #1672
|
Thanks @w-winter for the report and investigation. The root cause is right: We went with a narrower fix: The traversal guards (cycle detection in |
Problem
/treefreezes the TUI permanently (no input or paint until the tab is closed) on some sessions. The affected sessions'.jsonlfiles contain duplicated session headers and duplicate entry IDs./treedoes synchronous traversals that assume a well-formed tree, so duplicates and cycles cause non-terminating loops on the UI thread.How duplicated headers happen
Extensions can call
pi.appendEntry(...)before the first assistant message. For example,examples/extensions/preset.tspersists state onturn_start, which fires before the assistant responds. Session persistence is deferred until the first assistant message. When that flush fires,_persist()appends the full in-memoryfileEntriesto disk, but the file already has content from those earlyappendEntrycalls. Result: duplicated session header, prefix entries, and entry IDs.The added test
"rewrites deferred pre-assistant state instead of duplicating the existing session prefix"reproduces this directly.Fix
This prevents the duplication and hardens traversal so that existing malformed sessions don't hang.
Persistence: first deferred flush now rewrites the file instead of appending, so early extension entries are preserved without duplication.
Traversal guards:
buildSessionContext()andgetBranch(): visited-ID set terminates leaf-to-root walks on cyclesgetTree(): dedupes entries by ID (last occurrence wins), breaks parent cycles into roots, memoizes cycle detection for large sessionsValidation
npm run checkcd packages/coding-agent && npx vitest run test/session-manager/file-operations.test.tscd packages/coding-agent && npx vitest run test/session-manager/build-context.test.tscd packages/coding-agent && npx vitest run test/session-manager/tree-traversal.test.ts