From 517bc7ca8e9f1ef0cd12db0f9fffda9c0f58aa49 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Tue, 12 May 2026 15:01:28 +0200 Subject: [PATCH] =?UTF-8?q?feat(diag):=20Gehirn-Tab=20=E2=80=94=20klappbar?= =?UTF-8?q?e=20Type-Header=20+=20Category-AutoSuggest=20+=20Info-Modal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UX im Memory-Browser geschaerft, Stefan-Wunsch: 1. Klappbare Type-Gruppen: Jeder Type-Header (Identität, Regeln, ...) hat jetzt einen ▼/▶ Indikator und reagiert auf Click. Eingeklappte Sektionen werden in localStorage gemerkt — bleiben ueber Reloads stabil. 2. Category-AutoSuggest: Das Kategorie-Feld im Neu/Edit-Modal hat jetzt ein mit allen schon in der DB existierenden Categories als Vorschlag. Neue Categories sind weiterhin frei eintippbar. Liste wird bei jedem renderBrainList-Aufruf aus dem Cache aktualisiert. 3. Info-Button (ℹ) neben dem Typ-Dropdown: Erklaert welche Types FEST im System-Prompt eine eigene Sektion bekommen (identity/rule/preference/tool/skill — Hot Memory) und welche nur via semantischer Cold-Search reinkommen (fact/ conversation/reminder). Konsistent mit prompts.py:TYPE_HEADINGS. Auch dokumentiert dass Category ein freier Tag ist und den Prompt nicht direkt beeinflusst. Type-Dropdown-Labels selbst zeigen jetzt (FEST) / (Cold) als Hinweis. Co-Authored-By: Claude Opus 4.7 (1M context) --- diagnostic/index.html | 116 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 15 deletions(-) diff --git a/diagnostic/index.html b/diagnostic/index.html index de20a27..3af9d85 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -988,23 +988,27 @@ `; } + function _brainTypeHeading(t, count) { + const collapsed = brainCollapsedTypes.has(t); + const arrow = collapsed ? '▶' : '▼'; + const label = BRAIN_TYPE_LABELS[t] || t; + // onclick wirft das Klappen-Event; user-select:none damit das Toggle nicht Text markiert + return `
+ ${arrow} + ${escapeHtml(label)} (${count}) +
`; + } + function renderBrainList(items, isSearchResult) { const el = document.getElementById('brain-memory-list'); if (!el) return; + + // Auto-Suggest-Datalist mit allen existierenden Categories aktualisieren + _updateCategoryDatalist(items); + if (isSearchResult) { // Such-Treffer: in Aehnlichkeits-Reihenfolge, kein Type-Gruppieren const html = items.map(m => renderMemoryRow(m, true)).join(''); el.innerHTML = html || '(Keine Treffer)'; return; } - // Normale Liste: nach Type gruppieren + // Normale Liste: nach Type gruppieren, Header klappbar const byType = {}; items.forEach(m => { (byType[m.type] = byType[m.type] || []).push(m); }); const html = BRAIN_TYPE_ORDER.flatMap(t => { if (!byType[t]) return []; - const heading = `
${BRAIN_TYPE_LABELS[t] || t} (${byType[t].length})
`; + const heading = _brainTypeHeading(t, byType[t].length); + if (brainCollapsedTypes.has(t)) return [heading]; const rows = byType[t].map(m => renderMemoryRow(m, false)).join(''); return [heading, rows]; }).join(''); @@ -3505,12 +3575,28 @@ const extraTypes = Object.keys(byType).filter(t => !BRAIN_TYPE_ORDER.includes(t)); let extra = ''; for (const t of extraTypes) { - extra += `
${escapeHtml(t)} (${byType[t].length})
`; - extra += byType[t].map(m => renderMemoryRow(m, false)).join(''); + extra += _brainTypeHeading(t, byType[t].length); + if (!brainCollapsedTypes.has(t)) { + extra += byType[t].map(m => renderMemoryRow(m, false)).join(''); + } } el.innerHTML = (html + extra) || '(Keine bekannten Typen gefunden)'; } + function _updateCategoryDatalist(items) { + const dl = document.getElementById('memory-category-suggestions'); + if (!dl) return; + const set = new Set(); + // Aus dem Cache UND aus den uebergebenen items beziehen — der Cache + // kann Such-Treffer enthalten, items kann ein gefilteter View sein. + Object.values(brainMemoryCache).concat(items || []).forEach(m => { + if (m && m.category && typeof m.category === 'string') set.add(m.category.trim()); + }); + const opts = Array.from(set).filter(Boolean).sort().map(c => + `