"""Journal closeout — nightly extraction of profile observations. Runs once per user per day at day_rollover_hour. Reads yesterday's /journal conversation, filters out assistant-authored auto-content (daily prep), asks the background LLM to extract user-side patterns/habits, and appends the bullets to user_profiles.observations_raw via append_observations. """ from __future__ import annotations # Message kinds whose content must NEVER be sent to the closeout LLM. # These are assistant-authored auto-blocks that would otherwise dominate # attention and leak back into "what the assistant has learned." EXCLUDED_KINDS: set[str] = {"daily_prep"} def _filter_messages(messages): """Drop messages whose msg_metadata.kind is in EXCLUDED_KINDS. Accepts any iterable of message-like objects with `role`, `content`, and `msg_metadata` attributes (real Message rows or SimpleNamespace). """ kept = [] for m in messages: meta = getattr(m, "msg_metadata", None) or {} if meta.get("kind") in EXCLUDED_KINDS: continue kept.append(m) return kept