Memory session commit missing context engine notifications
NousResearch/hermes-agent · cluster 22394
Data as of
Nothing open on GitHub. Fix merged in #22764. Check it covers your case.
The short answer
0open issues
0open PRs
6items grouped
- Known?
- Yes. 6 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #22764. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #22764. That is separate from the fix event. - Still open
- Nothing open on GitHub.
These issues and PRs address a bug where committing a memory session fails to notify the context engine or context compressor at session end. Multiple fixes target the same missing callback across related components.
Open issues0
Open PRs0
Fixes on record
-
#22764 fix(agent): notify context engine on commit_memory_session
files:
run_agent.py,tests/run_agent/test_commit_memory_session_context_engine.pyShow the diff
-
run_agent.py@@ -5067,12 +5067,25 @@ def commit_memory_session(self, messages: list = None) -> None: Called when session_id rotates (e.g. /new, context compression); providers keep their state and continue running under the old session_id — they just flush pending extraction now.""" - if not self._memory_manager: - return - try: - self._memory_manager.on_session_end(messages or []) - except Exception: - pass + if self._memory_manager: + try: + self._memory_manager.on_session_end(messages or []) + except Exception: + pass + # Notify context engine of session end too — same lifecycle moment as + # the memory manager's on_session_end. Without this, engines that + # accumulate per-session state (DAGs, summaries) leak that state from + # the rotated-out session into whatever comes next under the same + # compressor instance. Mirrors the call in shutdown_memory_provider(). + # See issue #22394. + if hasattr(self, "context_compressor") and self.context_compressor: + try: + self.context_compressor.on_session_end( + self.session_id or "", + messages or [], + ) + except Exception: + pass def _sync_external_memory_for_turn( self, -
tests/run_agent/test_commit_memory_session_context_engine.py@@ -0,0 +1,102 @@ +"""Regression tests for AIAgent.commit_memory_session. + +Issue #22394: commit_memory_session was calling MemoryManager.on_session_end +but never ContextEngine.on_session_end. Context engines that accumulate +per-session state (LCM-style DAGs, summary stores) leaked that state from a +rotated-out session into whatever continued under the same compressor +instance. +""" + +from __future__ import annotations + +from types import SimpleNamespace +from unittest.mock import MagicMock + + +def _make_minimal_agent(memory_manager, context_compressor, session_id="abc"): + """Build an object with just enough surface for commit_memory_session to run. + + AIAgent.__init__ is too heavy for a focused unit test — bind the method + to a SimpleNamespace-style object that has the attributes the method + actually touches. + """ + from run_agent import AIAgent + + obj = SimpleNamespace( + _memory_manager=memory_manager, + context_compressor=context_compressor, + session_id=session_id, + ) + obj.commit_memory_session = AIAgent.commit_memory_session.__get__(obj) + return obj + + +def test_commit_memory_session_notifies_context_engine(): + """Both the memory manager AND the context engine receive on_session_end.""" + mm = MagicMock() + ctx = MagicMock() + agent = _make_minimal_agent(mm, ctx, session_id="sess-42") + + msgs = [{"role": "user", "content": "hi"}, {"role": "assistant", "content": "yo"}] + agent.commit_memory_session(msgs) + + mm.on_session_end.assert_called_once_with(msgs) + ctx.on_session_end.assert_called_once_with("sess-42", msgs) + + +def test_commit_memory_session_with_no_messages_passes_empty_list(): + """Empty/None messages must still fire both hooks with an empty list.""" + mm = MagicMock() + ctx = MagicMock() + agent = _make_minimal_agent(mm, ctx, session_id="sess-7") + + agent.commit_memory_session(None) + + mm.on_session_end.assert_called_once_with([]) + ctx.on_session_end.assert_called_once_with("sess-7", []) + + +def test_commit_memory_session_no_memory_manager_still_notifies_context_engine(): + """If only the context engine is configured, it still gets the hook.""" + ctx = MagicMock() + agent = _make_minimal_agent(None, ctx, session_id="sess-9") + + agent.commit_memory_session([{"role": "user", "content": "x"}]) + + ctx.on_session_end.assert_called_once_with("sess-9", [{"role": "user", "content": "x"}]) + + +def test_commit_memory_session_no_context_engine_still_notifies_memory_manager(): + """If only the memory manager is configured, it still gets the hook.""" + mm = MagicMock() + agent = _make_minimal_agent(mm, None, session_id="sess-3") + + agent.commit_memory_session([{"role": "user", "content": "x"}]) + + mm.on_session_end.assert_called_once_with([{"role": "user", "content": "x"}]) + + +def test_commit_memory_session_tolerates_memory_manager_failure(): + """A raising memory manager must not block the context engine notification.""" + mm = MagicMock() + mm.on_session_end.side_effect = RuntimeError("boom") + ctx = MagicMock() + agent = _make_minimal_agent(mm, ctx, session_id="sess-X") + + # Must not raise + agent.commit_memory_session([{"role": "user", "content": "x"}]) + + ctx.on_session_end.assert_called_once_with("sess-X", [{"role": "user", "content": "x"}]) + + +def test_commit_memory_session_tolerates_context_engine_failure(): + """A raising context engine must not surface the exception.""" + mm = MagicMock() + ctx = MagicMock() + ctx.on_session_end.side_effect = RuntimeError("boom") + agent = _make_minimal_agent(mm, ctx, session_id="sess-Y") + + # Must not raise + agent.commit_memory_session([{"role": "user", "content": "x"}]) + + mm.on_session_end.assert_called_once()
-
4 PRs closed without merging
From the close comments: superseded by another PR 3 · duplicate 1
-
#22431 fix(run_agent): notify context engine on commit_memory_session (#22394) · superseded by another PR →
e90aa7f,#22764 -
#22433 fix(agent): notify context_compressor on commit_memory_session · superseded by another PR →
#22394,#22764 -
#22599 fix: commit context engine sessions on rotation · duplicate →
#22764,#22431,#22433 -
#22738 fix(memory): call context_compressor.on_session_end in commit_memory_session · superseded by another PR →
#22764,#22394
Closed issues · 1
- Closed#22394commit_memory_session() missing context_compressor.on_session_end() call
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.33: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Merged PRs
- #22764
- Closed issues
- 1
- Attempts
- 4 PRs closed without merging
- Fix link checked
- 9 May 2026