Feat: Hermes-Terminal (ttyd) statt AnythingLLM + AnythingLLM komplett raus

Paket B des Plans. AnythingLLM war nur ein Fallback-Chat zu Hermes; ersetzt durch das
echte interaktive Agent-Terminal (`hermes chat`, mit Tools/PC) als eingebettetes
Web-Terminal.

Box: ttyd (apt) wrappt `hermes chat`; systemd-User-Unit deploy/hermes-terminal.service
(LAN-Bind eno1:7681, apt-Default-ttyd-Dienst deaktiviert). In deploy.sh verankert.

Backend: config HERMES_TERMINAL_URL statt ANYTHINGLLM_URL/_REPO; agent_status liefert
terminal_url/terminal_reachable; maintenance ohne _anythingllm_update; system.py Dienst-Liste
zeigt "Hermes-Terminal".

Frontend: neue Terminal-Seite (iframe auf ttyd) + Nav-Tab; AgentView/AgentStatusCard/nav/api
auf Terminal umgestellt; SystemDrawer toter hermes-dashboard raus, hermes-webui -> hermes-terminal;
Guide-Texte aktualisiert.

Cleanup: deploy/hermes-webui.service + deploy/lobechat/ entfernt (LobeChat-Migration hinfaellig),
HERMES_WEBUI_URL-Env raus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-27 18:23:37 +02:00
parent cf65589b93
commit dcfede7e69
23 changed files with 246 additions and 281 deletions
+5 -6
View File
@@ -53,14 +53,13 @@ HF_DOWNLOAD_ENV = {"HF_HUB_DISABLE_XET": "1"}
GATEWAY_URL = os.environ.get("MC_GATEWAY_URL", f"http://127.0.0.1:{os.environ.get('MC_PORT', '9000')}").rstrip("/")
# --- Hermes Agent (eigener Dienst auf der Box) -------------------------------
# Gateway (OpenAI-API des Agenten) + Chat-WebUI = AnythingLLM (eigener Host).
# Gateway (OpenAI-API des Agenten) + interaktives Web-Terminal (ttyd → `hermes chat`).
HERMES_API_URL = os.environ.get("HERMES_API_URL", "http://127.0.0.1:8642").rstrip("/")
HERMES_WEBUI_URL = os.environ.get("HERMES_WEBUI_URL", "http://127.0.0.1:8787").rstrip("/")
# AnythingLLM = die Chat-WebUI (löst nesquena/hermes-webui ab). Eigener Host im LAN.
ANYTHINGLLM_URL = os.environ.get("MC_ANYTHINGLLM_URL", "http://192.168.178.155:3001").rstrip("/")
# GitHub-Repos für Update-Checks.
# Hermes-Terminal: ttyd-Web-Terminal der interaktiven Agent-CLI (Ersatz für AnythingLLM-Chat).
# Wird in MC2 per iframe eingebettet (Terminal-Seite). Siehe deploy/hermes-terminal.service.
HERMES_TERMINAL_URL = os.environ.get("MC_HERMES_TERMINAL_URL", "http://192.168.178.151:7681").rstrip("/")
# GitHub-Repo für Update-Checks.
HERMES_AGENT_REPO = os.environ.get("MC_HERMES_AGENT_REPO", "NousResearch/hermes-agent")
ANYTHINGLLM_REPO = os.environ.get("MC_ANYTHINGLLM_REPO", "Mintplex-Labs/anything-llm")
HERMES_HOME = Path(os.path.expanduser(os.environ.get("HERMES_HOME", "~/.hermes")))
# PC Executor — läuft auf dem Windows-PC, erreichbar über LAN.
PC_EXECUTOR_URL = os.environ.get("MC_PC_EXECUTOR_URL", "http://192.168.178.98:7777").rstrip("/")
+2 -2
View File
@@ -46,12 +46,12 @@ def services() -> dict:
{"name": "Engine (llama-swap)", "url": LLAMA_SWAP_URL, "ok": engine_reachable()},
{"name": "Gateway (integriert)", "url": gw_url, "ok": gateway_reachable()},
{"name": "Hermes-Gateway", "url": HERMES_API_URL, "ok": a["gateway_reachable"]},
{"name": "AnythingLLM", "url": a["webui_url"], "ok": a["webui_reachable"]},
{"name": "Hermes-Terminal", "url": a["terminal_url"], "ok": a["terminal_reachable"]},
],
"links": {
"engine_ui": f"{LLAMA_SWAP_URL}/ui",
"gateway": gw_url,
"hermes_webui": a["webui_url"],
"hermes_terminal": a["terminal_url"],
},
}
+4 -4
View File
@@ -11,7 +11,7 @@ import re
import httpx
import psutil
from config import ANYTHINGLLM_URL, HERMES_API_URL, HERMES_HOME, PC_EXECUTOR_URL
from config import HERMES_TERMINAL_URL, HERMES_API_URL, HERMES_HOME, PC_EXECUTOR_URL
log = logging.getLogger(__name__)
@@ -162,10 +162,10 @@ def agent_status() -> dict:
return {
"gateway_url": HERMES_API_URL,
# Chat-WebUI ist jetzt AnythingLLM (eigener Host), nicht mehr hermes-webui :8787.
"webui_url": ANYTHINGLLM_URL,
# Interaktives Web-Terminal (ttyd → `hermes chat`), eingebettet in MC2.
"terminal_url": HERMES_TERMINAL_URL,
"gateway_reachable": _reach(HERMES_API_URL, "/health"),
"webui_reachable": _reach(ANYTHINGLLM_URL, "/api/ping"),
"terminal_reachable": _reach(HERMES_TERMINAL_URL, "/"),
"home_exists": home.exists(),
"brain_model": brain_model,
# Best-effort: welche Verdrahtung lokal sichtbar ist (auf der Box aussagekräftig).
+3 -19
View File
@@ -15,7 +15,7 @@ from datetime import datetime
import httpx
import psutil
from config import ANYTHINGLLM_REPO, ANYTHINGLLM_URL, HERMES_AGENT_REPO
from config import HERMES_AGENT_REPO
from services import catalog, discover, jobengine, llamaswap, system
# System-Dienste (root, via sudo -n NOPASSWD) vs. User-Dienste (systemctl --user).
@@ -128,28 +128,12 @@ def _hermes_agent_update() -> dict:
return info
def _anythingllm_update() -> dict:
"""AnythingLLM: erreichbar? + neueste verfügbare Version. Installierte Version ist
remote nicht unauth. abfragbar → update=None (nur Info: neueste verfügbar)."""
reachable = False
try:
reachable = httpx.get(f"{ANYTHINGLLM_URL}/api/ping", timeout=4).status_code == 200
except Exception:
reachable = False
info = {"key": "anythingllm", "name": "AnythingLLM", "current": None,
"latest": None, "update": None, "reachable": reachable}
gh = _gh_latest(ANYTHINGLLM_REPO)
if gh:
info["latest"] = gh["tag"]
return info
def _components_cached() -> list[dict]:
"""Update-Status von Hermes-Agent + AnythingLLM (1h-Cache → GitHub schonen)."""
"""Update-Status von Hermes-Agent (1h-Cache → GitHub schonen)."""
now = time.time()
if now - _comp_cache["ts"] < 3600 and _comp_cache["data"]:
return _comp_cache["data"]
data = [_hermes_agent_update(), _anythingllm_update()]
data = [_hermes_agent_update()]
_comp_cache.update(ts=now, data=data)
return data