Compare commits
3
Commits
v0.1.2.2
...
950a9d009c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
950a9d009c | ||
|
|
693542ef19 | ||
|
|
d12f356ebe |
+142
-60
@@ -120,6 +120,16 @@
|
||||
/* Settings */
|
||||
.settings-section { margin-bottom:20px; }
|
||||
.settings-section h2 { margin-bottom:12px; }
|
||||
/* Info-Button: kleines (i) neben Ueberschriften */
|
||||
.info-btn { background:transparent; border:1px solid #0096FF; color:#0096FF; width:20px; height:20px;
|
||||
border-radius:50%; padding:0; font-size:11px; font-weight:bold; cursor:pointer; margin-left:6px;
|
||||
line-height:18px; text-align:center; vertical-align:middle; font-family:serif; }
|
||||
.info-btn:hover { background:#0096FF; color:#fff; }
|
||||
.info-btn-small { background:transparent; border:1px solid #0096FF44; color:#0096FF; width:14px; height:14px;
|
||||
border-radius:50%; padding:0; font-size:9px; font-weight:bold; cursor:pointer; margin-left:4px;
|
||||
line-height:11px; text-align:center; vertical-align:middle; font-family:serif; }
|
||||
.info-btn-small:hover { background:#0096FF; color:#fff; }
|
||||
|
||||
.toggle { position:relative; width:40px; height:22px; flex-shrink:0; margin-left:8px; }
|
||||
.toggle input { opacity:0; width:0; height:0; }
|
||||
.toggle .slider { position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0;
|
||||
@@ -592,14 +602,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Runtime-Konfiguration (migriert von .env) -->
|
||||
<!-- Runtime-Konfiguration -->
|
||||
<div class="settings-section">
|
||||
<h2>Runtime-Konfiguration</h2>
|
||||
<div style="font-size:11px;color:#8888AA;margin-bottom:8px;">
|
||||
Werte werden in <code>/shared/config/runtime.json</code> persistiert und
|
||||
ueberschreiben die ENV-Variablen aus <code>aria.env</code>. Bridge liest
|
||||
sie beim naechsten Start — nach Aenderung <b>Bridge-Container neu starten</b>
|
||||
(Diagnostic-Container bleibt auf ENV).
|
||||
ueberschreiben die ENV-Variablen aus der <code>.env</code>. Bridge und Brain
|
||||
lesen sie beim Start — nach Aenderung den jeweiligen Container neu starten
|
||||
(Reparatur-Section oben).
|
||||
</div>
|
||||
<div class="card" style="max-width:600px;">
|
||||
<div style="display:grid;grid-template-columns:140px 1fr;gap:8px 10px;align-items:center;font-size:13px;">
|
||||
@@ -689,20 +699,22 @@
|
||||
<div id="tab-brain" class="main-tab">
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>Gehirn — Status</h2>
|
||||
<h2>Gehirn — Status <button class="info-btn" onclick="showInfo('brain-status')" title="Was bedeutet was?">ℹ</button></h2>
|
||||
<div class="card">
|
||||
<div id="brain-status" style="font-size:12px;color:#8888AA;margin-bottom:8px;">(Lade...)</div>
|
||||
<div id="conversation-status" style="font-size:12px;color:#8888AA;margin-bottom:8px;"></div>
|
||||
<div id="conversation-status" style="font-size:12px;color:#8888AA;margin-bottom:8px;">
|
||||
<button class="info-btn-small" onclick="showInfo('conversation')" title="Konversation — wie funktioniert das?">ℹ</button>
|
||||
</div>
|
||||
<div style="display:flex;gap:6px;flex-wrap:wrap;">
|
||||
<button class="btn secondary" onclick="loadBrainStatus()" style="padding:4px 12px;font-size:11px;">Aktualisieren</button>
|
||||
<button class="btn secondary" onclick="distillNow()" style="padding:4px 12px;font-size:11px;color:#FFD60A;border-color:#FFD60A;" title="Destilliert die aeltesten Turns sofort zu fact-Memories">⚗ Jetzt destillieren</button>
|
||||
<button class="btn secondary" onclick="resetConversation()" style="padding:4px 12px;font-size:11px;color:#FF6B6B;border-color:#FF6B6B;" title="Rolling-Window leeren — destillierte Facts bleiben in der DB">🧹 Konversation leeren</button>
|
||||
<button class="btn secondary" onclick="resetConversation()" style="padding:4px 12px;font-size:11px;color:#FF6B6B;border-color:#FF6B6B;" title="Leert ARIAs Rolling-Window (Brain) + die Chat-Anzeige (chat_backup). Memories bleiben in der Vector-DB.">🧹 Konversation komplett zurücksetzen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>Bootstrap & Migration</h2>
|
||||
<h2>Bootstrap & Migration <button class="info-btn" onclick="showInfo('bootstrap')" title="Was sind die drei Wege?">ℹ</button></h2>
|
||||
<div class="card" style="line-height:1.6;">
|
||||
<p style="color:#8888AA;font-size:12px;margin:0 0 12px;">
|
||||
Drei Wege ARIA mit "Grundregeln" zu füttern — von leichtgewichtig bis Voll-Wiederherstellung.
|
||||
@@ -754,7 +766,7 @@
|
||||
|
||||
<div class="settings-section">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
|
||||
<h2 style="margin:0;">Memories</h2>
|
||||
<h2 style="margin:0;">Memories <button class="info-btn" onclick="showInfo('memories')" title="Hot vs. Cold — wie funktioniert das Gedaechtnis?">ℹ</button></h2>
|
||||
<div>
|
||||
<button class="btn secondary" onclick="resetBrainFilters();loadBrainMemoryList()" style="padding:4px 10px;font-size:11px;">Aktualisieren</button>
|
||||
<button class="btn" onclick="openMemoryModal()" style="padding:4px 10px;font-size:11px;">+ Neu</button>
|
||||
@@ -845,6 +857,17 @@
|
||||
</div>
|
||||
</div><!-- /tab-skills -->
|
||||
|
||||
<!-- Generisches Info-Modal — wird via openInfoModal(title, html) gefuellt -->
|
||||
<div class="modal-overlay" id="info-modal">
|
||||
<div class="modal-box" style="max-width:640px;">
|
||||
<div class="modal-header">
|
||||
<h3 id="info-modal-title">Info</h3>
|
||||
<button class="modal-close" onclick="closeInfoModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body" id="info-modal-body" style="padding:16px;font-size:13px;color:#E0E0F0;line-height:1.6;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Memory-Modal (Neu + Editieren) -->
|
||||
<div class="modal-overlay" id="memory-modal">
|
||||
<div class="modal-box" style="max-width:640px;">
|
||||
@@ -993,7 +1016,16 @@
|
||||
ws.onopen = () => {
|
||||
addLog('info', 'browser', 'Verbunden mit Diagnostic Server');
|
||||
send({ action: 'load_chat_history' });
|
||||
// Brain-Card initial laden (sonst zeigt sie "Lade...")
|
||||
try { loadBrainStatus(); } catch {}
|
||||
};
|
||||
|
||||
// Brain-Status periodisch refreshen damit die Card live bleibt
|
||||
if (!window.__brainStatusInterval) {
|
||||
window.__brainStatusInterval = setInterval(() => {
|
||||
try { loadBrainStatus(); } catch {}
|
||||
}, 15000);
|
||||
}
|
||||
ws.onclose = () => {
|
||||
addLog('warn', 'browser', 'Verbindung zum Diagnostic Server verloren — Reconnect in 2s');
|
||||
setTimeout(connectWS, 2000);
|
||||
@@ -1230,12 +1262,7 @@
|
||||
el.textContent = msg.error ? `Fehler: ${msg.error}` : msg.info;
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'core_auth') {
|
||||
const el = document.getElementById('core-auth');
|
||||
el.style.display = 'block';
|
||||
el.textContent = msg.error ? `Fehler: ${msg.error}` : msg.info;
|
||||
return;
|
||||
}
|
||||
// core_auth WS-Event entfernt — aria-core ist raus.
|
||||
// Live SSH + Desktop
|
||||
if (msg.type?.startsWith('live_ssh_')) { handleLiveSSH(msg); return; }
|
||||
if (msg.type === 'desktop_status') { handleDesktop(msg); return; }
|
||||
@@ -1310,32 +1337,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Settings (permissions_list/permissions_saved entfernt — Alles-oder-Nichts via --dangerously-skip-permissions)
|
||||
if (msg.type === 'session_restarted') {
|
||||
const s = document.getElementById('perms-status');
|
||||
s.style.display = 'block';
|
||||
if (msg.status === 'restarting') {
|
||||
s.style.color = '#FFD60A';
|
||||
s.textContent = 'aria-core wird neu gestartet...';
|
||||
} else if (msg.status === 'ok') {
|
||||
s.style.color = '#34C759';
|
||||
s.textContent = msg.info || 'Session neu gestartet!';
|
||||
} else {
|
||||
s.style.color = '#FF6B6B';
|
||||
s.textContent = 'Restart fehlgeschlagen: ' + (msg.error || '?');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// session_restarted / openclaw_config WS-Events entfernt — aria-core ist raus.
|
||||
if (msg.type === 'model_info') {
|
||||
const el = document.getElementById('setting-model');
|
||||
const st = document.getElementById('model-status');
|
||||
if (msg.model) el.value = msg.model;
|
||||
st.textContent = msg.info || '';
|
||||
st.style.color = msg.error ? '#FF6B6B' : '#34C759';
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'openclaw_config') {
|
||||
document.getElementById('openclaw-config').textContent = msg.config || msg.error || '(leer)';
|
||||
if (el && msg.model) el.value = msg.model;
|
||||
if (st) {
|
||||
st.textContent = msg.info || msg.error || '';
|
||||
st.style.color = msg.error ? '#FF6B6B' : '#34C759';
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'response') { return; }
|
||||
@@ -1422,15 +1432,12 @@
|
||||
openTermModal('Claude Login Terminal (aria-proxy)', { action: 'proxy_login' });
|
||||
}
|
||||
|
||||
function openCoreTerminal() {
|
||||
document.getElementById('btn-core-term').disabled = true;
|
||||
openTermModal('aria-core Shell', { action: 'core_terminal' });
|
||||
}
|
||||
// openCoreTerminal entfernt — aria-core ist raus.
|
||||
|
||||
function closeTermModal() {
|
||||
document.getElementById('term-modal').classList.remove('open');
|
||||
document.getElementById('btn-proxy-login').disabled = false;
|
||||
document.getElementById('btn-core-term').disabled = false;
|
||||
const proxyBtn = document.getElementById('btn-proxy-login');
|
||||
if (proxyBtn) proxyBtn.disabled = false;
|
||||
// Terminal aufraeumen
|
||||
if (term) { term.dispose(); term = null; }
|
||||
}
|
||||
@@ -1496,12 +1503,8 @@
|
||||
}
|
||||
|
||||
function updateState(state) {
|
||||
// Gateway
|
||||
const gw = state.gateway || {};
|
||||
document.getElementById('gw-dot').className = `dot ${gw.status || 'disconnected'}`;
|
||||
document.getElementById('gw-status').textContent =
|
||||
(STATUS_LABELS[gw.status] || gw.status) + (gw.handshakeOk ? ' (Handshake OK)' : '');
|
||||
document.getElementById('gw-error').textContent = gw.lastError || '';
|
||||
// Brain-Card holt ihre Daten via loadBrainStatus() (fetch /api/brain/health).
|
||||
// state.gateway ist Reststruktur aus OpenClaw-Zeit — wir ignorieren das hier.
|
||||
|
||||
// RVS
|
||||
const rvs = state.rvs || {};
|
||||
@@ -2280,7 +2283,6 @@
|
||||
document.getElementById('rc-rvs-tls').value = String(cfg.RVS_TLS) === 'false' ? 'false' : 'true';
|
||||
document.getElementById('rc-rvs-token').value = cfg.RVS_TOKEN || '';
|
||||
document.getElementById('rc-auth-token').value = cfg.ARIA_AUTH_TOKEN || '';
|
||||
document.getElementById('rc-compact-after').value = cfg.compactAfterMessages != null ? cfg.compactAfterMessages : 140;
|
||||
statusEl.textContent = 'Geladen.';
|
||||
statusEl.style.color = '#34C759';
|
||||
loadOnboardingQR(); // QR bei Config-Wechsel neu generieren
|
||||
@@ -2293,14 +2295,12 @@
|
||||
async function saveRuntimeConfig() {
|
||||
const statusEl = document.getElementById('rc-status');
|
||||
statusEl.textContent = 'Speichere...';
|
||||
const compactRaw = document.getElementById('rc-compact-after').value.trim();
|
||||
const patch = {
|
||||
RVS_HOST: document.getElementById('rc-rvs-host').value.trim(),
|
||||
RVS_PORT: document.getElementById('rc-rvs-port').value.trim(),
|
||||
RVS_TLS: document.getElementById('rc-rvs-tls').value,
|
||||
RVS_TOKEN: document.getElementById('rc-rvs-token').value.trim(),
|
||||
ARIA_AUTH_TOKEN: document.getElementById('rc-auth-token').value.trim(),
|
||||
compactAfterMessages: compactRaw === '' ? 140 : Math.max(0, parseInt(compactRaw, 10) || 0),
|
||||
};
|
||||
try {
|
||||
const resp = await fetch('/api/runtime-config', {
|
||||
@@ -2895,14 +2895,15 @@
|
||||
// Conversation-Stats (separater Endpoint)
|
||||
const conv = document.getElementById('conversation-status');
|
||||
if (!conv) return;
|
||||
const infoBtn = `<button class="info-btn-small" onclick="showInfo('conversation')" title="Konversation — wie funktioniert das?">ℹ</button>`;
|
||||
try {
|
||||
const r2 = await fetch('/api/brain/conversation/stats');
|
||||
if (!r2.ok) throw new Error('HTTP ' + r2.status);
|
||||
const d2 = await r2.json();
|
||||
const distillIcon = d2.needs_distill ? ' ⚠ Destillat bald fällig' : '';
|
||||
conv.innerHTML = `Konversation: <strong>${d2.turns}</strong> Turns · Window: ${d2.max_window} · Schwelle: ${d2.distill_threshold}${distillIcon}`;
|
||||
conv.innerHTML = `Konversation: <strong>${d2.turns}</strong> Turns · Window: ${d2.max_window} · Schwelle: ${d2.distill_threshold}${distillIcon} ${infoBtn}`;
|
||||
} catch (e) {
|
||||
conv.innerHTML = `Konversation: <span style="color:#555570;">${e.message}</span>`;
|
||||
conv.innerHTML = `Konversation: <span style="color:#555570;">${e.message}</span> ${infoBtn}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2920,14 +2921,23 @@
|
||||
}
|
||||
|
||||
async function resetConversation() {
|
||||
if (!confirm('Konversation leeren?\n\nDer Rolling-Window-Verlauf wird komplett verworfen. Destillierte Facts bleiben in der DB.')) return;
|
||||
if (!confirm('Konversation komplett zurücksetzen?\n\n• ARIAs Rolling-Window (Brain) wird geleert — sie "vergisst" die letzten Turns\n• Chat-Anzeige in der Diagnostic wird geleert\n\nDestillierte Facts + andere Memories bleiben in der Vector-DB.')) return;
|
||||
try {
|
||||
const r = await fetch('/api/brain/conversation/reset', { method: 'POST' });
|
||||
const d = await r.json();
|
||||
if (d.ok) {
|
||||
// Beides parallel — Brain Window + Diagnostic chat_backup
|
||||
const [brainR, histR] = await Promise.all([
|
||||
fetch('/api/brain/conversation/reset', { method: 'POST' }),
|
||||
fetch('/api/chat-history-clear', { method: 'POST' }),
|
||||
]);
|
||||
const brainOk = brainR.ok;
|
||||
const histOk = histR.ok;
|
||||
if (brainOk && histOk) {
|
||||
// Chat-View leeren (Server broadcasted das eh, aber sicherheitshalber)
|
||||
if (chatBox) chatBox.innerHTML = '';
|
||||
const fsBox = document.getElementById('chat-box-fs');
|
||||
if (fsBox) fsBox.innerHTML = '';
|
||||
loadBrainStatus();
|
||||
} else {
|
||||
alert('Reset fehlgeschlagen');
|
||||
alert(`Reset teilweise fehlgeschlagen — Brain: ${brainOk ? 'OK' : 'fail'}, History: ${histOk ? 'OK' : 'fail'}`);
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Reset fehlgeschlagen: ' + e.message);
|
||||
@@ -3161,6 +3171,78 @@
|
||||
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
}
|
||||
|
||||
// ── Generisches Info-Modal — Aufruf: openInfoModal('Titel', '<p>HTML...</p>') ──
|
||||
function openInfoModal(title, html) {
|
||||
const t = document.getElementById('info-modal-title');
|
||||
const b = document.getElementById('info-modal-body');
|
||||
const m = document.getElementById('info-modal');
|
||||
if (!t || !b || !m) return;
|
||||
t.textContent = title;
|
||||
b.innerHTML = html;
|
||||
m.classList.add('open');
|
||||
}
|
||||
function closeInfoModal() {
|
||||
const m = document.getElementById('info-modal');
|
||||
if (m) m.classList.remove('open');
|
||||
}
|
||||
|
||||
// Vor-definierte Info-Blocks
|
||||
const INFO_TEXTS = {
|
||||
'brain-status': {
|
||||
title: 'Gehirn — Status',
|
||||
html: `
|
||||
<p><strong>online / offline</strong> — ob der <code>aria-brain</code> Container erreichbar ist (HTTP GET /health).</p>
|
||||
<p><strong>N Memories</strong> — Anzahl der Punkte in der Vector-DB. Beinhaltet alle Typen: identity, rule, preference, tool, skill, fact, conversation, reminder.</p>
|
||||
<p><strong>Qdrant: aria-qdrant:6333</strong> — Hostname + Port des Vector-DB-Containers. Der Brain spricht intern dorthin.</p>
|
||||
`,
|
||||
},
|
||||
'conversation': {
|
||||
title: 'Konversation — wie funktioniert das?',
|
||||
html: `
|
||||
<p><strong>Rolling Window:</strong> ARIA "sieht" pro Anfrage nur die letzten N Turns einer einzelnen, durchgehenden Konversation. Kein Sessions, kein Multi-Thread.</p>
|
||||
<ul>
|
||||
<li><strong>Turns</strong> — Anzahl aller Nachrichten (User + ARIA) seit dem letzten Destillat oder Reset.</li>
|
||||
<li><strong>Window: 50</strong> — die letzten 50 Turns wandern in den Prompt. Aelteste fallen raus, sobald die Schwelle ueberschritten ist.</li>
|
||||
<li><strong>Schwelle: 60</strong> — bei mehr als 60 Turns triggert Brain automatisch das Destillat (die 30 aeltesten werden zu fact-Memories verdichtet, Token-Budget bleibt konstant).</li>
|
||||
</ul>
|
||||
<p><strong>⚗ Jetzt destillieren:</strong> manueller Trigger fuer das Destillat (kostet einen Claude-Call). Verdichtet die aeltesten 30 Turns zu Fakten + entfernt sie aus dem Window.</p>
|
||||
<p><strong>🧹 Konversation komplett zuruecksetzen:</strong> leert beides — ARIAs Rolling-Window (Brain) UND die Chat-Anzeige hier (chat_backup.jsonl). Destillierte Facts + alle anderen Memories in der Vector-DB <em>bleiben</em>.</p>
|
||||
<p style="margin-top:8px;color:#FFD60A;font-size:12px;">⚠ Falls "Turns: 0" obwohl du oben Chat-Eintraege siehst: chat_backup.jsonl (Anzeige) und conversation.jsonl (Brain-Kontext) sind getrennte Stores. Alte chat_backup-Eintraege koennen aus OpenClaw-Zeit stammen. Reset-Button leert beides.</p>
|
||||
`,
|
||||
},
|
||||
'memories': {
|
||||
title: 'Memories — Hot vs. Cold',
|
||||
html: `
|
||||
<p><strong>Pinned (Hot Memory)</strong> 📌 — landet bei JEDER Anfrage im System-Prompt. Hier gehoeren rein: Identitaet, Sicherheitsregeln, Benutzer-Praeferenzen, Tool-Freigaben, Kern-Skills.</p>
|
||||
<p><strong>Cold Memory</strong> — semantisch durchsucht. Pro Anfrage werden die 5 aehnlichsten Punkte zur User-Frage in den Prompt eingehaengt.</p>
|
||||
<p><strong>Typen:</strong></p>
|
||||
<ul>
|
||||
<li><strong>identity</strong> — wer ARIA ist (Name, Persoenlichkeit)</li>
|
||||
<li><strong>rule</strong> — Sicherheits-/Werte-Regeln</li>
|
||||
<li><strong>preference</strong> — User-Profile</li>
|
||||
<li><strong>tool</strong> — Tool-Freigaben + Infrastruktur</li>
|
||||
<li><strong>skill</strong> — Faehigkeiten (verlinkt mit /data/skills/)</li>
|
||||
<li><strong>fact</strong> — Wissens-Fakten (oft aus Destillaten)</li>
|
||||
<li><strong>conversation</strong> — destillierte Konversations-Erkenntnisse</li>
|
||||
<li><strong>reminder</strong> — Termine, Aufgaben</li>
|
||||
</ul>
|
||||
<p><strong>Such-Feld:</strong> semantische Suche via Embedder + Qdrant. Findet sinngemaess, nicht nur Stichworte.</p>
|
||||
`,
|
||||
},
|
||||
'bootstrap': {
|
||||
title: 'Bootstrap & Migration — die drei Wege',
|
||||
html: `
|
||||
<p><strong>1. Aus brain-import/ migrieren</strong> 🔵 — Parser fuer die <code>.md</code>-Dateien im Repo (AGENT.md, USER.md, TOOLING.md). Schreibt sie als atomare pinned Memories. Idempotent — Re-Run ersetzt nur die Migration-Punkte, eigene Memories bleiben.</p>
|
||||
<p><strong>2. Bootstrap-Snapshot</strong> 🟡 — kleines JSON, NUR die pinned Memories. Export = aktueller Stand als Datei. Import = ALLE aktuell pinned werden ersetzt. Cold Memory bleibt unangetastet.</p>
|
||||
<p><strong>3. Komplettes Gehirn</strong> 🔴 — tar.gz mit allem (Memories + Skills + Qdrant-DB). Backup + Restore. Import ueberschreibt ALLES.</p>
|
||||
`,
|
||||
},
|
||||
};
|
||||
function showInfo(key) {
|
||||
const cfg = INFO_TEXTS[key];
|
||||
if (cfg) openInfoModal(cfg.title, cfg.html);
|
||||
}
|
||||
|
||||
function brainExport() {
|
||||
// Browser folgt der Download-Header-Antwort automatisch
|
||||
window.location.href = '/api/brain-export';
|
||||
|
||||
@@ -1448,6 +1448,23 @@ const server = http.createServer((req, res) => {
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else if (req.url === "/api/chat-history-clear" && req.method === "POST") {
|
||||
// Leert die Diagnostic-Anzeige-History (chat_backup.jsonl).
|
||||
// Brain's Rolling-Window (conversation.jsonl) ist davon unabhaengig —
|
||||
// der Caller sollte zusaetzlich /api/brain/conversation/reset triggern.
|
||||
log("warn", "server", "HTTP /api/chat-history-clear");
|
||||
try {
|
||||
const file = "/shared/config/chat_backup.jsonl";
|
||||
if (fs.existsSync(file)) fs.unlinkSync(file);
|
||||
// Broadcast: alle Browser-Clients sollen ihre lokale Chat-View leeren
|
||||
broadcast({ type: "chat_history", messages: [] });
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ ok: true }));
|
||||
} catch (err) {
|
||||
res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ ok: false, error: err.message }));
|
||||
}
|
||||
return;
|
||||
} else if (req.url === "/api/wipe-all" && req.method === "POST") {
|
||||
// Komplett-Reset — Gedaechtnis, Stimmen, Config alle weg. SSH-Keys
|
||||
// und .env bleiben, RVS-Anbindung bleibt. Brain + Qdrant werden
|
||||
|
||||
Reference in New Issue
Block a user