feat(brain): memory_save Tool — ARIA schreibt selber in die Qdrant-DB
ARIA hatte bisher KEIN Tool um eigene Notizen sauber zu persistieren — sie ist deshalb aufs Claude-Code-File-Memory ausgewichen (das wir mit dem letzten Commit per tmpfs abgeklemmt haben). Jetzt schliesst sich der Loop: ein echtes memory_save-Tool gegen die Qdrant-DB. Brain: - agent.py: memory_save als Meta-Tool mit Schema (title, content, type, optional category/tags/pinned). Tool-Description erklaert die Type-Wahl (identity/rule/preference/tool/skill = pinned, fact/conversation/reminder = cold) und sagt explizit: "Du hast KEIN File-Memory mehr, schreibe nicht in ~/.claude/projects/..." - Dispatcher: validiert type-enum, ruft self.embedder.embed + self.store.upsert, pushed memory_saved als _pending_events damit Bridge eine Bubble broadcasten kann. Side-Channel-Pipeline (gleich wie skill_created/trigger_created): - Bridge send_to_core + _handle_trigger_fired: forwarden memory_saved als RVS-Event - rvs/server.js: ALLOWED_TYPES += memory_saved - diagnostic/server.js: relayed memory_saved von RVS an Browser - diagnostic UI: addMemorySavedBubble (gelber Border) + Auto-Refresh des Gehirn-Tabs wenn aktiv - android: ChatMessage.memorySaved-Feld, Listener fuer memory_saved, renderMessage-Spezialbubble, History-Replace-Schutz (lokal-only) Damit ist die Architektur konsistent: "merk dir X" → ARIA ruft memory_save → Eintrag in Qdrant → Diagnostic-Gehirn-Tab zeigt's sofort → bei naechstem Turn liefert Cold Memory (Semantic Search) das Wissen wieder rein. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1383,6 +1383,14 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'memory_saved') {
|
||||
addMemorySavedBubble(msg.payload || {});
|
||||
// Falls Gehirn-Tab offen: refreshen
|
||||
if (document.getElementById('tab-brain') && document.getElementById('tab-brain').classList.contains('visible')) {
|
||||
loadBrainMemoryList();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'chat_delta') { return; }
|
||||
if (msg.type === 'chat_error') {
|
||||
addChat('error', msg.error, 'chat:error');
|
||||
@@ -1976,6 +1984,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** ARIA hat eine Memory in die Qdrant-DB gespeichert — als Bubble anzeigen. */
|
||||
function addMemorySavedBubble(memory) {
|
||||
const title = memory.title || '(ohne Titel)';
|
||||
const type = memory.type || 'fact';
|
||||
const cat = memory.category || '';
|
||||
const pinned = !!memory.pinned;
|
||||
const preview = memory.content_preview || '';
|
||||
const typeLabel = (typeof BRAIN_TYPE_LABELS !== 'undefined' && BRAIN_TYPE_LABELS[type]) || type;
|
||||
const pinBadge = pinned ? '<span style="color:#FFD60A;font-size:11px;margin-left:6px;">📌 pinned</span>' : '';
|
||||
const catBadge = cat ? ` <span style="color:#555570;font-size:10px;">[${escapeHtml(cat)}]</span>` : '';
|
||||
const html = `
|
||||
<div style="font-weight:bold;color:#FFD60A;">🧠 ARIA hat etwas gemerkt</div>
|
||||
<div style="margin-top:4px;color:#E0E0F0;">
|
||||
<strong>${escapeHtml(title)}</strong>
|
||||
<span style="color:#8888AA;font-size:11px;margin-left:6px;">(${escapeHtml(typeLabel)})</span>
|
||||
${pinBadge}${catBadge}
|
||||
</div>
|
||||
${preview ? `<div style="color:#8888AA;font-size:12px;margin-top:2px;">${escapeHtml(preview)}${preview.length >= 140 ? '…' : ''}</div>` : ''}
|
||||
<div class="meta">
|
||||
ARIA-Memory — ${new Date().toLocaleTimeString('de-DE')} ·
|
||||
<a href="#" onclick="event.preventDefault();switchMainTab('brain');" style="color:#FFD60A;">im Gehirn-Tab ansehen</a>
|
||||
</div>`;
|
||||
for (const box of [chatBox, document.getElementById('chat-box-fs')]) {
|
||||
if (!box) continue;
|
||||
const el = document.createElement('div');
|
||||
el.className = 'chat-msg received';
|
||||
el.style.borderLeft = '3px solid #FFD60A';
|
||||
el.innerHTML = html;
|
||||
box.appendChild(el);
|
||||
box.scrollTop = box.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/** Wenn der Server file_deleted broadcastet: alle Bubbles mit
|
||||
diesem serverPath rerendern als "geloescht" markieren. */
|
||||
function markFileDeletedInChat(serverPath) {
|
||||
|
||||
@@ -617,6 +617,11 @@ function connectRVS(forcePlain) {
|
||||
// Mode-Broadcast von der Bridge → an Browser-Clients weiterreichen
|
||||
log("info", "rvs", `Mode-Broadcast: ${msg.payload?.mode} (${msg.payload?.name})`);
|
||||
broadcast({ type: "mode", payload: msg.payload });
|
||||
} else if (msg.type === "memory_saved") {
|
||||
// ARIA hat selber etwas in die Qdrant-DB gespeichert (via memory_save Tool).
|
||||
const m = msg.payload || {};
|
||||
log("info", "rvs", `ARIA-Memory gespeichert: "${m.title}" (type=${m.type}, pinned=${m.pinned})`);
|
||||
broadcast({ type: "memory_saved", payload: m });
|
||||
} else if (msg.type === "chat_message_deleted") {
|
||||
// Bridge meldet: Bubble wurde aus chat_backup + Brain entfernt.
|
||||
// An Browser-Clients weiterreichen damit sie die Bubble lokal entfernen.
|
||||
|
||||
Reference in New Issue
Block a user