feat(v9): Phase 7 (Hermes 4 14B) live + Phase 9 proaktives Memory
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
+2
-1
@@ -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 `<function>`-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.
|
||||
|
||||
+13
-4
@@ -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}'."
|
||||
|
||||
Reference in New Issue
Block a user