From 3facb6c3ad1d5a90c8cd0d3a9653b939f3675894 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Wed, 24 Jun 2026 17:25:52 +0200 Subject: [PATCH] feat(v9): Phase 7 (Hermes 4 14B) live + Phase 9 proaktives Memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Phase 7: model.default = Hermes-4-14B (Q6_K, llama-swap-Alias hermes, --jinja), verifiziert (sauberer Tool-Call). A/B vs Qwen3-Coder umschaltbar. - Phase 9: mcp_memory.py Tool-Beschreibungen auf proaktives Protokoll (get→Session-Start, add→proaktiv+dedup, search→vor add) → geteiltes MC-SQLite waechst autonom aus allen Tool-Sessions mit. - Docs: Memory-Architektur (2 komplementaere Schichten) festgeschrieben. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 4 +++- ROADMAP.md | 3 ++- mcp_memory.py | 17 +++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 37ef268..76692b0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -130,7 +130,9 @@ Oder über den Self-Update-Button in Mission Control (empfohlen). **v8.1 (Bug-Fix)**: system_status-Keys, Model-Routing, asyncio, sudo-PW für Engine-Update, Chat-History in sessionStorage. **v8.2 (UX)**: Guide-Tabs + Begriffe oben, Mobile Bottom-Nav (≤520px), Download-Links, ConnectPanel-Fixes. **v8.3 (Memory Import)**: Import aus Cloud-KIs (Claude/Gemini/ChatGPT) — zeilenweiser Batch-POST. -**v9 (Hermes-Agent-Adoption, Entscheidung 2026-06-23)**: Eigenbau-Agent → Nous Hermes-Agent-Framework (MIT). MC wird Control-Plane. Eigenes Memory bleibt via MCP erhalten. Phasen 0–3 live (harter Cutover: `hermes_agent.py` entfernt) **+ Phase 4**: Agent-**Cockpit** (Status/Cron/Skills) via `hermes_control.py` **+ Phase 5 (Kurswechsel)**: Eigenbau-Chat ersetzt durch das **eingebettete Hermes-Web-Dashboard** (`hermes-dashboard`-Dienst :9119, MC-Reverse-Proxy `/hermes-ui/`, iframe). Offen: Phase 6 (volle lokale Rechte), Phase 7 (Agent-Modell Hermes 4 14B), Phase 8 (insights/Memory im Cockpit), Self-Update für `hermes-gateway`+`hermes-dashboard`. Siehe ROADMAP v9. +**v9 (Hermes-Agent-Adoption, Entscheidung 2026-06-23)**: Eigenbau-Agent → Nous Hermes-Agent-Framework (MIT). MC wird Control-Plane. Eigenes Memory bleibt via MCP erhalten. Phasen 0–3 live (harter Cutover: `hermes_agent.py` entfernt) **+ Phase 4**: Agent-**Cockpit** (Status/Cron/Skills) **+ Phase 5 (Kurswechsel)**: Eigenbau-Chat ersetzt durch das **eingebettete Hermes-Web-Dashboard** (`hermes-dashboard`-Dienst :9119, MC-Reverse-Proxy `/hermes-ui/`, iframe) **+ Phase 6**: volle lokale Rechte (`approvals.mode:auto`, `hooks_auto_accept`, `subagent_auto_approve`) **+ Phase 7**: Agent-Modell **Hermes 4 14B Q6_K** (llama-swap-Alias `hermes`, `--jinja`) **+ Phase 8**: Cockpit zeigt Lernen (`USER.md`) + Aktivität (`hermes insights`) **+ Phase 9**: `mcp_memory.py`-Tool-Beschreibungen proaktiv → geteiltes Memory wächst autonom mit. Offen: Kurator/Dedup fürs MC-SQLite, Self-Update für `hermes-gateway`+`hermes-dashboard`. Siehe ROADMAP v9. + +**Memory-Architektur (entschieden 2026-06-24):** Zwei komplementäre Schichten, keine Doppelung-Panik. **MC-SQLite (via MCP) = geteilte „Verfassung"** für ALLE Tools (Hermes, Cline, OpenCode, Zed) — kuratierbare, deterministische Fakten/Regeln; wächst autonom durch proaktives `add_memory`. **Hermes-nativ (`~/.hermes/memories/USER.md` + `state.db` FTS5) = Hermes' privates Profil-/Gesprächsgedächtnis** (nur Hermes). Linie: „soll das jedes Tool wissen?" → MC-SQLite; „Hermes' Eindruck/Gesprächsfaden" → nativ. Dokumenten-„Second Brain" (Obsidian/RAG) ist davon getrennt und nur bei Bedarf zu bauen. Offene v8-Einrichtungsschritte (kein Code, nur Setup): - Piper Binary + Kerstin-Stimme installieren (Befehle im Hermes-Tab → ⚙ Setup) diff --git a/ROADMAP.md b/ROADMAP.md index f540aac..8c694a0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -26,7 +26,8 @@ - [x] **Memory-Feintuning (✅ 2026-06-23):** `~/.hermes/SOUL.md` (Persona, frisch je Nachricht geladen) instruiert Hermes, das MCP-Gedächtnis bei Nutzer-/Projektfragen **proaktiv** via `get_memories` zu konsultieren, bevor er nachfragt — Name/Profil bleiben im Gedächtnis (nicht hart in SOUL.md). Verifiziert: weicher Prompt „nenne meinen Namen" → „Hallo Tobi!". **Hinweis:** SOUL.md liegt auf dem Bosgame (`~/.hermes/`), nicht im Repo — bei Neuaufsetzen mitschreiben. - [x] **Phase 5 — UI-Adoption (✅ 2026-06-24, Kurswechsel):** Statt Eigenbau-Chat das **mitgelieferte Hermes-Web-Dashboard** einbetten (Chat mit Live-Tool-Aktivität, Approval-Prompts, Settings, Sessions). Dashboard läuft als systemd-User-Dienst `hermes-dashboard` (`hermes dashboard --host 127.0.0.1 --port 9119 --skip-build`, Extras `[web,pty]`); MC reverse-proxyt es unter `/hermes-ui/` (`routers/hermes_ui.py`, HTTP + WS-Bridge für `pty/ws`) mit `X-Forwarded-Prefix` → Dashboard rewritet Assets/Base-Path selbst und injiziert seinen Session-Token (kein zweiter Login). HermesPanel: Chat → iframe; Eigenbau-Chat/Voice/`_proxy_chat` entfernt. **Damit gelöst:** Kontextverlust + „lernt nicht" (UI spricht direkt mit dem Agent-Loop, kein Proxy-Bug) und Tool-Sichtbarkeit. Verifiziert: HTTP-Kette (Asset-Rewrite, 1,9-MB-Bundle) + Chat-WS `/api/ws` durch MC identisch zu direkt. - [x] **Phase 6 — Rechte & Multi-Agent (✅ 2026-06-24):** „lokal = volle Rechte" via `hermes config set`: `approvals.mode: auto`, `approvals.cron_mode: allow`, `hooks_auto_accept: true`, `delegation.subagent_auto_approve: true`. Tirith/`allow_private_urls:false` bleiben an (Injection-Schutz). Verifiziert: Agent legt über die API autonom eine Datei an (Schreibrechte ohne manuelle Freigabe). Multi-Agent damit entsperrt. -- [~] **Phase 7 — Agent-Modell Hermes 4 14B (in Arbeit 2026-06-24):** GGUF `bartowski/NousResearch_Hermes-4-14B-GGUF` **Q6_K** (~12 GB, M5 hat RAM satt) → `/srv/models/Hermes-4-14B-GGUF/`. llama-swap-Eintrag `Hermes-4-14B` (Alias `hermes`, `--jinja`, `-c 65536`) angelegt (Backup `config.yaml.bak-pre-hermes4`). **Offen:** nach Download `hermes config set model.default hermes` + Gateway-Restart + Tool-Call-Verifikation (A/B gegen Qwen3-Coder). +- [x] **Phase 7 — Agent-Modell Hermes 4 14B (✅ 2026-06-24):** GGUF `bartowski/NousResearch_Hermes-4-14B-GGUF` **Q6_K** (~12 GB) → `/srv/models/Hermes-4-14B-GGUF/`. llama-swap-Eintrag `Hermes-4-14B` (Alias `hermes`, `--jinja`, `-c 65536`, Backup `config.yaml.bak-pre-hermes4`). `hermes config set model.default Hermes-4-14B` + Gateway-Restart. **Verifiziert:** llama-swap lädt das Modell (`state: ready`), Agent macht sauberen Tool-Call (kein ``-Leak, RAM via Terminal abgefragt). Kaltstart-Load ~3,5 min, dann ttl 1800 s. A/B gegen Qwen3-Coder jederzeit per `model.default` umschaltbar. +- [ ] **Phase 9 — Gedächtnis wächst autonom (✅ Stupser 2026-06-24, Kurator offen):** Tool-Beschreibungen in `mcp_memory.py` auf ein **proaktives Protokoll** umgeschrieben (get→Session-Start laden, add→proaktiv bei dauerhaften Fakten, vorher search/dedup) → schlägt auf **alle** Tools (Hermes + IDE-Tools) durch, das geteilte MC-SQLite wächst aus Vibe-Coding-Sessions mit. **Offen:** leichter Kurator/Dedup-Lauf fürs MC-SQLite (Hermes hat einen für sein eigenes Memory, MC-SQLite noch nicht). - [x] **Phase 8 — Cockpit-Ausbau (✅ 2026-06-24):** Cockpit zeigt jetzt **Aktivität** (`hermes insights`: Sessions/Nachrichten/Tool-Calls/Tokens/aktiv + Top-Tool-Balken) und **„Was Hermes über dich gelernt hat"** (`USER.md`-Profil, `§`-getrennt + `MEMORY.md`). Reads in `hermes_control.py` (`learned_profile`, `insights`), Endpunkte `/api/hermes/{learned,insights}`. Beantwortet sichtbar „lernt er mit?" — ja (7 Profil-Fakten, 262 Tool-Calls/30 T verifiziert). **Entscheidungen (gesetzt):** Memory via MCP einbinden (nicht migrieren) · **Kurswechsel 2026-06-24: mitgeliefertes Hermes-Web-Dashboard per iframe einbetten** (ersetzt Eigenbau-Chat; der alte „nicht hermes-webui"-Entscheid ist überholt — die UI ist offiziell, mit dem Install versioniert und auf genau dieses Ziel gebaut) · Agent-Modell **Hermes 4 14B** · stabiler OpenAI-API-Server bleibt für programmatischen Zugriff. diff --git a/mcp_memory.py b/mcp_memory.py index 929366c..e8d41ae 100644 --- a/mcp_memory.py +++ b/mcp_memory.py @@ -54,7 +54,10 @@ def _delete(path: str) -> dict: @mcp.tool() def get_memories(category: str = "") -> str: - """Laedt gespeicherte Fakten und Entscheidungen. category: stable | versioned | ephemeral | (leer = alle)""" + """Laedt gespeicherte Fakten und Entscheidungen aus dem geteilten Gedaechtnis. + RUFE DAS ZU BEGINN JEDER SESSION AUF, um vorhandenen Kontext (Konventionen, + Entscheidungen, Nutzer-Praeferenzen) zu laden, BEVOR du handelst oder nachfragst. + category: user | instruction | stable | versioned | ephemeral | (leer = alle)""" params = {"category": category} if category else {} items = _get("/api/memory", **params) if not items: @@ -69,8 +72,13 @@ def get_memories(category: str = "") -> str: @mcp.tool() def add_memory(content: str, category: str = "stable", source: str = "agent") -> str: - """Speichert einen Fakt oder eine Entscheidung. - category: user=Fakten ueber den User (Praeferenzen/Arbeitsweise), instruction=Verhaltensregeln fuer alle Tools, stable=Projektfakten, versioned=Tech-Versionen, ephemeral=temporaer (7 Tage). + """Speichert einen Fakt/eine Entscheidung dauerhaft im GETEILTEN Gedaechtnis (alle Tools sehen es). + RUFE DAS PROAKTIV AUF, sobald waehrend der Arbeit etwas Dauerhaftes entsteht — eine + Konvention, Architektur-Entscheidung, Tech-Version, Nutzer-Praeferenz oder ein Projektfakt. + Warte NICHT, bis man dich bittet. + Mache VORHER `search_memories` mit Stichworten, um Dubletten zu vermeiden; existiert ein + passender Eintrag, nutze `update_memory` statt neu anzulegen. Halte Eintraege knapp & atomar. + category: user=Fakten ueber den User (Praeferenzen/Arbeitsweise), instruction=Verhaltensregeln fuer alle Tools, stable=Projektfakten, versioned=Tech-Versionen, ephemeral=temporaer/Session-Notiz (7 Tage, dann weg). """ m = _post("/api/memory", {"content": content, "category": category, "source": source}) return f"Gespeichert (ID: {m['id'][:8]}): {content}" @@ -78,7 +86,8 @@ def add_memory(content: str, category: str = "stable", source: str = "agent") -> @mcp.tool() def search_memories(q: str) -> str: - """Sucht per Stichwort in allen gespeicherten Fakten.""" + """Sucht per Stichwort in allen gespeicherten Fakten. Nutze das VOR `add_memory` + (Dubletten-Check) und immer dann, wenn du fruehere Entscheidungen/Kontext brauchst.""" items = _get("/api/memory", q=q) if not items: return f"Keine Treffer fuer '{q}'."