a8763e175f
update_world_state relied entirely on the DM remembering to call it — no code checked whether it actually happened. Add refresh_if_due(), called at the top of every DM turn: it counts messages since the summary was last touched (by the tool or a prior auto-refresh), and once AUTO_REFRESH_MESSAGE_THRESHOLD (10) is crossed, forces a dedicated summarization call — a separate, tool-free completion whose only job is to fold the new messages into the existing summary — and persists the result directly, without waiting on the main DM turn's discretion. The trigger condition (message count) is deterministic; only the summary text itself still needs an LLM, which is unavoidable for a task that requires understanding, not just counting. context.py gained count_messages_since() and build_transcript_text() (an uncapped, since-filtered plain-text transcript for the summarizer, as opposed to build_context()'s char-budget-capped chat list for the main DM call) — factored out of the same underlying message-labeling logic to avoid duplicating the name-resolution joins. Verified with a fake LLM client: confirmed the trigger fires exactly at the threshold and not before, resets after firing, and that the second refresh's prompt carries the prior summary forward while only including messages since that refresh (not the whole history again). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>