homelab-brain/infrastructure/OPENMEMORY.md

48 lines
3.9 KiB
Markdown

# OpenMemory (mem0)
Selbst-gehosteter Memory-Store mit MCP-Schnittstelle. Wird u. a. von Cursor und Jervais/Hermes als persistentes Gedaechtnis genutzt.
## Deployment
- **Host:** CT122 auf pve-hetzner (Tailscale-Gateway `root@100.88.230.59`), interne IP `10.10.10.122`.
- **Container:** Docker Compose unter `/root/mem0/openmemory/` (`docker-compose.yml`):
- `openmemory-openmemory-mcp-1` (`mem0/openmemory-mcp`) — API/MCP auf Port `8765`, `uvicorn main:app --reload --workers 4`.
- `openmemory-mem0_store-1` (`qdrant/qdrant`) — Vektor-Store, Collection `openmemory`.
- `openmemory-openmemory-ui-1` (`mem0/openmemory-ui`) — Dashboard auf Port `3000`.
- **App-Quellcode (bind-mount):** Host `/root/mem0/openmemory/api` → Container `/usr/src/openmemory`.
- **Aktive Konfiguration:** NICHT `config.json`, sondern DB-Tabelle `configs` (key `main`) in `/usr/src/openmemory/openmemory.db`. LLM = `gpt-4o-mini` via OpenRouter (`OPENAI_BASE_URL=https://openrouter.ai/api/v1`), Embedder `text-embedding-3-small`.
- **Zugang vom Cursor-Host:** SSH-Tunnel `openmemory-tunnel.service` (autossh) leitet `localhost:8765``10.10.10.122:8765`. MCP-URL in `mcp.json`: `http://localhost:8765/mcp/cursor/sse/orbitalo`.
- **Logs:** `docker logs openmemory-openmemory-mcp-1` (json-file, keine Rotation konfiguriert).
---
# Hotfix — 2026-05-31
Behob zwei Fehlfunktionen.
## Symptome
1. `list_memories` lieferte hart: `Error getting memories: fromisoformat: argument must be str`.
2. `add_memories` mit laengeren Texten gab still `{"results": []}` zurueck (nicht gespeichert), ohne sichtbaren Client-Fehler.
## Root Causes
1. **Gemischte Timestamp-Typen in qdrant.** 274 von 663 Punkten hatten `hash` und `created_at` als **Integer** (alte Records einer frueheren mem0-Version), neuere als String/ISO.
- `mem0.memory.main._normalize_iso_timestamp_to_utc()` fing nur `ValueError`; bei int wirft `datetime.fromisoformat()` ein `TypeError``get_all`/`list_memories` crasht komplett.
- Zusaetzlich verlangt das Pydantic-Modell `MemoryItem` Strings fuer `hash`/`created_at``ValidationError` bei int.
2. **Truncation des Extraktor-LLM-JSON.** `max_tokens: 2000` zu klein; beim Update-Memory-Schritt (Prompt enthaelt alle bestehenden Memories) wurde das JSON abgeschnitten → `Invalid JSON response` → leeres `results`.
- Hinweis: Leeres `results` kann AUCH legitim sein (LLM-Dedup → `event: NONE`/`NOOP`). Nur das abgeschnittene JSON ist der Bug.
## Fixes (angewendet + verifiziert)
1. **qdrant-Daten normalisiert:** 274 Records, `hash` int→`str`, `created_at`/`updated_at` epoch-int→ISO-UTC. Backup: `api/qdrant_intfix_backup-20260531.json`.
2. **mem0-Library tolerant:** `site-packages/mem0/memory/main.py` `except ValueError:``except (ValueError, TypeError):`. Backup `.bak-tsfix-20260531` (NICHT rebuild-fest).
3. **Durabler Monkeypatch (rebuild-fest):** in `api/main.py` nach den Imports — ueberschreibt `_normalize_iso_timestamp_to_utc` so, dass Nicht-String-Werte unveraendert durchgereicht werden. Backup `api/main.py.bak-tsfix-20260531`.
4. **max_tokens erhoeht:** DB-Config `configs.main``mem0.llm.config.max_tokens` `2000``8000`. Backup `api/config_main.bak-20260531.json`.
## Verifikation
- `_normalize_iso_timestamp_to_utc(1774205916)` gibt int zurueck statt Crash; ISO weiterhin korrekt.
- `list_memories()` liefert JSON-Array (100), 0 verbleibende int-Records.
- Langer `add_memories` → gueltiges JSON, `event: ADD` (Dedup korrekt `NONE`/`NOOP`).
- Live ueber Cursor-MCP (nach Client-Reload) beide Tools ok.
## Nach Container-Rebuild beachten
- Persistent: Fix 1 (qdrant-Daten), Fix 3 (Monkeypatch in `main.py`), Fix 4 (DB-Config).
- Verloren bei Image-Rebuild: Fix 2 (site-packages) — durch Fix 3 abgedeckt.
- Container-Neustart invalidiert MCP-Sessions → Clients muessen neu initialisieren (`-32602` = request before initialization). In Cursor: MCP `openmemory` toggeln oder Fenster neu laden.