feat(llm): Kontextfenster pro Karte einstellbar + Fehlerart context_exceeded

Anlass: die Software-Schmiede bekam "request (8274 tokens) exceeds the
available context size (8192 tokens)". Sie holt ctx vom Cluster zwar ab,
kuerzt aber nach einem eigenen, von Hand eingetragenen Wert (32768).

ARIA-Seite:
- Neue Fehlerart context_exceeded (statt model_error) mit promptTokens und ctx
  — Programme koennen automatisch kuerzen und nochmal senden, statt Text
  auszuwerten. llm-adapter liest es aus llama.cpps exceed_context_size_error,
  der Cluster-Router reicht es durch und wiederholt es nicht anderswo.
- Diagnostic → LLM-Karten: Kontextfenster pro Karte (4k … 128k). Laedt das
  Modell mit neuem -c; Programme sehen den neuen Wert ueber ctx. Passt es
  nicht in den Grafikspeicher, setzt die Box zurueck — jetzt inkl. Registry
  (vorher blieb bei einem Fehlschlag der zu grosse ctx in aria_models.json
  stehen und waere beim naechsten Start wieder gescheitert).
- Doku: context_exceeded, ctx kann sich aendern, "danach kuerzen, nicht nur
  anzeigen".

Getestet gegen llama-swap: Kontext 512 → 1024 (gleiche Karte), Fehlschlag
bei 65536 → Registry + Config wieder 1024, zu langer Verlauf →
context_exceeded mit promptTokens=6030, ctx=1024.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 13:32:37 +02:00
co-authored by Claude Opus 5.5
parent f8ae2f4613
commit 79a901089b
4 changed files with 71 additions and 7 deletions
+29 -1
View File
@@ -356,6 +356,24 @@ def _sanitize_messages(messages: list) -> list:
return out
def _llama_error_info(exc: Exception) -> dict:
"""Maschinenlesbare Fehlerart. Wichtigster Fall: der Verlauf ist laenger
als das Kontextfenster — dann soll ein Programm automatisch kuerzen und
nochmal fragen koennen, statt einen Text auszuwerten."""
resp = getattr(exc, "response", None)
if resp is None:
return {}
try:
e = (resp.json() or {}).get("error") or {}
except Exception:
return {}
if isinstance(e, dict) and e.get("type") == "exceed_context_size_error":
return {"errorCode": "context_exceeded",
"promptTokens": int(e.get("n_prompt_tokens") or 0),
"ctx": int(e.get("n_ctx") or 0)}
return {}
def _llama_error_text(exc: Exception) -> str:
"""Bei HTTP-Fehlern den GRUND von llama.cpp mitnehmen. Bisher kam nur
"Server error '500 …'" an — die eigentliche Erklaerung steht im Body."""
@@ -419,7 +437,7 @@ async def _call_llama(messages: list, *, max_tokens: int, temperature: float,
except Exception as e:
msg = _llama_error_text(e)
logger.warning("llama.cpp-Call fehlgeschlagen: %s", msg[:300])
return {"ok": False, "content": "", "error": msg[:700]}
return {"ok": False, "content": "", "error": msg[:700], **_llama_error_info(e)}
# B0.5-2: Lade-Status ans Diagnostic (service_status, service="llm"). Wir kennen
@@ -678,6 +696,8 @@ async def _do_llm_request(ws, payload: dict) -> None:
"tool_calls": tc,
"error": res.get("error"),
"model": model,
# Fehlerart fuer Programme (z.B. context_exceeded + promptTokens + ctx)
**{k: res[k] for k in ("errorCode", "promptTokens", "ctx") if res.get(k)},
# Wer hat geantwortet: Box + Karte. Hilft Clients mit mehreren Boxen.
"instanceId": INSTANCE_ID, "node": NODE_NAME, "gpu": _card_of(model),
"usage": res.get("usage") or {},
@@ -927,6 +947,10 @@ async def _handle_provision(ws, payload: dict) -> None:
error=f"{key} liegt schon auf Karte {elsewhere} dieser Box — ein Modell pro Box nur einmal.")
quant_note = ""
repo_files = None
# Fuer ein Zuruecksetzen: der bisherige Registry-Eintrag dieses Modells.
# Noetig, wenn nur das Kontextfenster geaendert wird (gleiches Modell, gleiche
# Karte) — sonst bliebe nach einem Fehlschlag der zu grosse Wert stehen.
old_entry = next((dict(e) for e in _load_registry() if e.get("key") == key), None)
if repo:
wanted = (payload.get("quant") or "Q4_K_M").strip()
quant = wanted
@@ -1012,6 +1036,10 @@ async def _handle_provision(ws, payload: dict) -> None:
else:
slots.pop(card, None)
_save_slots(slots)
reg = [e for e in _load_registry() if e.get("key") != key]
if old_entry:
reg.append(old_entry)
_save_registry(reg)
_generate_config()
await _reload_llama()
await _announce(ws)