Skip to content

fix(memory): pass session transcript to shutdown_memory_provider on gateway + CLI (#15165)#16571

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-e46dcd56
Apr 27, 2026
Merged

fix(memory): pass session transcript to shutdown_memory_provider on gateway + CLI (#15165)#16571
teknium1 merged 2 commits into
mainfrom
hermes/hermes-e46dcd56

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Memory providers' on_session_end hook now receives the real conversation transcript on both gateway session teardown and CLI exit, instead of an empty list. Fixes #15165.

Salvaged from #15481 (@briandevans) with the CLI sibling site fixed in a follow-up commit.

The bug

Both teardown paths called shutdown_memory_provider with an effectively-empty list:

  • Gateway (gateway/run.py): agent.shutdown_memory_provider() — no args, so on_session_end([]) fired on every provider.
  • CLI (cli.py): shutdown_memory_provider(getattr(agent, 'conversation_history', None) or [])AIAgent has no conversation_history attribute, so the or [] branch always fired.

Providers that early-return on empty input (Holographic, Hindsight mid-batch) never persisted the session. Hindsight specifically buffers turns and only flushes at retain_every_n_turns boundaries — any turns held below the modulus at restart/idle-expiry/exit were silently dropped.

The fix

Both sites now forward agent._session_messages — the transcript AIAgent maintains and refreshes every turn in _persist_session (run_agent.py:3378) and several loop paths.

session_messages = getattr(agent, "_session_messages", None)
if isinstance(session_messages, list):
    agent.shutdown_memory_provider(session_messages)
else:
    agent.shutdown_memory_provider()

The isinstance(..., list) guard is deliberate — it protects against MagicMock agents (whose attribute access auto-synthesises a child mock) falling through to providers that expect List[Dict], keeping existing test suites green.

Scope

Part A of #15165 only (plus the CLI sibling). Part B (adding an on_session_end implementation to the Hindsight plugin) is a separate concern that benefits from this landing first — without Part A the hook would still receive [].

Commits

  1. fix(gateway): pass session messages to shutdown_memory_provider@briandevans, cherry-picked from fix(gateway): pass session messages to shutdown_memory_provider (#15165) #15481
  2. fix(cli): pass session messages to shutdown_memory_provider — widens the same fix to the CLI exit path; fix(gateway): pass session messages to shutdown_memory_provider (#15165) #15481 was gateway-only

Test plan

  • tests/gateway/test_shutdown_memory_provider_messages.py (7 cases, from fix(gateway): pass session messages to shutdown_memory_provider (#15165) #15481) — populated list forwarded, empty list forwarded, missing attribute falls back, MagicMock falls back, provider exception swallowed, None agent no-op, agent without method tolerated.
  • tests/cli/test_cli_shutdown_memory_messages.py (4 cases, new) — populated, empty, non-list fallback, provider exception swallowed.
  • Regression guard verified: reverted the CLI fix → 3 of 4 new CLI tests fail with Expected: mock([...]) / Actual: mock(); restored → all pass.
  • Related gateway suites green: test_shutdown_cache_cleanup, test_compress_command, test_agent_cache, test_session_hygiene, test_background_command, test_compress_plugin_engine, test_session_boundary_hooks (92 + 15 = 107 passing).

Related

briandevans and others added 2 commits April 27, 2026 06:38
``_cleanup_agent_resources`` previously invoked
``agent.shutdown_memory_provider()`` with no arguments, so every memory
provider's ``on_session_end`` hook received an empty list. Providers
with an early-return guard on empty input (Holographic, Hindsight) never
extracted facts from the conversation, and users hit
"抱歉,找不到相關的對話記錄" on the first turn after any gateway
restart, session reset, or idle expiry.

Forward ``agent._session_messages`` — the transcript the agent itself
maintains and refreshes every turn via ``_persist_session`` — so
providers see the actual conversation. Falls back to the legacy no-arg
call whenever the attribute is absent or not a list (test stubs built
via ``object.__new__`` or ``MagicMock``) to preserve backward
compatibility with existing suites. ``AIAgent.shutdown_memory_provider``
already accepts ``messages: list = None`` (run_agent.py:4126), so this
is a pure caller-side fix.

Paths that use ``skip_memory=True`` temporary agents (memory flush,
hygiene auto-compress, ``/compress``) are no-ops inside
``shutdown_memory_provider`` because ``self._memory_manager`` is None —
no behaviour change for them.

Covers Part A of the bug report. Part B (adding ``on_session_end`` to
the Hindsight plugin) is a separate concern that would benefit from
this fix landing first.

Regression test added at
``tests/gateway/test_shutdown_memory_provider_messages.py`` covering:
populated messages forwarded, empty list still forwarded, attribute
missing falls back, non-list (MagicMock) falls back, provider
exceptions don't block ``close()``, None agent no-op, and agent
without ``shutdown_memory_provider`` tolerated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ibling)

The gateway fix in the previous commit forwards _session_messages on
gateway session teardown.  The CLI exit cleanup path had the same bug:
it read getattr(agent, 'conversation_history', None) or [] — but AIAgent
has no conversation_history attribute, so providers always received [].

Switch to _session_messages (same attribute the gateway now uses),
guarded by isinstance(..., list) to preserve the no-arg fallback for
MagicMock-based CLI test stubs.

Adds tests/cli/test_cli_shutdown_memory_messages.py (4 cases mirroring
the gateway suite).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Gateway restart drops session memory — shutdown_memory_provider receives empty messages

3 participants