Feat: Engine-Update-Mechanismus + Update-Checks (Hermes Agent/AnythingLLM) + WebUI->AnythingLLM
- Engine-Update: deploy/update-engine.sh laedt neuesten ggml-org Vulkan-Build + restart; MC_ENGINE_UPDATE_CMD verdrahtet, engine_update_job nutzt es (Script macht Restart selbst). - Update-Checks: Hermes Agent (NousResearch/hermes-agent, Release-Datum vs. installiertes Commit) + AnythingLLM (Mintplex-Labs/anything-llm, neueste Version + /api/ping-Health), 1h-Cache. Neues Feld /api/maintenance/updates.components; UpdatesCard zeigt beide Zeilen. - WebUI -> AnythingLLM: agent_status.webui_* zeigt jetzt auf ANYTHINGLLM_URL (192.168.178.155:3001, /api/ping); alle "Hermes WebUI"-Buttons/Labels (AgentView, AgentStatusCard, nav, GuideView, Services-Liste) -> "AnythingLLM". Lokaler hermes-webui-Dienst bleibt als Service-Control im SystemDrawer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -53,9 +53,14 @@ 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("/")
|
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) -------------------------------
|
# --- Hermes Agent (eigener Dienst auf der Box) -------------------------------
|
||||||
# Gateway (OpenAI-API des Agenten) + standalone Web-UI (nesquena/hermes-webui).
|
# Gateway (OpenAI-API des Agenten) + Chat-WebUI = AnythingLLM (eigener Host).
|
||||||
HERMES_API_URL = os.environ.get("HERMES_API_URL", "http://127.0.0.1:8642").rstrip("/")
|
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("/")
|
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_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")))
|
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 — 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("/")
|
PC_EXECUTOR_URL = os.environ.get("MC_PC_EXECUTOR_URL", "http://192.168.178.98:7777").rstrip("/")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import subprocess
|
|||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from config import GATEWAY_URL, HERMES_API_URL, HERMES_WEBUI_URL, LLAMA_SWAP_URL
|
from config import GATEWAY_URL, HERMES_API_URL, LLAMA_SWAP_URL
|
||||||
from services import backup as backup_svc
|
from services import backup as backup_svc
|
||||||
from services.agent import agent_status
|
from services.agent import agent_status
|
||||||
from services.gateway import gateway_reachable
|
from services.gateway import gateway_reachable
|
||||||
@@ -46,12 +46,12 @@ def services() -> dict:
|
|||||||
{"name": "Engine (llama-swap)", "url": LLAMA_SWAP_URL, "ok": engine_reachable()},
|
{"name": "Engine (llama-swap)", "url": LLAMA_SWAP_URL, "ok": engine_reachable()},
|
||||||
{"name": "Gateway (integriert)", "url": gw_url, "ok": gateway_reachable()},
|
{"name": "Gateway (integriert)", "url": gw_url, "ok": gateway_reachable()},
|
||||||
{"name": "Hermes-Gateway", "url": HERMES_API_URL, "ok": a["gateway_reachable"]},
|
{"name": "Hermes-Gateway", "url": HERMES_API_URL, "ok": a["gateway_reachable"]},
|
||||||
{"name": "Hermes-WebUI", "url": HERMES_WEBUI_URL, "ok": a["webui_reachable"]},
|
{"name": "AnythingLLM", "url": a["webui_url"], "ok": a["webui_reachable"]},
|
||||||
],
|
],
|
||||||
"links": {
|
"links": {
|
||||||
"engine_ui": f"{LLAMA_SWAP_URL}/ui",
|
"engine_ui": f"{LLAMA_SWAP_URL}/ui",
|
||||||
"gateway": gw_url,
|
"gateway": gw_url,
|
||||||
"hermes_webui": HERMES_WEBUI_URL,
|
"hermes_webui": a["webui_url"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import os
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from config import HERMES_API_URL, HERMES_HOME, HERMES_WEBUI_URL, PC_EXECUTOR_URL
|
from config import ANYTHINGLLM_URL, HERMES_API_URL, HERMES_HOME, PC_EXECUTOR_URL
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -59,9 +59,10 @@ def agent_status() -> dict:
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"gateway_url": HERMES_API_URL,
|
"gateway_url": HERMES_API_URL,
|
||||||
"webui_url": HERMES_WEBUI_URL,
|
# Chat-WebUI ist jetzt AnythingLLM (eigener Host), nicht mehr hermes-webui :8787.
|
||||||
|
"webui_url": ANYTHINGLLM_URL,
|
||||||
"gateway_reachable": _reach(HERMES_API_URL, "/health"),
|
"gateway_reachable": _reach(HERMES_API_URL, "/health"),
|
||||||
"webui_reachable": _reach(HERMES_WEBUI_URL),
|
"webui_reachable": _reach(ANYTHINGLLM_URL, "/api/ping"),
|
||||||
"home_exists": home.exists(),
|
"home_exists": home.exists(),
|
||||||
"brain_model": brain_model,
|
"brain_model": brain_model,
|
||||||
# Best-effort: welche Verdrahtung lokal sichtbar ist (auf der Box aussagekräftig).
|
# Best-effort: welche Verdrahtung lokal sichtbar ist (auf der Box aussagekräftig).
|
||||||
|
|||||||
@@ -15,13 +15,17 @@ from datetime import datetime
|
|||||||
import httpx
|
import httpx
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
from services import discover, jobengine, llamaswap
|
from config import ANYTHINGLLM_REPO, ANYTHINGLLM_URL, HERMES_AGENT_REPO
|
||||||
|
from services import discover, jobengine, llamaswap, system
|
||||||
|
|
||||||
# System-Dienste (root, via sudo -n NOPASSWD) vs. User-Dienste (systemctl --user).
|
# System-Dienste (root, via sudo -n NOPASSWD) vs. User-Dienste (systemctl --user).
|
||||||
SYSTEM_SERVICES = {"llama-swap"}
|
SYSTEM_SERVICES = {"llama-swap"}
|
||||||
USER_SERVICES = {"mission-control-2", "hermes-gateway", "hermes-dashboard", "hermes-webui"}
|
USER_SERVICES = {"mission-control-2", "hermes-gateway", "hermes-dashboard", "hermes-webui"}
|
||||||
|
|
||||||
ENGINE_UPDATE_CMD = os.environ.get("MC_ENGINE_UPDATE_CMD", "")
|
# Engine-Update: lädt den neuesten Vulkan-Build (deploy/update-engine.sh, läuft als root).
|
||||||
|
_REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
ENGINE_UPDATE_CMD = os.environ.get(
|
||||||
|
"MC_ENGINE_UPDATE_CMD", f"sudo bash {_REPO_ROOT}/deploy/update-engine.sh")
|
||||||
# Engine = offizieller Vulkan-Build von ggml-org/llama.cpp (RADV auf Strix Halo).
|
# Engine = offizieller Vulkan-Build von ggml-org/llama.cpp (RADV auf Strix Halo).
|
||||||
ENGINE_PATH = os.environ.get("MC_ENGINE_PATH", "/opt/llamacpp-vulkan")
|
ENGINE_PATH = os.environ.get("MC_ENGINE_PATH", "/opt/llamacpp-vulkan")
|
||||||
ENGINE_REPO = os.environ.get("MC_ENGINE_REPO", "ggml-org/llama.cpp")
|
ENGINE_REPO = os.environ.get("MC_ENGINE_REPO", "ggml-org/llama.cpp")
|
||||||
@@ -82,6 +86,74 @@ def _engine_update_available() -> bool:
|
|||||||
return avail
|
return avail
|
||||||
|
|
||||||
|
|
||||||
|
_comp_cache = {"ts": 0.0, "data": []}
|
||||||
|
|
||||||
|
|
||||||
|
def _gh_latest(repo: str) -> dict | None:
|
||||||
|
"""Neuestes GitHub-Release {tag, published} oder None."""
|
||||||
|
try:
|
||||||
|
rel = httpx.get(f"https://api.github.com/repos/{repo}/releases/latest",
|
||||||
|
timeout=6, headers={"User-Agent": "MissionControl2"}).json()
|
||||||
|
return {"tag": str(rel.get("tag_name", "")), "published": rel.get("published_at")}
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _commit_ts(path: str) -> int | None:
|
||||||
|
try:
|
||||||
|
p = subprocess.run(["git", "-C", os.path.expanduser(path), "log", "-1", "--format=%ct"],
|
||||||
|
capture_output=True, text=True, timeout=8)
|
||||||
|
return int(p.stdout.strip()) if p.returncode == 0 and p.stdout.strip() else None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _hermes_agent_update() -> dict:
|
||||||
|
"""Hermes-Agent: neuestes Release vs. installiertes git-Commit-Datum."""
|
||||||
|
info = {"key": "hermes_agent", "name": "Hermes Agent", "current": None,
|
||||||
|
"latest": None, "update": False, "reachable": None}
|
||||||
|
git = system.find_hermes_agent_git()
|
||||||
|
if git:
|
||||||
|
info["current"] = git.get("hash")
|
||||||
|
gh = _gh_latest(HERMES_AGENT_REPO)
|
||||||
|
if gh:
|
||||||
|
info["latest"] = gh["tag"]
|
||||||
|
ts = _commit_ts(git["path"]) if (git and git.get("path")) else None
|
||||||
|
if gh["published"] and ts:
|
||||||
|
try:
|
||||||
|
pub = datetime.fromisoformat(gh["published"].replace("Z", "+00:00")).timestamp()
|
||||||
|
info["update"] = pub > ts + 86400 # Release > installiertes Commit (+1 Tag Toleranz)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
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)."""
|
||||||
|
now = time.time()
|
||||||
|
if now - _comp_cache["ts"] < 3600 and _comp_cache["data"]:
|
||||||
|
return _comp_cache["data"]
|
||||||
|
data = [_hermes_agent_update(), _anythingllm_update()]
|
||||||
|
_comp_cache.update(ts=now, data=data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def model_upgrades() -> list[dict]:
|
def model_upgrades() -> list[dict]:
|
||||||
"""Dynamisch: je discover-Kategorie das empfohlene Modell, das NOCH NICHT installiert ist,
|
"""Dynamisch: je discover-Kategorie das empfohlene Modell, das NOCH NICHT installiert ist,
|
||||||
aber NUR wenn für diese Rolle bereits irgendein Modell konfiguriert ist.
|
aber NUR wenn für diese Rolle bereits irgendein Modell konfiguriert ist.
|
||||||
@@ -135,7 +207,8 @@ def _last_apt_update() -> float | None:
|
|||||||
def updates() -> dict:
|
def updates() -> dict:
|
||||||
ups = model_upgrades()
|
ups = model_upgrades()
|
||||||
return {"os": _os_upgradable(), "engine": 1 if _engine_update_available() else 0,
|
return {"os": _os_upgradable(), "engine": 1 if _engine_update_available() else 0,
|
||||||
"models": len(ups), "model_list": ups, "last_check": _last_apt_update()}
|
"models": len(ups), "model_list": ups, "last_check": _last_apt_update(),
|
||||||
|
"components": _components_cached()}
|
||||||
|
|
||||||
|
|
||||||
def _run(cmd: list[str], sudo_password: str | None = None) -> dict:
|
def _run(cmd: list[str], sudo_password: str | None = None) -> dict:
|
||||||
@@ -233,8 +306,9 @@ def engine_update_job(sudo_password: str | None = None) -> dict | None:
|
|||||||
return None
|
return None
|
||||||
if err := check_sudo_needs_password(sudo_password):
|
if err := check_sudo_needs_password(sudo_password):
|
||||||
return err
|
return err
|
||||||
cmd = f"{ENGINE_UPDATE_CMD} && sudo systemctl restart llama-swap"
|
# update-engine.sh läuft via sudo als root und startet llama-swap am Ende selbst neu.
|
||||||
job_id = jobengine.start_job(["bash", "-c", cmd], "Engine-Update (llama.cpp)", sudo_password=sudo_password)
|
job_id = jobengine.start_job(["bash", "-c", ENGINE_UPDATE_CMD],
|
||||||
|
"Engine-Update (llama.cpp Vulkan)", sudo_password=sudo_password)
|
||||||
return {"ok": True, "job_id": job_id}
|
return {"ok": True, "job_id": job_id}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Aktualisiert den Vulkan-llama.cpp-Build auf den neuesten ggml-org-Release.
|
||||||
|
# Wird vom MC2-„Engine Update"-Button via `sudo bash …` als ROOT aufgerufen
|
||||||
|
# (deshalb KEIN internes sudo). Startet llama-swap am Ende neu.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VULKAN_DIR=/opt/llamacpp-vulkan
|
||||||
|
PIN_BUILD="${MC_ENGINE_BUILD:-}" # leer = neuester Release
|
||||||
|
|
||||||
|
if [ -n "$PIN_BUILD" ]; then
|
||||||
|
TAG="$PIN_BUILD"
|
||||||
|
else
|
||||||
|
TAG="$(curl -s https://api.github.com/repos/ggml-org/llama.cpp/releases/latest | jq -r .tag_name)"
|
||||||
|
fi
|
||||||
|
[ -n "$TAG" ] && [ "$TAG" != "null" ] || { echo "Konnte neuesten Release-Tag nicht ermitteln"; exit 1; }
|
||||||
|
|
||||||
|
ASSET="llama-${TAG}-bin-ubuntu-vulkan-x64.tar.gz"
|
||||||
|
URL="https://github.com/ggml-org/llama.cpp/releases/download/${TAG}/${ASSET}"
|
||||||
|
TMP="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$TMP"' EXIT
|
||||||
|
|
||||||
|
echo "Lade Engine ${TAG} …"
|
||||||
|
curl -fsSL -o "$TMP/v.tgz" "$URL"
|
||||||
|
tar xzf "$TMP/v.tgz" -C "$TMP"
|
||||||
|
mkdir -p "$VULKAN_DIR"
|
||||||
|
cp -rf "$TMP"/llama-*/. "$VULKAN_DIR"/
|
||||||
|
test -x "$VULKAN_DIR/llama-server"
|
||||||
|
ln -sfn "$VULKAN_DIR/llama-server" /usr/local/bin/llama-server
|
||||||
|
|
||||||
|
systemctl restart llama-swap
|
||||||
|
echo "Engine aktualisiert auf ${TAG} und llama-swap neugestartet."
|
||||||
+395
File diff suppressed because one or more lines are too long
-395
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DPqptZjm.js"></script>
|
<script type="module" crossorigin src="/assets/index-D9tRIUA4.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CjZVMvhL.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CjZVMvhL.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function AgentStatusCard() {
|
|||||||
: "border border-border text-muted-foreground"
|
: "border border-border text-muted-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ExternalLink className="h-3 w-3" /> Hermes öffnen
|
<ExternalLink className="h-3 w-3" /> AnythingLLM öffnen
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -60,7 +60,7 @@ export function AgentStatusCard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
|
<div className="p-3 bg-background/20 rounded-xl border border-border/40">
|
||||||
<div className="text-[10px] text-muted-foreground uppercase font-semibold">WebUI</div>
|
<div className="text-[10px] text-muted-foreground uppercase font-semibold">AnythingLLM</div>
|
||||||
<div className="flex items-center gap-2 mt-1">
|
<div className="flex items-center gap-2 mt-1">
|
||||||
<span className={cn("h-2 w-2 rounded-full", agent.webui_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
|
<span className={cn("h-2 w-2 rounded-full", agent.webui_reachable ? "bg-emerald-500 animate-pulse" : "bg-amber-500")} />
|
||||||
<span className="text-xs font-medium">{agent.webui_reachable ? "Online" : "Offline"}</span>
|
<span className="text-xs font-medium">{agent.webui_reachable ? "Online" : "Offline"}</span>
|
||||||
|
|||||||
@@ -210,6 +210,35 @@ export function UpdatesCard() {
|
|||||||
<span>Modell-Upgrades</span>
|
<span>Modell-Upgrades</span>
|
||||||
<span className="font-mono">{updates.models > 0 ? `${updates.models} verfügbar` : "aktuell"}</span>
|
<span className="font-mono">{updates.models > 0 ? `${updates.models} verfügbar` : "aktuell"}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Komponenten: Hermes Agent + AnythingLLM */}
|
||||||
|
{updates.components?.map((c) => {
|
||||||
|
const isUpdate = c.update === true
|
||||||
|
return (
|
||||||
|
<div key={c.key} className={cn(
|
||||||
|
"flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",
|
||||||
|
isUpdate
|
||||||
|
? "border-amber-500/30 bg-amber-500/5 text-amber-400 font-semibold"
|
||||||
|
: "border-border/30 bg-background/25 text-muted-foreground"
|
||||||
|
)}>
|
||||||
|
<span className="flex items-center gap-1.5">
|
||||||
|
{c.name}
|
||||||
|
{c.reachable === false && (
|
||||||
|
<span className="text-[8px] font-bold uppercase text-red-400/80">offline</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className="font-mono text-[10px]" title={c.current ? `installiert: ${c.current}` : undefined}>
|
||||||
|
{isUpdate
|
||||||
|
? `Update: ${c.latest}`
|
||||||
|
: c.update === false
|
||||||
|
? "aktuell"
|
||||||
|
: c.latest
|
||||||
|
? `neueste: ${c.latest}`
|
||||||
|
: "—"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-2 border-t border-border/20 pt-3">
|
<div className="grid grid-cols-2 gap-2 border-t border-border/20 pt-3">
|
||||||
|
|||||||
@@ -202,12 +202,22 @@ export interface ServicesResp {
|
|||||||
links: { engine_ui: string; gateway: string; hermes_webui: string }
|
links: { engine_ui: string; gateway: string; hermes_webui: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ComponentUpdate {
|
||||||
|
key: string // "hermes_agent" | "anythingllm"
|
||||||
|
name: string
|
||||||
|
current: string | null
|
||||||
|
latest: string | null
|
||||||
|
update: boolean | null // null = unbestimmbar (z.B. AnythingLLM-Version remote nicht abfragbar)
|
||||||
|
reachable: boolean | null
|
||||||
|
}
|
||||||
|
|
||||||
export interface UpdatesResp {
|
export interface UpdatesResp {
|
||||||
os: number
|
os: number
|
||||||
engine: number
|
engine: number
|
||||||
models: number
|
models: number
|
||||||
model_list: { role: string; title: string; repo: string }[]
|
model_list: { role: string; title: string; repo: string }[]
|
||||||
last_check?: number | null
|
last_check?: number | null
|
||||||
|
components?: ComponentUpdate[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnectTool {
|
export interface ConnectTool {
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ export const NAV: NavItem[] = [
|
|||||||
{ id: "system", label: "Diagnose", hint: "Metriken, Dienste, Logs", icon: Cpu },
|
{ id: "system", label: "Diagnose", hint: "Metriken, Dienste, Logs", icon: Cpu },
|
||||||
{ id: "memory", label: "Gedächtnis", hint: "Geteiltes Memory verwalten", icon: Brain },
|
{ id: "memory", label: "Gedächtnis", hint: "Geteiltes Memory verwalten", icon: Brain },
|
||||||
{ id: "connect", label: "Verbinden", hint: "IDE-/Agent-Configs erzeugen", icon: Plug },
|
{ id: "connect", label: "Verbinden", hint: "IDE-/Agent-Configs erzeugen", icon: Plug },
|
||||||
{ id: "agent", label: "Hermes", hint: "Agent-Status & WebUI öffnen", icon: Bot },
|
{ id: "agent", label: "Hermes", hint: "Agent-Status & AnythingLLM öffnen", icon: Bot },
|
||||||
{ id: "guide", label: "Anleitung", hint: "Einrichten & Vibe-Coding", icon: HelpCircle },
|
{ id: "guide", label: "Anleitung", hint: "Einrichten & Vibe-Coding", icon: HelpCircle },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export function AgentView() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ExternalLink className="h-4 w-4" />
|
<ExternalLink className="h-4 w-4" />
|
||||||
<span>Hermes WebUI öffnen</span>
|
<span>AnythingLLM öffnen</span>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -170,9 +170,9 @@ export function AgentView() {
|
|||||||
icon={Bot}
|
icon={Bot}
|
||||||
/>
|
/>
|
||||||
<Tile
|
<Tile
|
||||||
label="Agent WebUI"
|
label="AnythingLLM"
|
||||||
ok={s.webui_reachable}
|
ok={s.webui_reachable}
|
||||||
detail="Port :8787 (Chat UI)"
|
detail="Chat-UI (AnythingLLM)"
|
||||||
icon={Activity}
|
icon={Activity}
|
||||||
/>
|
/>
|
||||||
<Tile
|
<Tile
|
||||||
@@ -239,10 +239,10 @@ export function AgentView() {
|
|||||||
onMouseEnter={() => setHoveredNode("webui")}
|
onMouseEnter={() => setHoveredNode("webui")}
|
||||||
onMouseLeave={() => setHoveredNode(null)}
|
onMouseLeave={() => setHoveredNode(null)}
|
||||||
onClick={() => s.webui_reachable && window.open(resolveExternalUrl(s.webui_url), "_blank")}
|
onClick={() => s.webui_reachable && window.open(resolveExternalUrl(s.webui_url), "_blank")}
|
||||||
title={s.webui_reachable ? "Klicken um Chat-WebUI zu öffnen" : "WebUI Offline"}
|
title={s.webui_reachable ? "Klicken um AnythingLLM zu öffnen" : "AnythingLLM offline"}
|
||||||
>
|
>
|
||||||
<Activity className={cn("h-3.5 w-3.5", s.webui_reachable ? "text-emerald-400" : "text-amber-500")} />
|
<Activity className={cn("h-3.5 w-3.5", s.webui_reachable ? "text-emerald-400" : "text-amber-500")} />
|
||||||
<span>Agent WebUI</span>
|
<span>AnythingLLM</span>
|
||||||
<span className={cn("w-1.5 h-1.5 rounded-full animate-pulse ml-auto", s.webui_reachable ? "bg-emerald-500" : "bg-amber-500")} />
|
<span className={cn("w-1.5 h-1.5 rounded-full animate-pulse ml-auto", s.webui_reachable ? "bg-emerald-500" : "bg-amber-500")} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ export function GuideView() {
|
|||||||
<ul className="text-[11px] text-muted-foreground space-y-2 list-disc pl-4 leading-relaxed">
|
<ul className="text-[11px] text-muted-foreground space-y-2 list-disc pl-4 leading-relaxed">
|
||||||
<li><strong>Keine Verbindung?</strong> Überprüfe im Live-Verbindungsprüfer oben, ob die Box-IP erreichbar ist. Stelle sicher, dass dein lokaler PC im selben WLAN/LAN-Netzwerk wie die Box eingeloggt ist.</li>
|
<li><strong>Keine Verbindung?</strong> Überprüfe im Live-Verbindungsprüfer oben, ob die Box-IP erreichbar ist. Stelle sicher, dass dein lokaler PC im selben WLAN/LAN-Netzwerk wie die Box eingeloggt ist.</li>
|
||||||
<li><strong>Modell antwortet nicht?</strong> Schaue unter <strong>Diagnose</strong>, ob der Dienst `llama-swap` aktiv (grün) is. Wenn nicht, klicke daneben auf <strong>Restart</strong>.</li>
|
<li><strong>Modell antwortet nicht?</strong> Schaue unter <strong>Diagnose</strong>, ob der Dienst `llama-swap` aktiv (grün) is. Wenn nicht, klicke daneben auf <strong>Restart</strong>.</li>
|
||||||
<li><strong>Hermes Agent reagiert merkwürdig?</strong> Starte in der Hermes WebUI einfach eine frische Session (neuen Chat). Ältere Chats sammeln Kontext-Müll an.</li>
|
<li><strong>Hermes Agent reagiert merkwürdig?</strong> Starte in AnythingLLM einfach eine frische Session (neuen Chat). Ältere Chats sammeln Kontext-Müll an.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -474,7 +474,7 @@ description: Drive development with strict TDD practices
|
|||||||
<ul className="list-disc pl-4 space-y-1">
|
<ul className="list-disc pl-4 space-y-1">
|
||||||
<li><strong>Chat-Kontext sauber halten:</strong> Starte regelmäßig neue Chats. Zu große Historien verlangsamen den Agenten und führen zu Halluzinationen.</li>
|
<li><strong>Chat-Kontext sauber halten:</strong> Starte regelmäßig neue Chats. Zu große Historien verlangsamen den Agenten und führen zu Halluzinationen.</li>
|
||||||
<li><strong>Gehirn festlegen:</strong> Konfiguriere im Gateway die Modell-Rolle <code>brain</code> für Hermes, damit er automatisch das passende Modell per Llama Swap lädt.</li>
|
<li><strong>Gehirn festlegen:</strong> Konfiguriere im Gateway die Modell-Rolle <code>brain</code> für Hermes, damit er automatisch das passende Modell per Llama Swap lädt.</li>
|
||||||
<li><strong>Sandbox umgehen:</strong> Erweitere Hermes' System-Prompt (WebUI-Einstellungen), um Befehle über SSH an deinen Windows-PC zu leiten.</li>
|
<li><strong>Sandbox umgehen:</strong> Erweitere Hermes' System-Prompt (AnythingLLM-Einstellungen), um Befehle über SSH an deinen Windows-PC zu leiten.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user