From 940a2f47a9dba2644f97a998769ae49dde2f55cc Mon Sep 17 00:00:00 2001 From: aquamarine Date: Thu, 19 Mar 2026 02:24:52 -0500 Subject: [PATCH] fix(reme): use timezone-aware datetime in memory summarization (#165) Use user-specified timezone instead of system local time when generating daily note filenames and timestamps in memory summarization and CLI. Changes: - Summarizer: accept 'timezone' param in __init__; use datetime.now(zoneinfo.ZoneInfo(tz)) instead of naive datetime.now() - ReMeLight.summary_memory(): accept 'timezone' param and pass to Summarizer - CliAgent: accept 'timezone' param in __init__; pass to Summarizer and use for current_time timestamp in system prompts - Fallback to system local time if timezone is None (preserves original behavior) Fixes timezone mismatch when system timezone differs from user's actual location (e.g., server in UTC+8 but user in America/Chicago). --- reme/memory/file_based/components/cli.py | 8 +++++++- reme/memory/file_based/components/summarizer.py | 11 ++++++++++- reme/reme_light.py | 4 ++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/reme/memory/file_based/components/cli.py b/reme/memory/file_based/components/cli.py index f4dddc21..11d45035 100644 --- a/reme/memory/file_based/components/cli.py +++ b/reme/memory/file_based/components/cli.py @@ -3,6 +3,7 @@ import asyncio from datetime import datetime from pathlib import Path +import zoneinfo from agentscope.agent import ReActAgent from agentscope.message import Msg, TextBlock @@ -46,6 +47,7 @@ class CliAgent(BaseOp): reserve_tokens: int = 36000, keep_recent_tokens: int = 20000, language: str = "zh", + timezone: str | None = None, **kwargs, ): super().__init__(**kwargs) @@ -57,6 +59,7 @@ class CliAgent(BaseOp): self.reserve_tokens: int = reserve_tokens self.keep_recent_tokens: int = keep_recent_tokens self.language: str = language + self.timezone: str | None = timezone # Initialize message history self.messages: list[Msg] = [] @@ -93,6 +96,7 @@ class CliAgent(BaseOp): as_llm_formatter=self.as_llm_formatter, language=self.language if self.language == "zh" else "", console_enabled=False, # We disable the terminal printing to avoid messy outputs + timezone=self.timezone, ) # Create summary task @@ -168,6 +172,7 @@ class CliAgent(BaseOp): as_llm_formatter=self.as_llm_formatter, language=self.language if self.language == "zh" else "", console_enabled=False, # We disable the terminal printing to avoid messy outputs + timezone=self.timezone, ) summary_content = await compactor.call( @@ -195,7 +200,8 @@ class CliAgent(BaseOp): async def _build_messages(self, query: str) -> list[Msg]: """Build system prompt message.""" - current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S %A") + tz = zoneinfo.ZoneInfo(self.timezone) if self.timezone else None + current_time = datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S %A") # Create system prompt system_prompt = self.prompt_format( diff --git a/reme/memory/file_based/components/summarizer.py b/reme/memory/file_based/components/summarizer.py index d553a5f6..855d64c1 100644 --- a/reme/memory/file_based/components/summarizer.py +++ b/reme/memory/file_based/components/summarizer.py @@ -1,6 +1,7 @@ """Summarizer module for memory summarization operations.""" import datetime +import zoneinfo from agentscope.agent import ReActAgent from agentscope.message import Msg @@ -23,6 +24,7 @@ class Summarizer(BaseOp): memory_compact_threshold: int, toolkit: Toolkit | None = None, console_enabled: bool = False, + timezone: str | None = None, **kwargs, ): super().__init__(**kwargs) @@ -31,6 +33,7 @@ class Summarizer(BaseOp): self.memory_compact_threshold: int = memory_compact_threshold self.toolkit: Toolkit | None = toolkit self.console_enabled: bool = console_enabled + self.timezone: str | None = timezone async def execute(self): messages: list[Msg] = self.context.get("messages", []) @@ -62,7 +65,13 @@ class Summarizer(BaseOp): user_message: str = f"\n{history_formatted_str}\n\n" + self.prompt_format( "user_message", - date=datetime.datetime.now().strftime("%Y-%m-%d"), + date=( + datetime.datetime.now( + zoneinfo.ZoneInfo(self.timezone), + ) + if self.timezone + else datetime.datetime.now() + ).strftime("%Y-%m-%d"), working_dir=self.working_dir, memory_dir=self.memory_dir, ) diff --git a/reme/reme_light.py b/reme/reme_light.py index 46b0ffe9..c8561550 100644 --- a/reme/reme_light.py +++ b/reme/reme_light.py @@ -406,6 +406,7 @@ class ReMeLight(Application): language: str = "zh", max_input_length: float = 128 * 1024, compact_ratio: float = 0.7, + timezone: str | None = None, ) -> str: """ Generate a comprehensive summary of the given messages. @@ -430,6 +431,8 @@ class ReMeLight(Application): Defaults to 128K tokens. compact_ratio (float): Ratio used to calculate compaction threshold. Defaults to 0.7. + timezone (str | None): Timezone string for date formatting + (e.g., "America/Chicago"). Defaults to system local time if None. Returns: str: The generated summary text, or an empty string if an error occurred. @@ -455,6 +458,7 @@ class ReMeLight(Application): as_llm_formatter=as_llm_formatter, as_token_counter=as_token_counter, language=language if language == "zh" else "", + timezone=timezone, ) return await summarizer.call(messages=messages, service_context=self.service_context)