Context
#6654 fixes the Hindsight resume overwrite bug for the CLI path (hermes --resume <id> / hermes -c) by scoping document_id to the process lifecycle. Each new process gets a fresh document_id, so resuming via the terminal works correctly.
However, the fix does not cover the in-chat slash commands:
/resume <id> — swaps session in-process
/branch [name] — forks the current session into a new one
Both of these reassign self.session_id and self.agent.session_id mid-process without notifying memory providers. The Hindsight provider (and any other provider that caches per-session state in initialize()) keeps its old _session_id, accumulated state, and document tracking — so subsequent turns get written into the wrong session's memory document.
Why the plugin can't fix this on its own
run_agent.py calls self._memory_manager.sync_all(user, response) without passing session_id:
# run_agent.py
self._memory_manager.sync_all(original_user_message, final_response)
self._memory_manager.queue_prefetch_all(original_user_message)
The memory provider has no way to detect the session switch — it only sees what was set during initialize(). The agent's session_id attribute is updated, but the provider never gets the new value.
Proposed Solutions
Any one of the following would unblock plugins:
Option A: Pass session_id through the manager methods
run_agent.py already has self.session_id available. Pass it explicitly:
self._memory_manager.sync_all(
original_user_message, final_response,
session_id=self.session_id,
)
self._memory_manager.queue_prefetch_all(
original_user_message,
session_id=self.session_id,
)
MemoryManager.sync_all and queue_prefetch_all already accept session_id as a kwarg — they just need to be called with it. Providers can then detect a mismatch with their cached _session_id and reset internal state.
Pros: smallest change, no ABC modification, backward compatible (existing providers ignore the kwarg).
Option B: Add an on_session_switch hook to MemoryProvider
# agent/memory_provider.py
def on_session_switch(self, new_session_id: str, **kwargs) -> None:
\"\"\"Called when the agent switches to a different session mid-process.
Triggered by /resume and /branch slash commands. Providers should
reset any per-session in-memory state (caches, counters, etc.).
Default is no-op.
\"\"\"
\`\`\`
Then `cli.py:_handle_resume_command` and `_handle_branch_command` would call:
```python
if self.agent and self.agent._memory_manager:
for p in self.agent._memory_manager.providers:
try:
p.on_session_switch(new_session_id, parent_session_id=old_session_id)
except Exception as e:
logger.warning(\"on_session_switch failed: %s\", e)
Pros: explicit signal, providers don't have to detect drift on every turn.
Cons: new ABC method.
Option C: Re-call initialize() on session switch
Simplest signal — just have _handle_resume_command call provider.initialize(new_session_id, ...) again. Providers already need initialize() to be idempotent for cron flushes, so this should be safe in most cases.
Pros: zero new API surface.
Cons: providers may set up resources in initialize() they don't want to re-create (clients, threads, daemon connections). Hindsight specifically guards against re-creating its _client, but other providers may not.
Affected providers
Any provider that caches per-session state in initialize() is potentially affected. Confirmed:
- Hindsight —
_session_id, _document_id, _session_turns, _turn_counter
Likely also affected (would need verification):
- Any provider that uses
session_id for scoping (per-user memory, per-session bank, etc.)
My preference
Option A seems cleanest: it's the smallest possible change, doesn't extend the ABC, is backward compatible (the kwarg is already accepted by MemoryManager.sync_all), and gives plugins enough information to do the right thing on every turn.
I'm happy to implement whichever approach the maintainers prefer.
Context
#6654 fixes the Hindsight resume overwrite bug for the CLI path (
hermes --resume <id>/hermes -c) by scopingdocument_idto the process lifecycle. Each new process gets a freshdocument_id, so resuming via the terminal works correctly.However, the fix does not cover the in-chat slash commands:
/resume <id>— swaps session in-process/branch [name]— forks the current session into a new oneBoth of these reassign
self.session_idandself.agent.session_idmid-process without notifying memory providers. The Hindsight provider (and any other provider that caches per-session state ininitialize()) keeps its old_session_id, accumulated state, and document tracking — so subsequent turns get written into the wrong session's memory document.Why the plugin can't fix this on its own
run_agent.pycallsself._memory_manager.sync_all(user, response)without passingsession_id:The memory provider has no way to detect the session switch — it only sees what was set during
initialize(). The agent'ssession_idattribute is updated, but the provider never gets the new value.Proposed Solutions
Any one of the following would unblock plugins:
Option A: Pass
session_idthrough the manager methodsrun_agent.pyalready hasself.session_idavailable. Pass it explicitly:MemoryManager.sync_allandqueue_prefetch_allalready acceptsession_idas a kwarg — they just need to be called with it. Providers can then detect a mismatch with their cached_session_idand reset internal state.Pros: smallest change, no ABC modification, backward compatible (existing providers ignore the kwarg).
Option B: Add an
on_session_switchhook toMemoryProviderPros: explicit signal, providers don't have to detect drift on every turn.
Cons: new ABC method.
Option C: Re-call
initialize()on session switchSimplest signal — just have
_handle_resume_commandcallprovider.initialize(new_session_id, ...)again. Providers already needinitialize()to be idempotent for cron flushes, so this should be safe in most cases.Pros: zero new API surface.
Cons: providers may set up resources in
initialize()they don't want to re-create (clients, threads, daemon connections). Hindsight specifically guards against re-creating its_client, but other providers may not.Affected providers
Any provider that caches per-session state in
initialize()is potentially affected. Confirmed:_session_id,_document_id,_session_turns,_turn_counterLikely also affected (would need verification):
session_idfor scoping (per-user memory, per-session bank, etc.)My preference
Option A seems cleanest: it's the smallest possible change, doesn't extend the ABC, is backward compatible (the kwarg is already accepted by
MemoryManager.sync_all), and gives plugins enough information to do the right thing on every turn.I'm happy to implement whichever approach the maintainers prefer.