fix(phase-a): Kontext-Cap, Download-State, Recipe-Edit, OS-Badge, Swap-Flash

A1: 32768-Kontext-Cap entfernt (install-recipe, install-model, register) →
    max_ctx_for() liefert nun bis zu 128k auf Strix Halo; behebt "context
    size exceeded" bei externen Tools.
A2: Download-State jetzt im Status-Endpoint sichtbar: Modelle zeigen
    "↓ Download X%" statt "bereit" während Job läuft (Backend + Frontend).
A3: PUT /api/cookbook/user-recipe/{id} + Edit-Button (✎) für eigene Setups.
    Download-Modal setzt Kontext-Input automatisch auf optimal.
A4: /api/updates liefert apt_cache_age_h; Badge zeigt Tooltip + ⚠ wenn >24h.
A5: Swap-Flash: Topbar-Text pulst kurz teal wenn Modell den State wechselt.
A6: LLM-Engine-Update fragt jetzt per confirmModal nach (Konsistenz).
A7: Event-Delegation statt per-render addEventListener in models.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-22 21:33:03 +02:00
parent 022c42dccb
commit 82d15d82db
10 changed files with 214 additions and 45 deletions
+21 -2
View File
@@ -42,7 +42,7 @@ class RegisterReq(BaseModel):
alias: str = "" # rueckwaertskompatibel: wird als Rolle interpretiert, wenn 'role' fehlt
role: str | None = None # Rollen-Tag (vision/coder/scout/reviewer/manager o.ae.)
model_path: str
ctx: int = 8192
ctx: int | None = None # None → optimal fuer die Hardware (max_ctx_for)
ttl: int | None = None
@@ -138,6 +138,20 @@ def status():
"peak_ram_optimal_gb": (round(estimate_memory_gb(_pb, quant or "Q4_K_M", _oc), 1) if _oc else None),
}
}
# Laufende Download-Jobs erkennnen: Modell bekommt state "downloading" + Fortschritt.
for j in JOBS.values():
if j.get("state") not in ("running", "queued"):
continue
rp = j.get("result_path", "")
if not rp:
continue
for mconf in configured.values():
m_p = re.search(r'-(?:m|-model)\s+(\S+)', mconf.get("cmd", ""))
if m_p and m_p.group(1).strip("'\"") == rp:
mconf["state"] = "downloading"
mconf["download_progress"] = j.get("progress")
break
swap_ok = True
try:
running = _swap_get("/running")
@@ -200,7 +214,12 @@ def register(req: RegisterReq):
# Bewusst KEIN exists()-Check: beim frischen Download läuft der hf-Job noch, die Datei kommt
# erst gleich. Eintrag jetzt schon schreiben → llama-swap (-watch-config) lädt, sobald sie da ist.
cfg = read_config()
cmd = CMD_TEMPLATE.replace("{model}", req.model_path).replace("{ctx}", str(req.ctx))
ctx = req.ctx
if ctx is None:
params_b = extract_params_b(req.model_path)
ram_gb = psutil.virtual_memory().total / (1024 ** 3)
ctx = max_ctx_for(params_b, "Q4_K_M", ram_gb)
cmd = CMD_TEMPLATE.replace("{model}", req.model_path).replace("{ctx}", str(ctx))
cmd = _augment_vision(cmd, req.model_path)
# Neues Schema: Schluessel = sprechender Modellname (steht so in der Modell-Liste und ist
# der API-Name), die Rolle kommt als llama-swap-Alias obendrauf (beide Namen funktionieren).