fix: simplify session recency activity tracking

maintainer edit: remove the _last_compacted_at maintenance state, gate idle compaction on whether a session still has a removable tail, and sort WebUI sessions by the latest visible transcript activity.
This commit is contained in:
chengyongru
2026-06-30 23:38:32 +08:00
committed by Xubin Ren
parent 3403b87641
commit 840ba5af33
7 changed files with 94 additions and 88 deletions
+19 -12
View File
@@ -8,7 +8,6 @@ from typing import TYPE_CHECKING, Callable, Coroutine
from loguru import logger
from nanobot.agent.memory import LAST_COMPACTED_AT_META
from nanobot.session.manager import Session, SessionManager
if TYPE_CHECKING:
@@ -46,17 +45,25 @@ class AutoCompact:
now_epoch = self._timestamp(now or datetime.now())
return now_epoch is not None and now_epoch - ts_epoch >= self._ttl * 60
def _compacted_after_activity(self, key: str, last_active: datetime | str | None) -> bool:
metadata_row = self.sessions.read_session_metadata(key)
metadata = metadata_row.get("metadata") if isinstance(metadata_row, dict) else None
if not isinstance(metadata, dict):
def _has_compactable_idle_tail(self, key: str) -> bool:
session = self.sessions.get_or_create(key)
tail = list(session.messages[session.last_consolidated:])
if not tail:
return False
compacted_at = metadata.get(LAST_COMPACTED_AT_META)
if not isinstance(compacted_at, str):
return False
compacted_epoch = self._timestamp(compacted_at)
active_epoch = self._timestamp(last_active)
return compacted_epoch is not None and active_epoch is not None and compacted_epoch >= active_epoch
probe = Session(
key=session.key,
messages=tail.copy(),
created_at=session.created_at,
updated_at=session.updated_at,
metadata={},
last_consolidated=0,
)
result = probe.retain_recent_legal_suffix(
self._RECENT_SUFFIX_MESSAGES,
extend_to_user=True,
)
messages_to_remove = result.dropped[result.already_consolidated_count:]
return bool(messages_to_remove)
@staticmethod
def _format_summary(text: str, last_active: datetime) -> str:
@@ -77,7 +84,7 @@ class AutoCompact:
if key in active_session_keys:
continue
updated_at = info.get("updated_at")
if self._is_expired(updated_at, now) and not self._compacted_after_activity(key, updated_at):
if self._is_expired(updated_at, now) and self._has_compactable_idle_tail(key):
self._archiving.add(key)
schedule_background(self._archive(key))
-7
View File
@@ -33,9 +33,6 @@ if TYPE_CHECKING:
from nanobot.providers.base import LLMProvider
from nanobot.session.manager import SessionManager
LAST_COMPACTED_AT_META = "_last_compacted_at"
# ---------------------------------------------------------------------------
# MemoryStore — pure file I/O layer
# ---------------------------------------------------------------------------
@@ -1005,11 +1002,9 @@ class Consolidator:
async with lock:
self.sessions.invalidate(session_key)
session = self.sessions.get_or_create(session_key)
compacted_at = datetime.now().isoformat()
messages_to_summarize = list(session.messages[session.last_consolidated:])
if not messages_to_summarize:
session.metadata[LAST_COMPACTED_AT_META] = compacted_at
self.sessions.save(session)
return ""
@@ -1026,7 +1021,6 @@ class Consolidator:
messages_to_remove = result.dropped[result.already_consolidated_count:]
if not messages_to_remove and not messages_to_keep:
session.metadata[LAST_COMPACTED_AT_META] = compacted_at
self.sessions.save(session)
return ""
@@ -1049,7 +1043,6 @@ class Consolidator:
session.messages = messages_to_keep
session.last_consolidated = 0
session.metadata[LAST_COMPACTED_AT_META] = compacted_at
self.sessions.save(session)
if messages_to_remove: