diff --git a/agent/memory/summarizer.py b/agent/memory/summarizer.py index c679c229..e0f2298d 100644 --- a/agent/memory/summarizer.py +++ b/agent/memory/summarizer.py @@ -175,6 +175,15 @@ class MemoryFlushManager: injection. """ try: + # Strip scheduler-injected pairs before any further processing. + # These messages already serve as short-term context inside the + # receiver session; promoting them into long-term daily memory + # produces low-value flat logs (e.g. "11:28 price=1013, normal / + # 11:58 price=1013, normal / ...") and wastes summarisation tokens. + messages = self._strip_scheduler_pairs(messages) + if not messages: + return False + import hashlib deduped = [] for m in messages: @@ -647,6 +656,40 @@ class MemoryFlushManager: return "\n".join(parts) return "" + @classmethod + def _strip_scheduler_pairs(cls, messages: List[Dict]) -> List[Dict]: + """Drop scheduler-injected user/assistant pairs from a flush batch. + + A scheduler user message starts with the ``[SCHEDULED]`` marker + (written by ``AgentBridge.remember_scheduled_output``); the message + immediately following it (if it is an assistant turn) is its paired + output and is dropped together. Regular user/assistant turns and + any tool_use / tool_result blocks are preserved as-is. + """ + if not messages: + return messages + + SCHEDULED_PREFIX = "[SCHEDULED]" + result = [] + skip_next_assistant = False + for msg in messages: + if not isinstance(msg, dict): + result.append(msg) + skip_next_assistant = False + continue + role = msg.get("role") + if skip_next_assistant and role == "assistant": + skip_next_assistant = False + continue + skip_next_assistant = False + if role == "user": + text = cls._extract_text_from_content(msg.get("content", "")) + if text.lstrip().startswith(SCHEDULED_PREFIX): + skip_next_assistant = True + continue + result.append(msg) + return result + def create_memory_files_if_needed(workspace_dir: Path, user_id: Optional[str] = None): """