fix(memory): pass session transcript to shutdown_memory_provider on gateway + CLI (#15165)#16571
Merged
Conversation
``_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).
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Memory providers'
on_session_endhook 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_providerwith an effectively-empty list:gateway/run.py):agent.shutdown_memory_provider()— no args, soon_session_end([])fired on every provider.cli.py):shutdown_memory_provider(getattr(agent, 'conversation_history', None) or [])—AIAgenthas noconversation_historyattribute, so theor []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_turnsboundaries — any turns held below the modulus at restart/idle-expiry/exit were silently dropped.The fix
Both sites now forward
agent._session_messages— the transcriptAIAgentmaintains and refreshes every turn in_persist_session(run_agent.py:3378) and several loop paths.The
isinstance(..., list)guard is deliberate — it protects against MagicMock agents (whose attribute access auto-synthesises a child mock) falling through to providers that expectList[Dict], keeping existing test suites green.Scope
Part A of #15165 only (plus the CLI sibling). Part B (adding an
on_session_endimplementation to the Hindsight plugin) is a separate concern that benefits from this landing first — without Part A the hook would still receive[].Commits
fix(gateway): pass session messages to shutdown_memory_provider— @briandevans, cherry-picked from fix(gateway): pass session messages to shutdown_memory_provider (#15165) #15481fix(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-onlyTest 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.Expected: mock([...]) / Actual: mock(); restored → all pass.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
/new//resetmemory commit, different code pathon_session_finalizenot fired on idle timeout (orthogonal)