From 5c3f50dfa5c3394103a5c1b9d7882cd5a78e9342 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Sat, 27 Jun 2026 20:12:13 +0200 Subject: [PATCH] Fix: mc2-memory Provider flusht offene Turns bei Session-Ende shutdown() + on_session_end() schreiben verbliebene Queue-Eintraege synchron raus (_flush), damit kurzlebige Prozesse den Hintergrund-Worker nicht mitten im /learn-POST killen. Live verifiziert: hands-off Auto-Lernen via Gateway (source=hermes) + Recall. Co-Authored-By: Claude Opus 4.8 --- hermes/plugins/mc2-memory/__init__.py | 33 ++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/hermes/plugins/mc2-memory/__init__.py b/hermes/plugins/mc2-memory/__init__.py index efe034d..e3ee492 100644 --- a/hermes/plugins/mc2-memory/__init__.py +++ b/hermes/plugins/mc2-memory/__init__.py @@ -25,6 +25,7 @@ import logging import os import queue import threading +import time from typing import Any, Dict, List, Optional import httpx @@ -128,6 +129,14 @@ class MC2MemoryProvider(MemoryProvider): # Neue Fakten können gelandet sein → Recall-Cache invalidieren. self._recall_cache.clear() + def _post_learn(self, msgs: list) -> None: + try: + httpx.post(f"{MC_URL}/api/memory/learn", + json={"messages": msgs, "source": "hermes"}, + headers=_headers(), timeout=90.0) + except Exception as exc: + log.debug("mc2-memory learn POST failed: %s", exc) + def _run(self) -> None: while not self._stop.is_set(): try: @@ -135,20 +144,32 @@ class MC2MemoryProvider(MemoryProvider): except queue.Empty: continue try: - httpx.post(f"{MC_URL}/api/memory/learn", - json={"messages": msgs, "source": "hermes"}, - headers=_headers(), timeout=120.0) - except Exception as exc: - log.debug("mc2-memory learn POST failed: %s", exc) + self._post_learn(msgs) finally: self._q.task_done() + def _flush(self) -> None: + """Offene Turns garantiert rausschreiben — bei Session-Ende/CLI-Exit, wo der + Prozess sofort beendet wird (daemon-Worker würde sonst mitten im POST sterben).""" + self._stop.set() + if self._worker and self._worker.is_alive(): + self._worker.join(timeout=95.0) # laufenden Worker-POST zu Ende lassen + while True: # vom Worker nicht mehr abgeholte Turns + try: + msgs = self._q.get_nowait() + except queue.Empty: + break + self._post_learn(msgs) + # -- Context-only: keine Agent-Tools → kein Tool-Loop -------------------- def get_tool_schemas(self) -> List[Dict[str, Any]]: return [] + def on_session_end(self, messages: List[Dict[str, Any]]) -> None: + self._flush() + def shutdown(self) -> None: - self._stop.set() + self._flush() def register(ctx) -> None: