Repository navigation
Keep compacted turns out of the session row - #1153
Draft
sosidudku1 wants to merge 2 commits into
Draft
sosidudku1 wants to merge 2 commits into
sosidudku1 wants to merge 2 commits into
Conversation
Every write of a session (each step's checkpoint, every turn's end) serialized the whole transcript into one JSON string, even the part a compaction had already summarized. On long sessions and overnight runs that string grows without bound, and so does the peak memory of each write. Turns covered by a compaction checkpoint now move once into a new session_turn_archive table, one row per turn. The row's payload keeps only the turns after them, plus an archivedTurns marker with the count and the first user message (for the session list). SessionStore.load, listRecent and listByWorkingDir put the archived turns back in front, so the in-memory transcript and every absolute index into it (coveredThrough, macroTurnStarts, pack start) are unchanged. - Archive rows are append-only and written in the same transaction as the payload. A write whose transcript no longer starts with the archived turns (an older copy, a replaced history) drops the archive and stores the transcript in full, so a load always returns what was saved. - Rows written before this change load as before and are migrated on their next write. Sessions without a checkpoint are stored exactly as before. - listChatLines and the summary page read across the archive. - delete, the retention pass and the desktop importer handle the archive. If the table cannot be created (read-only file, lock held), the store keeps storing transcripts in full. Refs ATO-1271
If the store could not create the turn archive table at open (a lock held past the busy timeout, a read-only file), it ran without the archive for its whole lifetime. Loading a compacted session then stripped the archivedTurns marker and kept only the tail, the next save wrote that tail as the full transcript, and a later process with the archive saw a transcript unrelated to the archived rows and deleted them. - The archive is now retried lazily before each load, list and save (a table another process created is picked up at once; a failed create is retried after 30 seconds) instead of being disabled for the store's lifetime. - Without the archive, a loaded payload keeps its marker. Such a tail-only state is written back as it is, marker included, and never compared with the archived rows, so they are never cleared. Its stored checkpoint and rolling summary are kept as well. - A write that would still lose history is skipped with a process warning: a whole transcript over a row whose prefix is archived while the archive is unavailable, or a tail-only state over a row that no longer counts archived turns. - Tests: a store without the archive loads and saves a compacted session and a normal reopen still has every turn; a tail copy saved once the archive is back; checkpointTurn rolls archive rows back when the owner guard matches no row; the desktop importer reads a source's archived turns. Refs ATO-1271
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Long sessions re-serialized their whole transcript on every write: each step's checkpoint and every turn's end turned all of
SessionState.turnsinto one JSON string, including the part a compaction had already summarized. Peak memory per write grew with session age, the likely cause of the 0xC000009A crashes on multi-hour sessions and overnight runs (ATO-1271).What changes:
session_turn_archivetable, one row per turn, in the same transaction as the payload. The payload keeps only the turns after them, plus anarchivedTurnsmarker (count and first user message).load,listRecentandlistByWorkingDirput the archived turns back, so the in-memory transcript and all indices into it (coveredThrough,macroTurnStarts, pack start) are unchanged.listChatLinesand the session list's first prompt read across the archive.delete, the retention pass and the desktop importer handle it.If the archive table cannot be created at open (for example the shared database is write-locked by another process), the store retries before each load or save. While it is unavailable, a compacted session loads as its tail with the marker kept, is written back as a tail without touching the archive rows, and any save that would replace archived history is skipped with a warning (
ATOMIC_SESSION_ARCHIVE_UNAVAILABLE), so archived turns are never deleted.Not in this PR: the in-memory transcript is still full, and
loadstill parses all archived turns (row by row). Bounding memory itself needs a tail-only in-memory model and index rebasing across about 30 readers.Known risk, needs a decision before merge: the desktop app and the terminal share
~/.atomic-agent. An older binary (for example a desktop build without this change) opening a compacted session sees only the uncovered tail, drops the checkpoint as invalid, and if it saves, writesmacroTurnStartsrelative to the tail. Sessions never compacted are unaffected. Mixed versions on the same folder (old desktop + new terminal) drop the checkpoint and bring back the whole uncompacted history. The terminal and the desktop must ship this change together, in the same release.Not yet checked on the second Mac.