${e(b.revision)} · ${e(b.backend)} ${s.active===b.id?'· STANDARD':''}
Commit ${e(b.commit)} · GPU-Ziele ${e(b.architectures.join(', ')||'CPU')} · Auto-Fit ${b.fit_supported?'unterstützt':'nicht unterstützt'}
const RuntimeUI=(()=>{ const e=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); async function api(path='',data){const r=await fetch('/api/v1/runtime'+path,data?{method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)}:{});const v=await r.json();if(!r.ok)throw Error(v.error||'Anfrage fehlgeschlagen');return v;} function html(){return `
Offizielle Versionen getrennt bauen und prüfen. Ein Build lädt kein Modell und ändert keine produktiven Laufzeiten.
Das aktuelle reguläre Release steht zuerst. Nightlies enthalten neuere Änderungen, sind aber keine pauschale Empfehlung. Modell-, MTP- und Projektor-Kompatibilität vor einem Standardwechsel testen.
Als Standard auswählen startet keinen Prozess. Bestehende Router bleiben unverändert.
Kein pauschales Reservefeld: Die Laufzeit soll Modell, gewünschten Kontext, Slots und den aktuell freien Speicher gemeinsam berücksichtigen. Unterstützte Builds verwenden llama.cpp --fit on; der Kontext wird ausdrücklich vorgegeben. Keine absichtlichen OOM-Tests auf den produktiv genutzten GPUs.
Ein Build allein kann keine Modell-Layerzahl bestimmen. Die Berechnung verwendet llama-fit-params ohne Gewichtsallokation. Sie ist eine Prognose für das Textmodell und kein Lasttest. Vision-Projektor und MTP sind noch nicht eingerechnet. Ein Modellstart erfolgt nicht.
Commit ${e(b.commit)} · GPU-Ziele ${e(b.architectures.join(', ')||'CPU')} · Auto-Fit ${b.fit_supported?'unterstützt':'nicht unterstützt'}
Noch kein geprüfter Build vorhanden.
';root.querySelectorAll('[data-build]').forEach(b=>b.onclick=()=>action('/activate',{build_id:b.dataset.build}));if(s.job){const log=await api('/log');if(root.isConnected)root.querySelector('#rt-log').textContent=log.text;}if(running)setTimeout(()=>{if(root.isConnected)status();},3000);}catch(err){msg(err.message);}} async function action(path,data){try{await api(path,data);msg('Aktion angenommen.');await status();}catch(err){msg(err.message);}} async function prerequisites(){try{const p=await api('/prerequisites');if(!root.isConnected)return;root.querySelector('#rt-prereq').innerHTML=`CPU-Build: ${p.cpu_ready?'bereit':'Werkzeuge fehlen'} · CUDA-Build: ${p.cuda_ready?'bereit':'Werkzeuge oder GPUs fehlen'}
${['git','cmake','g++','nvcc'].map(k=>e(k)+': '+e(p[k]||'fehlt')).join(' · ')}
`+p.gpus.map(g=>`${e(g.name)} · Architektur ${e(g.architecture)} · aktuell ${Math.round(g.free_mib)} / ${Math.round(g.total_mib)} MiB frei
`).join('');}catch(err){msg(err.message);}} root.querySelector('#rt-check').onclick=prerequisites; root.querySelector('#rt-build').onsubmit=event=>{event.preventDefault();const d=Object.fromEntries(new FormData(event.target));d.jobs=Number(d.jobs);action('/build',d);}; root.querySelector('#rt-cancel').onclick=()=>action('/cancel',{});root.querySelector('#rt-rollback').onclick=()=>action('/rollback',{}); root.querySelector('#rt-releases').onclick=async()=>{msg('Offizielle Releases werden abgefragt …');try{const v=await api('/releases');if(!root.isConnected)return;root.querySelector('#rt-releases-list').innerHTML=v.releases.map(r=>`${e(r.notes)}