fix(diagnostic+brain): Sprachmodell-Einstellung auf runtime.json umgestellt

War kaputt nach OpenClaw-Abriss: handleGetModel/handleSetModel haben gegen
aria-core (dockerExec + node-script in den Container) gearbeitet, der gibt's
nicht mehr.

diagnostic/server.js
  - handleGetModel/handleSetModel lesen/schreiben jetzt brainModel in
    /shared/config/runtime.json
  - RUNTIME_CONFIG_FIELDS um "brainModel" erweitert
  - Tote Variante (findSettingsFile + base64-node-script) komplett raus

aria-brain/proxy_client.py
  - Liest brainModel aus runtime.json beim Container-Start
  - Fallback: BRAIN_MODEL env → "claude-sonnet-4" Default
  - Bei Aenderung in Diagnostic: aria-brain restarten damit's greift
    (Hinweis steht in der UI)

diagnostic/index.html
  - Section "Model" → "Sprachmodell (Brain)"
  - Hinweis-Block mit Default-Erklaerung und Restart-Hinweis
  - Modelle: claude-sonnet-4 (default), claude-opus-4, claude-haiku-4-5

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 22:36:14 +02:00
parent 094bd6e4f1
commit aa077f60e6
3 changed files with 53 additions and 25 deletions
+20 -1
View File
@@ -9,8 +9,10 @@ neuen CLI-Prozess (Cold-Start), das dauert.
from __future__ import annotations
import json
import logging
import os
from pathlib import Path
from typing import List, Optional
import httpx
@@ -18,11 +20,28 @@ from pydantic import BaseModel
logger = logging.getLogger(__name__)
DEFAULT_MODEL = os.environ.get("BRAIN_MODEL", "claude-sonnet-4")
RUNTIME_CONFIG_FILE = Path("/shared/config/runtime.json")
ENV_MODEL = os.environ.get("BRAIN_MODEL", "claude-sonnet-4")
PROXY_URL = os.environ.get("PROXY_URL", "http://proxy:3456")
PROXY_TIMEOUT_SEC = float(os.environ.get("PROXY_TIMEOUT_SEC", "300"))
def _read_model_from_runtime() -> str:
"""Liest brainModel aus runtime.json. Fallback: ENV BRAIN_MODEL."""
try:
if RUNTIME_CONFIG_FILE.exists():
data = json.loads(RUNTIME_CONFIG_FILE.read_text(encoding="utf-8"))
m = (data.get("brainModel") or "").strip()
if m:
return m
except Exception as exc:
logger.warning("runtime.json lesen fehlgeschlagen: %s", exc)
return ENV_MODEL
DEFAULT_MODEL = _read_model_from_runtime()
class Message(BaseModel):
role: str # "system" | "user" | "assistant" | "tool"
content: Optional[str] = None
+11 -3
View File
@@ -659,13 +659,21 @@
selbst (Skills + skill_create Meta-Tool). Es gibt keine granulare
Permission-Maske, Brain weiss zur Laufzeit welche Tools es hat. -->
<!-- Model-Einstellungen -->
<!-- Brain-Model-Einstellung -->
<div class="settings-section">
<h2>Model</h2>
<h2>Sprachmodell (Brain)</h2>
<div class="card" style="max-width:500px;">
<div style="font-size:11px;color:#8888AA;margin-bottom:10px;line-height:1.5;">
Welches Claude-Model nutzt das Brain pro Anfrage. Wert wird in
<code>/shared/config/runtime.json</code> als <code>brainModel</code> persistiert.
Bei Aenderung: <strong>aria-brain restarten</strong> (Reparatur-Section oben), damit's greift.
<br><br>
Verfuegbar via Proxy: <code>claude-sonnet-4</code> (Default — schnell, gut),
<code>claude-opus-4</code> (langsam, smarter), <code>claude-haiku-4-5</code> (sehr schnell, kleiner Kontext).
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:12px;color:#8888AA;white-space:nowrap;">Aktives Model:</span>
<input type="text" id="setting-model" placeholder="z.B. proxy/claude-sonnet-4" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<input type="text" id="setting-model" placeholder="claude-sonnet-4" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<button class="btn secondary" onclick="loadModel()" style="padding:4px 8px;font-size:10px;">Laden</button>
<button class="btn" onclick="saveModel()" style="padding:4px 8px;font-size:10px;">Setzen</button>
</div>
+22 -21
View File
@@ -65,6 +65,7 @@ const RUNTIME_CONFIG_FILE = "/shared/config/runtime.json";
const RUNTIME_CONFIG_FIELDS = [
"RVS_HOST", "RVS_PORT", "RVS_TLS", "RVS_TOKEN",
"ARIA_AUTH_TOKEN", "WHISPER_MODEL", "WHISPER_LANGUAGE",
"brainModel",
];
function readRuntimeConfig() {
const envDefaults = {
@@ -2164,42 +2165,42 @@ async function handleRestartSession(clientWs) {
// Claude Code laeuft mit --dangerously-skip-permissions (Alles oder Nichts).
// Root-Check wird via CLAUDE_CODE_BUBBLEWRAP=1 in docker-compose.yml umgangen.
// ── Einstellungen: Model ────────────────────────────────
// ── Einstellungen: Model (Brain) ────────────────────────
// Liest/schreibt brainModel in /shared/config/runtime.json — Brain liest
// das beim Container-Start. Bei Aenderung: aria-brain restarten
// (Einstellungen → Reparatur → 🚨 aria-brain neu).
async function handleGetModel(clientWs) {
function handleGetModel(clientWs) {
try {
const raw = await dockerExec("aria-core", `echo $DEFAULT_MODEL`);
clientWs.send(JSON.stringify({ type: "model_info", model: raw.trim(), info: "Aktuelles Model (ENV)" }));
const cfg = readRuntimeConfig();
const model = (cfg.brainModel || "").trim() || "claude-sonnet-4";
clientWs.send(JSON.stringify({
type: "model_info",
model,
info: "Brain-Model (runtime.json) — bei Aenderung: aria-brain restarten",
}));
} catch (err) {
clientWs.send(JSON.stringify({ type: "model_info", error: err.message }));
}
}
async function handleSetModel(clientWs, model) {
function handleSetModel(clientWs, model) {
if (!model || typeof model !== "string") {
clientWs.send(JSON.stringify({ type: "model_info", error: "Kein Model angegeben" }));
return;
}
try {
// Model in Settings speichern (OpenClaw liest das)
const settingsPath = await findSettingsFile();
const script = [
'const fs=require("fs");',
`const f="${settingsPath}";`,
'let s={};try{s=JSON.parse(fs.readFileSync(f,"utf8"));}catch(e){}',
`s.model=${JSON.stringify(model)};`,
`const dir=f.substring(0,f.lastIndexOf("/"));`,
'try{fs.mkdirSync(dir,{recursive:true});}catch(e){}',
'fs.writeFileSync(f,JSON.stringify(s,null,2));',
].join("");
const b64 = Buffer.from(script).toString("base64");
await dockerExec("aria-core", `echo ${b64} | base64 -d | node`);
clientWs.send(JSON.stringify({ type: "model_info", model, info: `Model auf "${model}" gesetzt (Neustart noetig)` }));
log("info", "server", `Model gesetzt: ${model}`);
writeRuntimeConfig({ brainModel: model.trim() });
log("info", "server", `Brain-Model gesetzt: ${model.trim()}`);
clientWs.send(JSON.stringify({
type: "model_info",
model: model.trim(),
info: `Model auf "${model.trim()}" gesetzt — aria-brain neu starten damit's greift`,
}));
} catch (err) {
clientWs.send(JSON.stringify({ type: "model_info", error: err.message }));
}
return;
}
// OpenClaw-Config-Handler entfernt — aria-core ist raus.