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:
@@ -87,6 +87,14 @@ interface ChatMessage {
|
||||
fires_at?: string;
|
||||
condition?: string;
|
||||
};
|
||||
/** Memory-Saved-Bubble: ARIA hat etwas via memory_save in die Qdrant-DB gepackt */
|
||||
memorySaved?: {
|
||||
title: string;
|
||||
type: string;
|
||||
category?: string;
|
||||
pinned: boolean;
|
||||
preview?: string;
|
||||
};
|
||||
/** Backup-Timestamp aus chat_backup.jsonl auf dem Bridge — Voraussetzung
|
||||
* zum Loeschen der Bubble via Muelltonne. Lokale Bubbles ohne backupTs
|
||||
* sind noch nicht persistiert (kurzer Race) — Muelltonne erscheint erst
|
||||
@@ -467,6 +475,7 @@ const ChatScreen: React.FC = () => {
|
||||
const localOnly = prev.filter(m =>
|
||||
m.skillCreated ||
|
||||
m.triggerCreated ||
|
||||
m.memorySaved ||
|
||||
(m.audioRequestId && (!m.text || m.text === '🎙 Aufnahme...' || m.text === 'Aufnahme...'))
|
||||
);
|
||||
// Server-Stand + lokal-only (chronologisch sortiert)
|
||||
@@ -521,6 +530,27 @@ const ChatScreen: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// memory_saved: ARIA hat etwas via memory_save Tool in die Qdrant-DB
|
||||
// gepackt — eigene Bubble (gelb wie trigger/skill).
|
||||
if (message.type === 'memory_saved') {
|
||||
const p = (message.payload || {}) as any;
|
||||
const memoryMsg: ChatMessage = {
|
||||
id: nextId(),
|
||||
sender: 'aria',
|
||||
text: '',
|
||||
timestamp: Date.now(),
|
||||
memorySaved: {
|
||||
title: String(p.title || '(ohne Titel)'),
|
||||
type: String(p.type || 'fact'),
|
||||
category: p.category ? String(p.category) : undefined,
|
||||
pinned: !!p.pinned,
|
||||
preview: p.content_preview ? String(p.content_preview) : undefined,
|
||||
},
|
||||
};
|
||||
setMessages(prev => capMessages([...prev, memoryMsg]));
|
||||
return;
|
||||
}
|
||||
|
||||
// file_deleted: Datei wurde geloescht (vom Diagnostic User) → Bubble updaten
|
||||
if (message.type === 'file_deleted') {
|
||||
const p = (message.payload?.path as string) || '';
|
||||
@@ -1253,6 +1283,27 @@ const ChatScreen: React.FC = () => {
|
||||
? { borderWidth: 2, borderColor: '#FFD60A' }
|
||||
: null;
|
||||
|
||||
// Spezial-Bubble: ARIA hat etwas via memory_save gespeichert
|
||||
if (item.memorySaved) {
|
||||
const m = item.memorySaved;
|
||||
const catPart = m.category ? ` · [${m.category}]` : '';
|
||||
return (
|
||||
<View style={[styles.messageBubble, styles.ariaBubble, {borderLeftWidth: 3, borderLeftColor: '#FFD60A'}, searchHighlightStyle]}>
|
||||
<Text style={{color: '#FFD60A', fontWeight: 'bold', fontSize: 14}}>
|
||||
{'🧠 ARIA hat etwas gemerkt'}
|
||||
</Text>
|
||||
<Text style={{color: '#E0E0F0', marginTop: 4, fontSize: 14}}>
|
||||
<Text style={{fontWeight: 'bold'}}>{m.title}</Text>
|
||||
<Text style={{color: '#8888AA', fontSize: 12}}>{` (${m.type}${m.pinned ? ' · 📌 pinned' : ''}${catPart})`}</Text>
|
||||
</Text>
|
||||
{m.preview ? (
|
||||
<Text style={{color: '#888', fontSize: 12, marginTop: 4}}>{m.preview}{m.preview.length >= 140 ? '…' : ''}</Text>
|
||||
) : null}
|
||||
<Text style={{color: '#555570', fontSize: 10, marginTop: 6}}>ARIA-Memory · {time}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// Spezial-Bubble: ARIA hat einen Trigger angelegt
|
||||
if (item.triggerCreated) {
|
||||
const t = item.triggerCreated;
|
||||
|
||||
Reference in New Issue
Block a user