ReMe/reme/memory/file_based/components/summarizer.py
jinliyl 7b02c45218
style(memory): update message formatting and improve logging (#175)
* style(memory): update message formatting and improve logging

- Change default include_thinking parameter to True in as_msg_handler.py
- Replace angle brackets with square brackets for block formatting in as_msg_stat.py
- Add newline replacement in text truncation method in as_msg_stat.py
- Add loading duration timing to embedding cache loading in base_embedding_model.py
- Replace XML-style tags with markdown headers in compactor.py conversation format
- Update compactor.yaml prompts to reference markdown-style headers instead of XML tags
- Modify summarizer.py to use markdown-style conversation header format

* refactor(file-watcher): replace scan_on_start with rebuild_index_on_start parameter

- Replace scan_on_start and clear_on_start boolean parameters with single rebuild_index_on_start
- Update BaseFileWatcher constructor to use rebuild_index_on_start instead of two separate flags
- Modify initialization logic to clear and rescan when rebuild_index_on_start is True
- Remove scan_on_start parameter from CLI and light configuration files
- Update documentation to remove scan_on_start from quick start guides
- Rename all test methods and classes from scan_on_start to rebuild_index_on_start
- Add timezone-aware datetime helper method to summarizer component
- Format log message with proper line breaks for readability

* fix(core): resolve file watcher initialization issue and update version

- Fixed file watcher task creation to properly handle rebuild index on start logic
- Moved initialization and watch loop into async function to ensure proper execution order
- Updated package version from 0.3.1.1 to 0.3.1.2
- Added missing comma in embedding model logging statement

* fix(core): reduce max formatter text length limit

- Changed _DEFAULT_MAX_FORMATTER_TEXT_LENGTH from 2000 to 1000
- Updated constant value in as_msg_stat.py schema module

* fix(file-watcher): change default rebuild index behavior on start

- Changed rebuild_index_on_start parameter default from False to True
- This ensures index is rebuilt by default when file watcher starts
- Maintains consistent state initialization for file watching operations

* feat(compactor): add return_dict option and improve summary validation

- Add _is_valid_summary function to validate summary content format
- Introduce return_dict parameter to return structured results with validation
- Update prompt templates with clearer task descriptions and formatting rules
- Refactor update_user_message prompts to combine prefix and suffix logic
- Return dictionary with user_message, history_compact, and is_valid fields when enabled
- Add proper error handling for exception cases in memory compaction
- Maintain backward compatibility with string return when return_dict=False

* feat(memory): add thinking block configuration option

- Add add_thinking_block parameter to compactor component
- Pass include_thinking flag to message formatting in compactor
- Add add_thinking_block parameter to reme_light compact function
- Add add_thinking_block parameter to reme_light summarize function
- Add add_thinking_block parameter to summarizer component
- Pass include_thinking flag to message formatting in summarizer
- Remove previous-summary tags from compressed summary format
2026-03-24 00:20:15 +08:00

97 lines
3.4 KiB
Python

"""Summarizer module for memory summarization operations."""
import datetime
import zoneinfo
from agentscope.agent import ReActAgent
from agentscope.message import Msg
from agentscope.tool import Toolkit
from ..utils import AsMsgHandler
from ....core.op import BaseOp
from ....core.utils import get_logger
logger = get_logger()
class Summarizer(BaseOp):
"""Summarizer class for summarizing memory messages."""
def __init__(
self,
working_dir: str,
memory_dir: str,
memory_compact_threshold: int,
toolkit: Toolkit | None = None,
console_enabled: bool = False,
timezone: str | None = None,
add_thinking_block: bool = True,
**kwargs,
):
super().__init__(**kwargs)
self.working_dir: str = working_dir
self.memory_dir: str = memory_dir
self.memory_compact_threshold: int = memory_compact_threshold
self.toolkit: Toolkit | None = toolkit
self.console_enabled: bool = console_enabled
self.timezone: str | None = timezone
self.add_thinking_block: bool = add_thinking_block
def _get_current_datetime(self) -> datetime.datetime:
"""Get current datetime with timezone, fallback to local time if timezone is invalid."""
if self.timezone:
try:
return datetime.datetime.now(zoneinfo.ZoneInfo(self.timezone))
except Exception as e:
logger.error(f"Invalid timezone: {self.timezone}, falling back to local time error={e}")
return datetime.datetime.now()
async def execute(self):
messages: list[Msg] = self.context.get("messages", [])
if not messages:
return ""
msg_handler = AsMsgHandler(self.as_token_counter)
before_token_count = await msg_handler.count_msgs_token(messages)
history_formatted_str: str = await msg_handler.format_msgs_to_str(
messages=messages,
memory_compact_threshold=self.memory_compact_threshold,
include_thinking=self.add_thinking_block,
)
after_token_count = await msg_handler.count_str_token(history_formatted_str)
logger.info(f"Summarizer before_token_count={before_token_count} after_token_count={after_token_count}")
if not history_formatted_str:
logger.warning(f"No history to summarize. messages={messages}")
return ""
agent = ReActAgent(
name="reme_summarizer",
model=self.as_llm,
sys_prompt="You are a helpful assistant.",
formatter=self.as_llm_formatter,
toolkit=self.toolkit,
)
agent.set_console_output_enabled(self.console_enabled)
user_message: str = f"# conversation\n{history_formatted_str}\n\n" + self.prompt_format(
"user_message",
date=self._get_current_datetime().strftime("%Y-%m-%d"),
working_dir=self.working_dir,
memory_dir=self.memory_dir,
)
summary_msg: Msg = await agent.reply(
Msg(
name="reme",
role="user",
content=user_message,
),
)
for i, (msg, _) in enumerate(agent.memory.content):
logger.info(f"Summarizer memory[{i}]: {msg.content}")
history_summary: str = summary_msg.get_text_content()
logger.info(f"Summarizer Result:\n{history_summary}")
return history_summary