refactor(memory): promote on_session_reset to base provider hook

Replace hasattr-forked OpenViking-specific paths with a proper base-class
hook. Collapse the two agent wrappers into a single rotate_memory_session
so callers don't orchestrate commit + rebind themselves.

- MemoryProvider: add on_session_reset(new_session_id) as a default no-op
- MemoryManager: on_session_reset fans out unconditionally (no hasattr,
  no builtin skip — base no-op covers it)
- OpenViking: rename reset_session -> on_session_reset; drop the explicit
  POST /api/v1/sessions (OV auto-creates on first message) and the two
  debug raise_for_status wrappers
- AIAgent: collapse commit_memory_session + reinitialize_memory_session
  into rotate_memory_session(new_sid, messages)
- cli.py / run_agent.py: replace hasattr blocks and the split calls with
  a single unconditional rotate_memory_session call; compression path
  now passes the real messages list instead of []
- tests: align with on_session_reset, assert reset does NOT POST /sessions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
zhiheng.liu
2026-04-16 00:31:48 +08:00
committed by Teknium
parent 7856d304f2
commit 8275fa597a
6 changed files with 68 additions and 152 deletions

View File

@@ -281,25 +281,19 @@ class MemoryManager:
provider.name, e,
)
def restart_session(self, new_session_id: str) -> None:
"""Transition external providers to a new session without full teardown.
def on_session_reset(self, new_session_id: str) -> None:
"""Notify all providers of a session reset.
Must be called AFTER on_session_end() has committed the old session.
Providers that implement reset_session() are transitioned cheaply
(HTTP client kept alive); others fall back to a full initialize().
The builtin provider is skipped — it has no per-session state.
Called after on_session_end() has committed the previous session.
Providers with per-session state override on_session_reset to rebind
it cheaply (default is a no-op on the base class).
"""
for provider in self._providers:
if provider.name == "builtin":
continue
try:
if hasattr(provider, "reset_session"):
provider.reset_session(new_session_id)
else:
provider.initialize(session_id=new_session_id)
provider.on_session_reset(new_session_id)
except Exception as e:
logger.debug(
"Memory provider '%s' restart_session failed: %s",
"Memory provider '%s' on_session_reset failed: %s",
provider.name, e,
)

View File

@@ -160,6 +160,15 @@ class MemoryProvider(ABC):
(CLI exit, /reset, gateway session expiry).
"""
def on_session_reset(self, new_session_id: str) -> None:
"""Transition to a new session without full teardown.
Called after on_session_end() has committed the previous session
(e.g. /new, context compression). Providers with per-session state
override to rebind counters/IDs while keeping HTTP clients alive.
Default: no-op.
"""
def on_pre_compress(self, messages: List[Dict[str, Any]]) -> str:
"""Called before context compression discards old messages.