fix: persist ACP sessions to SessionDB so they survive process restarts
* fix: persist ACP sessions to disk so they survive process restarts The ACP adapter stored sessions entirely in-memory. When the editor restarted the ACP subprocess (idle timeout, crash, system sleep/wake, editor restart), all sessions were lost. The editor's load_session / resume_session calls would fail to find the session, forcing a new empty session and losing all conversation history. Changes: - SessionManager now persists each session as a JSON file under ~/.hermes/acp_sessions/<session_id>.json - get_session() transparently restores from disk when not in memory - update_cwd(), fork_session(), list_sessions() all check disk - server.py calls save_session() after prompt completion, /reset, /compact, and model switches - cleanup() and remove_session() delete disk files too - Sessions have a 7-day TTL; expired sessions are pruned on startup - Atomic writes via tempfile + os.replace to prevent corruption - 11 new tests covering persistence, disk restoration, and TTL expiry * refactor: use SessionDB instead of JSON files for ACP session persistence Replace the standalone JSON file persistence layer with SessionDB (~/.hermes/state.db) integration. ACP sessions now: - Share the same DB as CLI and gateway sessions - Are searchable via session_search (FTS5) - Get token tracking, cost tracking, and session titles for free - Follow existing session pruning policies Key changes: - _get_db() lazily creates a SessionDB, resolving HERMES_HOME dynamically (not at import time) for test compatibility - _persist() creates session record + replaces messages in DB - _restore() loads from DB with source='acp' filter - cwd stored in model_config JSON field (no schema migration) - Model values coerced to str to handle mock agents in tests - Removed: json files, sessions_dir, ttl_days, _expire logic - Tests updated: DB-backed persistence, FTS search, tool_call round-tripping, source filtering --------- Co-authored-by: Test <test@test.com>
This commit is contained in:
parent
bb59057d5d
commit
388130a122
3 changed files with 438 additions and 35 deletions
|
|
@ -304,6 +304,8 @@ class HermesACPAgent(acp.Agent):
|
|||
|
||||
if result.get("messages"):
|
||||
state.history = result["messages"]
|
||||
# Persist updated history so sessions survive process restarts.
|
||||
self.session_manager.save_session(session_id)
|
||||
|
||||
final_response = result.get("final_response", "")
|
||||
if final_response and conn:
|
||||
|
|
@ -400,6 +402,7 @@ class HermesACPAgent(acp.Agent):
|
|||
cwd=state.cwd,
|
||||
model=new_model,
|
||||
)
|
||||
self.session_manager.save_session(state.session_id)
|
||||
provider_label = target_provider or getattr(state.agent, "provider", "auto")
|
||||
logger.info("Session %s: model switched to %s", state.session_id, new_model)
|
||||
return f"Model switched to: {new_model}\nProvider: {provider_label}"
|
||||
|
|
@ -444,6 +447,7 @@ class HermesACPAgent(acp.Agent):
|
|||
|
||||
def _cmd_reset(self, args: str, state: SessionState) -> str:
|
||||
state.history.clear()
|
||||
self.session_manager.save_session(state.session_id)
|
||||
return "Conversation history cleared."
|
||||
|
||||
def _cmd_compact(self, args: str, state: SessionState) -> str:
|
||||
|
|
@ -453,6 +457,7 @@ class HermesACPAgent(acp.Agent):
|
|||
agent = state.agent
|
||||
if hasattr(agent, "compress_context"):
|
||||
agent.compress_context(state.history)
|
||||
self.session_manager.save_session(state.session_id)
|
||||
return f"Context compressed. Messages: {len(state.history)}"
|
||||
return "Context compression not available for this agent."
|
||||
except Exception as e:
|
||||
|
|
@ -475,5 +480,6 @@ class HermesACPAgent(acp.Agent):
|
|||
cwd=state.cwd,
|
||||
model=model_id,
|
||||
)
|
||||
self.session_manager.save_session(session_id)
|
||||
logger.info("Session %s: model switched to %s", session_id, model_id)
|
||||
return None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue