fix+docs: Bug-Fixes, vollstaendige Dokumentation v8

Bug-Fixes:
- hermes_agent.py: asyncio.get_event_loop() → get_running_loop() (Python 3.10+)
- routers/hermes.py: Thread-Lock fuer Whisper-Init, HERMES_WINDOWS_USER Import,
  Piper stderr logging, __import__ Anti-Pattern entfernt
- routers/memory.py: SQLite WAL-Mode, Kategorie-Enum-Validierung (user/instruction/stable/versioned/ephemeral)
- HermesPanel.svelte: findLast() → reverse().find() (Browser-Kompatibilitaet)
- ConnectPanel.svelte: Hardcoded Username durch Platzhalter ersetzt

Docs:
- CLAUDE.md: komplett aktualisiert (v7+v8, Hermes, Memory, alle Env-Vars)
- ROADMAP.md: v7+v8 als erledigt, naechste Features (v8.1-v9.1)
- README.md: komplett neu geschrieben (Agentic OS Konzept, alle Features)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-23 14:48:22 +02:00
parent 5881a21d9a
commit 8539999627
9 changed files with 269 additions and 313 deletions
+18 -11
View File
@@ -14,6 +14,7 @@ import hashlib
import json
import subprocess
import tempfile
import threading
from pathlib import Path
from typing import Optional
@@ -23,7 +24,7 @@ from fastapi.responses import Response, JSONResponse
from auth import auth
from config import (
PIPER_BIN, PIPER_VOICE, WHISPER_MODEL_SIZE,
HERMES_WINDOWS_HOST, HERMES_SSH_KEY,
HERMES_WINDOWS_HOST, HERMES_WINDOWS_USER, HERMES_SSH_KEY,
)
from hermes_agent import run_agent
@@ -35,23 +36,28 @@ router = APIRouter(prefix="/api")
_whisper_model = None
_whisper_loading = False
_whisper_lock = threading.Lock()
def _get_whisper():
global _whisper_model, _whisper_loading
if _whisper_model is not None:
return _whisper_model
if _whisper_loading:
return None
_whisper_loading = True
with _whisper_lock:
if _whisper_model is not None:
return _whisper_model
if _whisper_loading:
return None
_whisper_loading = True
try:
from faster_whisper import WhisperModel
_whisper_model = WhisperModel(WHISPER_MODEL_SIZE, device="cpu", compute_type="int8")
model = WhisperModel(WHISPER_MODEL_SIZE, device="cpu", compute_type="int8")
with _whisper_lock:
_whisper_model = model
return model
except Exception:
_whisper_model = None
return None
finally:
_whisper_loading = False
return _whisper_model
with _whisper_lock:
_whisper_loading = False
# ---------------------------------------------------------------------------
@@ -75,6 +81,7 @@ def _tts(text: str) -> Optional[bytes]:
input=text, capture_output=True, text=True, timeout=30
)
if result.returncode != 0:
print(f"[Piper] Fehler: {result.stderr or 'exit '+str(result.returncode)}")
return None
audio = Path(wav_path).read_bytes()
if len(_tts_cache) >= 64:
@@ -190,7 +197,7 @@ def hermes_status():
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(
HERMES_WINDOWS_HOST,
username=__import__("config").HERMES_WINDOWS_USER,
username=HERMES_WINDOWS_USER,
key_filename=str(HERMES_SSH_KEY),
timeout=3,
)
+12 -2
View File
@@ -9,6 +9,7 @@ Alle MCP-Tools teilen denselben Speicher via mcp_memory.py-Wrapper.
import sqlite3
import uuid
from datetime import datetime, timezone
from enum import Enum
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
@@ -28,6 +29,7 @@ def _db() -> sqlite3.Connection:
MEMORY_DB.parent.mkdir(parents=True, exist_ok=True)
_db_conn = sqlite3.connect(str(MEMORY_DB), check_same_thread=False)
_db_conn.row_factory = sqlite3.Row
_db_conn.execute("PRAGMA journal_mode=WAL") # sicherer bei concurrent FastAPI-Threads
_db_conn.execute("""
CREATE TABLE IF NOT EXISTS memories (
id TEXT PRIMARY KEY,
@@ -47,15 +49,23 @@ def _db() -> sqlite3.Connection:
return _db_conn
class _MemCategory(str, Enum):
user = "user"
instruction = "instruction"
stable = "stable"
versioned = "versioned"
ephemeral = "ephemeral"
class _MemIn(BaseModel):
content: str
category: str = "stable" # stable | versioned | ephemeral
category: _MemCategory = _MemCategory.stable
source: str = "manual"
class _MemUp(BaseModel):
content: Optional[str] = None
category: Optional[str] = None
category: Optional[_MemCategory] = None
def _row(r: sqlite3.Row) -> dict: