"""OpenMemory REST-Client (CT 122). Nutzt die REST-API von OpenMemory (mem0/Qdrant) für langfristige User-Memories. Ergänzt den Memory-Service (CT 117) um semantische/langfristige Erinnerungen. """ import logging from typing import Optional import requests from core import config log = logging.getLogger("openmemory_client") _cfg = None _base_url = None _user_id = None def _ensure_config(): global _cfg, _base_url, _user_id if _base_url is not None: return _cfg = config.parse_config() _base_url = (_cfg.raw.get("OPENMEMORY_API_URL") or "http://10.10.10.122:8765").rstrip("/") _user_id = _cfg.raw.get("OPENMEMORY_USER_ID") or "orbitalo" if not _base_url: log.warning("OPENMEMORY_API_URL nicht in homelab.conf") def search(query: str, limit: int = 10) -> list[dict]: """Sucht Memories per Text (GET mit search_query). Liefert Liste von {content, id, ...}.""" _ensure_config() if not _base_url: return [] try: r = requests.get( f"{_base_url}/api/v1/memories/", params={"user_id": _user_id, "search_query": query, "size": limit}, timeout=5, ) if r.ok: data = r.json() items = data.get("items", []) return [{"content": i.get("content", ""), "id": str(i.get("id", ""))} for i in items] log.debug("OpenMemory search %s: %s", r.status_code, r.text[:150]) except Exception as e: log.debug("OpenMemory search: %s", e) return [] def add(text: str, app: str = "hausmeister") -> Optional[dict]: """Fügt eine neue Memory hinzu. Gibt {id, ...} oder None zurück.""" _ensure_config() if not _base_url or not text.strip(): return None try: r = requests.post( f"{_base_url}/api/v1/memories/", json={"user_id": _user_id, "text": text.strip(), "metadata": {}, "infer": True, "app": app}, timeout=10, ) if r.ok: return r.json() log.warning("OpenMemory add %s: %s", r.status_code, r.text[:200]) except Exception as e: log.warning("OpenMemory add: %s", e) return None def list_memories(limit: int = 15) -> list[dict]: """Listet die neuesten Memories (ohne semantische Suche).""" _ensure_config() if not _base_url: return [] try: r = requests.get( f"{_base_url}/api/v1/memories/", params={"user_id": _user_id, "page": 1, "size": limit}, timeout=5, ) if r.ok: data = r.json() items = data.get("items", []) return [{"content": i.get("content", ""), "id": str(i.get("id", ""))} for i in items] except Exception as e: log.debug("OpenMemory list: %s", e) return [] def get_openmemory_for_prompt(query: str, top_k: int = 8) -> str: """Holt OpenMemory-Ergebnisse und formatiert sie für den System-Prompt.""" items = search(query, limit=top_k) if not items: items = list_memories(limit=5) if not items: return "" lines = ["", "=== OPENMEMORY (langfristige Erinnerungen) ==="] for item in items: c = (item.get("content") or "").strip() if c: lines.append(f"• {c}") lines.append("=== ENDE OPENMEMORY ===") return "\n".join(lines)