From 02bfe308486696427e9a337f0e6a2bb04c9016a1 Mon Sep 17 00:00:00 2001 From: zhayujie Date: Tue, 28 Apr 2026 15:30:51 +0800 Subject: [PATCH] fix(memory): prevent duplicate Deep Dream runs --- agent/memory/summarizer.py | 17 +++++++++++------ bridge/agent_initializer.py | 5 ++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/agent/memory/summarizer.py b/agent/memory/summarizer.py index 9b23a705..c679c229 100644 --- a/agent/memory/summarizer.py +++ b/agent/memory/summarizer.py @@ -115,7 +115,7 @@ class MemoryFlushManager: self.last_flush_timestamp: Optional[datetime] = None self._trim_flushed_hashes: set = set() # Content hashes of already-flushed messages self._last_flushed_content_hash: str = "" # Content hash at last flush, for daily dedup - self._last_dream_input_hash: str = "" # Hash of dream input, for dedup + self._last_dream_input_hash: str = "" # "{date}:{daily_hash}" of last dream, for dedup self._last_flush_thread: Optional[threading.Thread] = None def get_today_memory_file(self, user_id: Optional[str] = None, ensure_exists: bool = False) -> Path: @@ -323,13 +323,18 @@ class MemoryFlushManager: logger.info("[DeepDream] No recent daily records, skipping to preserve existing MEMORY.md") return False - # Dedup: skip if input materials haven't changed since last dream + # Dedup: skip if same daily content already dreamed today. + # Note: only hash daily_content (not memory_content), because deep_dream + # itself rewrites MEMORY.md as a side effect, which would otherwise + # invalidate the hash on every subsequent call within the same window. import hashlib - input_hash = hashlib.md5((memory_content + daily_content).encode("utf-8")).hexdigest() - if not force and input_hash == self._last_dream_input_hash: - logger.debug("[DeepDream] Input unchanged since last dream, skipping") + daily_hash = hashlib.md5(daily_content.encode("utf-8")).hexdigest() + today_str = datetime.now().strftime("%Y-%m-%d") + dedup_key = f"{today_str}:{daily_hash}" + if not force and dedup_key == self._last_dream_input_hash: + logger.info("[DeepDream] Already dreamed today with same daily content, skipping") return False - self._last_dream_input_hash = input_hash + self._last_dream_input_hash = dedup_key logger.info( f"[DeepDream] Materials collected: " diff --git a/bridge/agent_initializer.py b/bridge/agent_initializer.py index 32768d39..5e02f67e 100644 --- a/bridge/agent_initializer.py +++ b/bridge/agent_initializer.py @@ -549,19 +549,22 @@ class AgentInitializer: def _daily_flush_loop(): import random + last_run_date = None # Track last successful run date to prevent same-day re-trigger while True: try: now = datetime.datetime.now() jitter_min = random.randint(50, 55) jitter_sec = random.randint(0, 59) target = now.replace(hour=23, minute=jitter_min, second=jitter_sec, microsecond=0) - if target <= now: + # Always schedule for tomorrow if we already ran today, or if target time has passed + if target <= now or (last_run_date == now.date()): target += datetime.timedelta(days=1) wait_seconds = (target - now).total_seconds() logger.info(f"[DailyFlush] Next flush at {target.strftime('%Y-%m-%d %H:%M:%S')} (in {wait_seconds/3600:.1f}h)") time.sleep(wait_seconds) self._flush_all_agents() + last_run_date = datetime.datetime.now().date() except Exception as e: logger.warning(f"[DailyFlush] Error in daily flush loop: {e}") time.sleep(3600)