694aff9801
Punkt 1 - Hirn warm: brains-Gruppe wird bei on-demand-Last ausserhalb der Gruppe verdraengt; persist verhindert nur Idle-Unload, nicht Gruppen-Swap -> Hirn blieb bis zum naechsten llama-swap-Neustart kalt. Neu: services/warmer.py als Hintergrund-Task (FastAPI lifespan) prueft periodisch llama-swap /running; ist die Box idle, pingt es das Hirn (Rolle hermes) vor. Waehrend aktiver Last (irgendwas geladen) haelt es sich raus. Justierbar via MC_REWARM_* (ENABLED/INTERVAL/MODEL). Kein sudo, im Repo, deployt normal. Punkt 2 - Updates-Doppelung: Aktionen gab es auf der Karte UND im Pflege-Drawer. UpdatesCard zeigt jetzt nur noch die Status-Ampel + 'Updates verwalten & Pflege'-Button (oeffnet den Drawer). Alle Aktionen (OS/Engine/Reboot/Modell-Upgrade) leben im Drawer mit Job-Fortschritt -> keine Dublette, kuerzere Karte, Sudo-Modal raus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
"""
|
|
Hält das Agent-Hirn (Rolle `hermes`) dauerhaft warm.
|
|
|
|
Hintergrund: llama-swap ist EIN-Gruppen-resident — lädt ein on-demand-Modell außerhalb
|
|
der `brains`-Gruppe, wird die ganze Gruppe (inkl. Hirn) verdrängt. `persist: true`
|
|
verhindert nur Idle-Unload, NICHT die Gruppen-Verdrängung; neu vorgewärmt wird sonst erst
|
|
beim nächsten llama-swap-(Re)Start. Dieser Wächter schließt die Lücke: ist die Box idle
|
|
(nichts geladen), pingt er das Hirn vor. Während aktiver Last (irgendetwas geladen) hält
|
|
er sich raus, verdrängt also nie ein gerade genutztes Modell.
|
|
|
|
Abschaltbar/justierbar via Env: MC_REWARM_ENABLED=0, MC_REWARM_INTERVAL, MC_REWARM_MODEL.
|
|
"""
|
|
|
|
import asyncio
|
|
import logging
|
|
import os
|
|
|
|
import httpx
|
|
|
|
from config import LLAMA_SWAP_URL
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
ENABLED = os.environ.get("MC_REWARM_ENABLED", "1") != "0"
|
|
INTERVAL = int(os.environ.get("MC_REWARM_INTERVAL", "90")) # Sekunden zwischen Checks
|
|
MODEL = os.environ.get("MC_REWARM_MODEL", "hermes") # Alias der Rolle
|
|
START_DELAY = int(os.environ.get("MC_REWARM_START_DELAY", "25"))
|
|
|
|
|
|
async def _running_empty() -> bool:
|
|
async with httpx.AsyncClient(timeout=8.0) as c:
|
|
r = await c.get(f"{LLAMA_SWAP_URL}/running")
|
|
data = r.json() or {}
|
|
return not (data.get("running") or [])
|
|
|
|
|
|
async def _warm() -> None:
|
|
async with httpx.AsyncClient(timeout=180.0) as c:
|
|
await c.post(f"{LLAMA_SWAP_URL}/v1/chat/completions", json={
|
|
"model": MODEL, "max_tokens": 1,
|
|
"messages": [{"role": "user", "content": "ping"}],
|
|
})
|
|
|
|
|
|
async def rewarm_loop() -> None:
|
|
"""Endlos-Schleife (Hintergrund-Task): prüft periodisch, wärmt bei Idle vor."""
|
|
await asyncio.sleep(START_DELAY) # Box/Engine nach MC-Start setzen lassen
|
|
while True:
|
|
try:
|
|
if await _running_empty():
|
|
log.info("rewarm: Box idle → Hirn '%s' wird vorgewärmt", MODEL)
|
|
await _warm()
|
|
except Exception:
|
|
log.debug("rewarm: Tick fehlgeschlagen", exc_info=True)
|
|
await asyncio.sleep(INTERVAL)
|