homelab-brain/infrastructure/OPENMEMORY.md

3.9 KiB

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:876510.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 TypeErrorget_all/list_memories crasht komplett.
    • Zusaetzlich verlangt das Pydantic-Modell MemoryItem Strings fuer hash/created_atValidationError 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.mainmem0.llm.config.max_tokens 20008000. 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.