feat(diagnostic): Info-Buttons mit Modal-Erklaerungen im Gehirn-Tab
Reusable Info-Modal-System: kleines (ℹ)-Button neben Ueberschriften, beim
Klick oeffnet ein Modal mit ausfuehrlicher Erklaerung. Fuer die 4 wichtigsten
Brain-Konzepte sind die Texte vor-definiert (INFO_TEXTS dict).
- Gehirn — Status online/offline, N Memories, Qdrant-Endpoint
- Konversation Rolling Window 50, Schwelle 60, Destillat-Logik,
Hinweis warum chat_backup ≠ conversation.jsonl
- Memories Hot vs. Cold, alle 8 Typen erklaert, semantische Suche
- Bootstrap Die drei Wege (Migration / Snapshot / Komplett-Gehirn)
Plus inline-ℹ-Button neben der "Konversation: N Turns"-Zeile in der
Status-Card, damit man dort wo's relevant ist sofort die Erklaerung findet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+102
-10
@@ -120,6 +120,16 @@
|
|||||||
/* Settings */
|
/* Settings */
|
||||||
.settings-section { margin-bottom:20px; }
|
.settings-section { margin-bottom:20px; }
|
||||||
.settings-section h2 { margin-bottom:12px; }
|
.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 { position:relative; width:40px; height:22px; flex-shrink:0; margin-left:8px; }
|
||||||
.toggle input { opacity:0; width:0; height:0; }
|
.toggle input { opacity:0; width:0; height:0; }
|
||||||
.toggle .slider { position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0;
|
.toggle .slider { position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0;
|
||||||
@@ -689,24 +699,22 @@
|
|||||||
<div id="tab-brain" class="main-tab">
|
<div id="tab-brain" class="main-tab">
|
||||||
|
|
||||||
<div class="settings-section">
|
<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 class="card">
|
||||||
<div id="brain-status" style="font-size:12px;color:#8888AA;margin-bottom:8px;">(Lade...)</div>
|
<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;">
|
<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="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="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="Leert ARIAs Rolling-Window (Brain) + die Chat-Anzeige (chat_backup). Memories bleiben in der Vector-DB.">🧹 Konversation komplett zurücksetzen</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 style="margin-top:6px;font-size:10px;color:#555570;line-height:1.5;">
|
|
||||||
<strong>Konversation zurücksetzen:</strong> leert ARIAs Rolling-Window (Brain "vergisst" die letzten Turns)
|
|
||||||
UND die Chat-Anzeige hier (<code>chat_backup.jsonl</code>). Destillierte Facts + restliche Memories bleiben.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-section">
|
<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;">
|
<div class="card" style="line-height:1.6;">
|
||||||
<p style="color:#8888AA;font-size:12px;margin:0 0 12px;">
|
<p style="color:#8888AA;font-size:12px;margin:0 0 12px;">
|
||||||
Drei Wege ARIA mit "Grundregeln" zu füttern — von leichtgewichtig bis Voll-Wiederherstellung.
|
Drei Wege ARIA mit "Grundregeln" zu füttern — von leichtgewichtig bis Voll-Wiederherstellung.
|
||||||
@@ -758,7 +766,7 @@
|
|||||||
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
|
<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>
|
<div>
|
||||||
<button class="btn secondary" onclick="resetBrainFilters();loadBrainMemoryList()" style="padding:4px 10px;font-size:11px;">Aktualisieren</button>
|
<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>
|
<button class="btn" onclick="openMemoryModal()" style="padding:4px 10px;font-size:11px;">+ Neu</button>
|
||||||
@@ -849,6 +857,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div><!-- /tab-skills -->
|
</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) -->
|
<!-- Memory-Modal (Neu + Editieren) -->
|
||||||
<div class="modal-overlay" id="memory-modal">
|
<div class="modal-overlay" id="memory-modal">
|
||||||
<div class="modal-box" style="max-width:640px;">
|
<div class="modal-box" style="max-width:640px;">
|
||||||
@@ -2876,14 +2895,15 @@
|
|||||||
// Conversation-Stats (separater Endpoint)
|
// Conversation-Stats (separater Endpoint)
|
||||||
const conv = document.getElementById('conversation-status');
|
const conv = document.getElementById('conversation-status');
|
||||||
if (!conv) return;
|
if (!conv) return;
|
||||||
|
const infoBtn = `<button class="info-btn-small" onclick="showInfo('conversation')" title="Konversation — wie funktioniert das?">ℹ</button>`;
|
||||||
try {
|
try {
|
||||||
const r2 = await fetch('/api/brain/conversation/stats');
|
const r2 = await fetch('/api/brain/conversation/stats');
|
||||||
if (!r2.ok) throw new Error('HTTP ' + r2.status);
|
if (!r2.ok) throw new Error('HTTP ' + r2.status);
|
||||||
const d2 = await r2.json();
|
const d2 = await r2.json();
|
||||||
const distillIcon = d2.needs_distill ? ' ⚠ Destillat bald fällig' : '';
|
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) {
|
} catch (e) {
|
||||||
conv.innerHTML = `Konversation: <span style="color:#555570;">${e.message}</span>`;
|
conv.innerHTML = `Konversation: <span style="color:#555570;">${e.message}</span> ${infoBtn}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3151,6 +3171,78 @@
|
|||||||
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
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() {
|
function brainExport() {
|
||||||
// Browser folgt der Download-Header-Antwort automatisch
|
// Browser folgt der Download-Header-Antwort automatisch
|
||||||
window.location.href = '/api/brain-export';
|
window.location.href = '/api/brain-export';
|
||||||
|
|||||||
Reference in New Issue
Block a user