diff --git a/backend/services/agent.py b/backend/services/agent.py index b3c23ae..155f3cb 100644 --- a/backend/services/agent.py +++ b/backend/services/agent.py @@ -25,63 +25,43 @@ def _hermes_version(name: str) -> float | None: return float(m.group(1)) if m else None +def _active_brain_name() -> str: + """Aktives Agent-Hirn aus Hermes' Config: model.default (sonst model.model).""" + try: + from ruamel.yaml import YAML + p = HERMES_HOME / "config.yaml" + if p.exists(): + with p.open(encoding="utf-8") as f: + cfg = YAML().load(f) or {} + m = (cfg.get("model") or {}) if isinstance(cfg, dict) else {} + return str(m.get("default") or m.get("model") or "auto") + except Exception: + log.debug("_active_brain_name: Lesefehler", exc_info=True) + return "auto" + + def hermes_brain_info() -> dict: - """Aktuelles Agent-Hirn (hermes-Rolle) + bestes verfügbares NousResearch-Hermes-Modell, - das auf diese Hardware passt. Für den Modell-Manager: Brain sichtbar + updatebar, - sobald NousResearch eine neuere Hermes-Generation veröffentlicht.""" - from services import discover, llamaswap - from services.fit import evaluate_fit, extract_params_b + """Aktuelles Agent-Hirn = Modell/Alias, das Hermes laut Config nutzt (model.default), + plus Budget-Check. Zeigt das REAL genutzte Hirn — unabhängig von einer 'hermes'-Rolle.""" + from services import llamaswap models = llamaswap.list_models() - cur = next((m for m in models if m.get("role") == "hermes"), None) - cur_ver = _hermes_version(cur["name"]) if cur else None + brain = _active_brain_name() # z.B. "fast" (Alias) oder ein Modellname + bl = brain.lower() + cur = next((m for m in models if (m.get("role") or "").lower() == bl), None) \ + or next((m for m in models if bl in (m["name"] or "").lower()), None) cur_params = (cur.get("capabilities") or {}).get("params_b") if cur else None current = None if cur: - current = {"name": cur["name"], "filename": cur.get("filename"), + current = {"name": cur["name"], "alias": brain, "filename": cur.get("filename"), "params_b": cur_params, "quant": cur.get("quant"), - "size_bytes": cur.get("size_bytes"), "version": cur_ver, + "size_bytes": cur.get("size_bytes"), "gguf_path": cur.get("gguf_path"), "incomplete": cur.get("incomplete")} - ram = psutil.virtual_memory().total / (1024 ** 3) - best = None - try: - cands = [] - for r in discover._fetch_author_models("NousResearch"): - rid = r.get("id", "") - if "hermes" not in rid.lower(): - continue - pb = extract_params_b(rid) - fit = evaluate_fit(pb, "Q4_K_M", 8192, ram, name=rid) - if fit["level"] == "too_tight": - continue - cands.append({"repo": rid, "name": rid.split("/")[-1], - "version": _hermes_version(rid) or 0.0, "params_b": pb, - "downloads": int(r.get("downloads") or 0), "fit": fit}) - # neueste Hermes-Version zuerst, dann größer/fähiger, dann beliebter - cands.sort(key=lambda c: (c["version"], c["params_b"], c["downloads"]), reverse=True) - best = cands[0] if cands else None - except Exception: - log.debug("hermes_brain_info: HF-Abfrage fehlgeschlagen", exc_info=True) - - update = False - if best is not None: - if cur_ver is None: - update = True - elif best["version"] > cur_ver: - update = True - elif best["version"] == cur_ver and best["params_b"] > (cur_params or 0) * 1.05: - update = True - # gleiche Datei schon installiert? dann kein Update - if current and best["repo"].split("/")[-1].lower() in (current["name"] or "").lower(): - update = False - - # Fit-Check: passt das EMPFOHLENE Brain als Always-On noch ins Budget, sodass das - # größte on-demand-Modell daneben lädt? (Brain muss immer resident sein.) + # Fit-Check: passt das (immer warme) Hirn + das größte on-demand-Modell zusammen ins Budget? budget = None try: from services.budget import footprint_gb, gtt_budget_gb - from services.fit import estimate_memory_gb groups = llamaswap.list_groups() persist = set() for g in groups.values(): @@ -89,13 +69,7 @@ def hermes_brain_info() -> dict: persist.update(g.get("members") or []) cur_name = cur["name"] if cur else None - brain_ctx = int((cur.get("ctx") if cur else None) or 32768) - if best: - brain_gb = estimate_memory_gb(float(best["params_b"]), "Q4_K_M", brain_ctx) - elif cur: - brain_gb = footprint_gb(cur) - else: - brain_gb = 0.0 + brain_gb = footprint_gb(cur) if cur else 0.0 # voller Always-Warm-Footprint (alle persist, Brain=Empfehlung) — nur Info warm = brain_gb + sum(footprint_gb(m) for m in models if m["name"] in persist and m["name"] != cur_name) @@ -114,7 +88,7 @@ def hermes_brain_info() -> dict: except Exception: log.debug("hermes_brain_info: Budget-Berechnung fehlgeschlagen", exc_info=True) - return {"current": current, "recommended": best, "update_available": update, "budget": budget} + return {"current": current, "recommended": None, "update_available": False, "budget": budget} def _reach(url: str, path: str = "") -> bool: