fix(session): correct last_consolidated tracking in non-contiguous retention
The previous fix made retain_recent_legal_suffix return the actual dropped message list, but already_consolidated was still computed with min(before_last_consolidated, len(dropped)), which assumes dropped messages are always a prefix. In the else branch (tail has no user messages), dropped may include messages from after the consolidated prefix, causing already_consolidated to skip too many and leaving tail messages neither retained nor raw-archived. Fix by having retain_recent_legal_suffix return (dropped, already_consolidated_count) where already_consolidated_count is computed against original message indices. Also fix last_consolidated update to count how many retained messages were inside the old consolidated prefix.
This commit is contained in:
@@ -269,19 +269,25 @@ class Session:
|
||||
self.updated_at = datetime.now()
|
||||
self.metadata.pop("_last_summary", None)
|
||||
|
||||
def retain_recent_legal_suffix(self, max_messages: int) -> list[dict]:
|
||||
def retain_recent_legal_suffix(self, max_messages: int) -> tuple[list[dict], int]:
|
||||
"""Keep a legal recent suffix constrained by a hard message cap.
|
||||
|
||||
Returns the list of messages that were removed.
|
||||
Returns ``(dropped, already_consolidated_count)`` where *dropped* is
|
||||
the list of removed messages (in original order) and
|
||||
*already_consolidated_count* is how many of those were inside the
|
||||
pre-existing ``last_consolidated`` prefix and therefore do not need
|
||||
raw archiving.
|
||||
"""
|
||||
if max_messages <= 0:
|
||||
dropped = list(self.messages)
|
||||
lc = self.last_consolidated
|
||||
self.clear()
|
||||
return dropped
|
||||
return dropped, min(lc, len(dropped))
|
||||
if len(self.messages) <= max_messages:
|
||||
return []
|
||||
return [], 0
|
||||
|
||||
original = list(self.messages)
|
||||
before_lc = self.last_consolidated
|
||||
|
||||
retained = list(self.messages[-max_messages:])
|
||||
|
||||
@@ -318,10 +324,26 @@ class Session:
|
||||
retained_ids = set(id(m) for m in retained)
|
||||
dropped = [m for m in original if id(m) not in retained_ids]
|
||||
|
||||
# Count how many dropped messages were in the already-consolidated
|
||||
# prefix of the original list. This cannot be a simple min() because
|
||||
# dropped may include messages from *after* the consolidated prefix
|
||||
# (e.g. in the else branch).
|
||||
already_consolidated = sum(
|
||||
1 for i, m in enumerate(original)
|
||||
if i < before_lc and id(m) not in retained_ids
|
||||
)
|
||||
|
||||
# New last_consolidated = count of retained messages that were inside
|
||||
# the old consolidated prefix.
|
||||
new_lc = sum(
|
||||
1 for i, m in enumerate(original)
|
||||
if i < before_lc and id(m) in retained_ids
|
||||
)
|
||||
|
||||
self.messages = retained
|
||||
self.last_consolidated = max(0, self.last_consolidated - len(dropped))
|
||||
self.last_consolidated = new_lc
|
||||
self.updated_at = datetime.now()
|
||||
return dropped
|
||||
return dropped, already_consolidated
|
||||
|
||||
def enforce_file_cap(
|
||||
self,
|
||||
@@ -332,12 +354,10 @@ class Session:
|
||||
if limit <= 0 or len(self.messages) <= limit:
|
||||
return
|
||||
|
||||
before_last_consolidated = self.last_consolidated
|
||||
dropped = self.retain_recent_legal_suffix(limit)
|
||||
dropped, already_consolidated = self.retain_recent_legal_suffix(limit)
|
||||
if not dropped:
|
||||
return
|
||||
|
||||
already_consolidated = min(before_last_consolidated, len(dropped))
|
||||
archive_chunk = dropped[already_consolidated:]
|
||||
if archive_chunk and on_archive:
|
||||
on_archive(archive_chunk)
|
||||
|
||||
Reference in New Issue
Block a user