refactor(memory): clarify idle compact archive inputs

maintainer edit: rename the idle compact archive inputs so the code distinguishes messages being removed from messages being summarized. This keeps the #4264 behavior unchanged while making the retained-suffix summary rule easier to read.
This commit is contained in:
chengyongru
2026-06-13 22:24:30 +08:00
committed by Xubin Ren
parent 0863e6e5ab
commit be6419b289
+21 -26
View File
@@ -799,23 +799,22 @@ class Consolidator:
messages: list[dict],
*,
session_key: str | None = None,
summary_context: list[dict] | None = None,
summary_messages: list[dict] | None = None,
) -> str | None:
"""Summarize messages via LLM and append to history.jsonl.
``messages`` are the messages being archived (removed from the live
session); they are what gets raw-dumped if the LLM call fails.
``summary_context``, when given, is fed to the summarizer in place of
``messages`` so a caller can summarize over a wider window (e.g. the
full conversation tail) while still only archiving ``messages``.
``summary_messages``, when given, lets callers include retained
messages in the summary without archiving them.
Returns the summary text on success, None if nothing to archive.
"""
if not messages:
return None
context = summary_context if summary_context is not None else messages
messages_to_summarize = summary_messages if summary_messages is not None else messages
try:
formatted = MemoryStore._format_messages(context)
formatted = MemoryStore._format_messages(messages_to_summarize)
formatted = self._truncate_to_token_budget(formatted)
response = await self.provider.chat_with_retry(
model=self.model,
@@ -972,42 +971,38 @@ class Consolidator:
self.sessions.invalidate(session_key)
session = self.sessions.get_or_create(session_key)
tail = list(session.messages[session.last_consolidated:])
if not tail:
messages_to_summarize = list(session.messages[session.last_consolidated:])
if not messages_to_summarize:
session.updated_at = datetime.now()
self.sessions.save(session)
return ""
probe = Session(
key=session.key,
messages=tail.copy(),
messages=messages_to_summarize.copy(),
created_at=session.created_at,
updated_at=session.updated_at,
metadata={},
last_consolidated=0,
)
dropped, already_consolidated = probe.retain_recent_legal_suffix(max_suffix)
kept = probe.messages
archive_msgs = dropped[already_consolidated:]
messages_to_keep = probe.messages
messages_to_remove = dropped[already_consolidated:]
if not archive_msgs and not kept:
if not messages_to_remove and not messages_to_keep:
session.updated_at = datetime.now()
self.sessions.save(session)
return ""
last_active = session.updated_at
summary: str | None = ""
if archive_msgs:
# Summarize over the full unconsolidated tail — including the
# recent suffix we retain — not just the dropped prefix. Idle
# compaction usually runs on a finished conversation, so a late
# user correction or final result that landed in the kept suffix
# must still reach the persisted summary; otherwise history keeps
# the stale pre-correction conclusion that never gets fixed
# (#4264). Only archive_msgs are removed/raw-dumped; kept stays
# in the session.
if messages_to_remove:
# Summarize the retained suffix too, but only remove/raw-dump
# the messages that are no longer kept in the live session.
summary = await self.archive(
archive_msgs, session_key=session_key, summary_context=tail
messages_to_remove,
session_key=session_key,
summary_messages=messages_to_summarize,
)
if summary and summary != "(nothing)":
@@ -1016,17 +1011,17 @@ class Consolidator:
"last_active": last_active.isoformat(),
}
session.messages = kept
session.messages = messages_to_keep
session.last_consolidated = 0
session.updated_at = datetime.now()
self.sessions.save(session)
if archive_msgs:
if messages_to_remove:
logger.info(
"Idle-session compact for {}: archived={}, kept={}, summary={}",
session_key,
len(archive_msgs),
len(kept),
len(messages_to_remove),
len(messages_to_keep),
bool(summary),
)