mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-01 01:51:44 +00:00
fix(hindsight): flush buffered turns and drop stale prefetch on session switch
Two data-loss / leak gaps in HindsightMemoryProvider.on_session_switch introduced by #17409. 1. Buffered turns silently lost when retain_every_n_turns > 1. on_session_switch unconditionally cleared _session_turns without flushing. Users who batched every N>1 turns and switched mid-batch (/reset, /new, /resume, /branch, or context compression) had those buffered turns disappear. Same data-loss class as the shutdown race, different lifecycle event. Note commit_memory_session() -> on_session_end() runs *before* on_session_switch on /reset, but Hindsight doesn't implement on_session_end so the buffer survives that step and dies at clear time. /resume, /branch, and compression skip commit_memory_session entirely so an on_session_end impl wouldn't help them anyway. Fix: snapshot the old _session_id, _document_id, _parent_session_id, _turn_index, and _session_turns; spawn one final retain that lands under the OLD document_id; then rotate state. Metadata is built synchronously against the old self._* so session_id / lineage tags on the flushed item all reference the prior session consistently. 2. Stale _prefetch_result leaks across switch. If queue_prefetch ran in the old session and the result hadn't been consumed by prefetch() yet, on_session_switch left the cached recall text in place. The next session's first prefetch() call would return text mined from the prior session's bank/query. Fix: join any in-flight _prefetch_thread (3s bounded — matches shutdown()), then clear _prefetch_result under _prefetch_lock before rotating session_id. Tests ----- - tests/plugins/memory/test_hindsight_provider.py (TestSessionSwitchBufferFlush): - buffered turns flushed under OLD document_id with OLD lineage tags - empty buffer => no spurious retain - _prefetch_result cleared on switch - in-flight prefetch thread is awaited before clear (no race) - tests/agent/test_memory_session_switch.py: factory extended to seed the attrs the new flush path reads (_retain_source, _platform, _bank_id, prefetch state, etc.) and stub _run_hindsight_operation so existing switch-state assertions keep passing without network setup.
This commit is contained in:
parent
1bedc836b5
commit
c38dac742b
3 changed files with 191 additions and 0 deletions
|
|
@ -205,6 +205,7 @@ def _make_hindsight_provider():
|
|||
bypassing __init__ and seeding the attributes on_session_switch
|
||||
reads/writes. This keeps the test hermetic.
|
||||
"""
|
||||
import threading
|
||||
hindsight_mod = pytest.importorskip("plugins.memory.hindsight")
|
||||
provider = object.__new__(hindsight_mod.HindsightMemoryProvider)
|
||||
provider._session_id = "old-sid"
|
||||
|
|
@ -213,6 +214,33 @@ def _make_hindsight_provider():
|
|||
provider._session_turns = ["turn-1", "turn-2"]
|
||||
provider._turn_counter = 2
|
||||
provider._turn_index = 2
|
||||
# Attrs read by _build_metadata / _build_retain_kwargs when the
|
||||
# buffer-flush path on session switch fires. Empty strings keep the
|
||||
# metadata minimal but well-formed.
|
||||
provider._retain_source = ""
|
||||
provider._platform = ""
|
||||
provider._user_id = ""
|
||||
provider._user_name = ""
|
||||
provider._chat_id = ""
|
||||
provider._chat_name = ""
|
||||
provider._chat_type = ""
|
||||
provider._thread_id = ""
|
||||
provider._agent_identity = ""
|
||||
provider._agent_workspace = ""
|
||||
provider._retain_tags = []
|
||||
provider._retain_context = "test-context"
|
||||
provider._retain_async = False
|
||||
provider._bank_id = "test-bank"
|
||||
# Prefetch state the switch path drains/clears.
|
||||
provider._prefetch_thread = None
|
||||
provider._prefetch_lock = threading.Lock()
|
||||
provider._prefetch_result = ""
|
||||
# Sync thread tracking — flush spawn target.
|
||||
provider._sync_thread = None
|
||||
# Stub the network-touching helper so the spawned flush thread is a
|
||||
# no-op in unit tests. Real plugin behavior is covered by the
|
||||
# mock-client tests in tests/plugins/memory/test_hindsight_provider.py.
|
||||
provider._run_hindsight_operation = lambda _op: None
|
||||
return provider
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue