Bug Description
When a session expires and triggers a proactive memory flush, if the gateway restarts during or after the flush, the same session gets flushed again because the _pre_flushed_sessions set is in-memory only and resets on restart.
Evidence
From gateway logs at 2026-03-25 04:00-04:05:
04:00:18 - Session 20260324_075052_df00a65e expired, flushing memories proactively
[Hermes Gateway Starting...] ← Gateway restarted
04:04:51 - Same session expired again, flushing memories proactively (duplicate!)
The session was flushed twice, causing:
- Duplicate LLM API calls via OpenRouter
- Memory tool errors as the LLM tried to save already-saved memories
- Wasted tokens and potential memory corruption
Root Cause
In gateway/session.py:
self._pre_flushed_sessions: set = set() # session_ids already flushed by watcher
This set is initialized in __init__ and never persisted. When the gateway restarts, it resets to empty, so the expiry watcher in _session_expiry_watcher() sees the same expired session and flushes it again.
Proposed Fix
Persist _pre_flushed_sessions to state.db (the existing SQLite database used for other gateway state) so it survives restarts. The set should be:
- Written to state.db after each successful flush
- Loaded from state.db on gateway startup
- Cleaned up when sessions are actually reset/deleted
Additional Issue
The flush prompt should also account for memory being near/full. Currently it just says "save memories" without giving guidance to consolidate when at capacity. When memory is >90% full, the LLM generates invalid tool calls trying to work around the limit.
Bug Description
When a session expires and triggers a proactive memory flush, if the gateway restarts during or after the flush, the same session gets flushed again because the
_pre_flushed_sessionsset is in-memory only and resets on restart.Evidence
From gateway logs at 2026-03-25 04:00-04:05:
The session was flushed twice, causing:
Root Cause
In
gateway/session.py:This set is initialized in
__init__and never persisted. When the gateway restarts, it resets to empty, so the expiry watcher in_session_expiry_watcher()sees the same expired session and flushes it again.Proposed Fix
Persist
_pre_flushed_sessionstostate.db(the existing SQLite database used for other gateway state) so it survives restarts. The set should be:Additional Issue
The flush prompt should also account for memory being near/full. Currently it just says "save memories" without giving guidance to consolidate when at capacity. When memory is >90% full, the LLM generates invalid tool calls trying to work around the limit.