# Enhanced Memory V2 - Analisi e Progettazione

## Stato: FASE 2 - Analisi e Proposta completata

---

## 1. DECISIONI PRESE

| Domanda | Risposta |
|---------|----------|
| **Privacy** | Backend PUÒ processare plaintext in-memory per estrazione. NO persistenza plaintext |
| **SaaS vs In-House** | **Solo in-house**. Nessuna dipendenza Supermemory API |
| **Feature target** | Graph Memory, Contradiction Resolution, Forgetting/Decay, User Profiles, LLM Episode Summarization |
| **Scala utenti** | < 100 (early stage) |
| **Budget LLM** | **Minimizzare**. Preferire modelli piccoli/euristiche dove possibile |
| **Semantic search** | NON richiesta in questa fase (keyword fallback accettato per ora) |

---

## 2. IMPLEMENTAZIONE ATTUALE (AdiuvAI)

### Architettura Memoria (MemGPT-style, 4 livelli)

| Livello | Tabella | Stato |
|---------|---------|-------|
| **Core** | `memory_core` | Funzionante - key/value preferenze |
| **Associativa** | `memory_associative` | Parziale - keyword fallback, no semantic |
| **Episodica** | `memory_episodic` | Funzionante - troncamento 200 char |
| **Proattiva** | `memory_proactive` | Schema vuoto, nessuna logica |

### Punti di Forza
- E2E encryption per-user (Fernet)
- 9 tool agente per memoria
- Context injection automatica pre-LLM
- Episodi auto-salvati post-conversazione

### Gap vs Supermemory (ciò che manca)
1. Nessuna estrazione automatica di fatti dalle conversazioni
2. Nessuna relazione tra memorie (graph UPDATE/EXTEND/DERIVE)
3. Nessun forgetting/decay temporale
4. Nessuna risoluzione contraddizioni
5. Nessun user profile auto-generato
6. Episodi troncati a 200 char senza summarization
7. Proactive memory non implementata

### IL PROBLEMA CENTRALE: context selection cieca
Il metodo `_load_associative()` fa:
```python
SELECT * FROM memory_associative
WHERE user_id = ?
ORDER BY updated_at DESC   ← ordina per DATA, non per rilevanza
LIMIT 5
```
**Il messaggio dell'utente NON viene usato per filtrare.** Ritorna i 5 fatti più recenti,
anche se totalmente irrilevanti alla domanda. Lo stesso per episodic (ultimi 10 per data).

---

## 3. COME SUPERMEMORY SALVA I DATI (non usa MD!)

### Chiarimento: Supermemory NON salva file MD
Supermemory accetta MD come formato di input (insieme a PDF, JSON, codice, ecc.),
ma i dati vengono trasformati e salvati in **PostgreSQL + vector embeddings (Cloudflare AI)**.

### Schema di storage Supermemory (da codice sorgente)
```
Documents table (Drizzle ORM + Postgres)
├── id, customId, orgId, userId
├── content         ← raw content originale
├── title, summary  ← generati da LLM
├── type            ← 'text' | 'web' | 'pdf' | 'md' | ecc.
├── status          ← 'queued' | 'extracting' | 'chunking' | 'embedding' | 'done'
├── metadata        ← JSON key/value filtrabile
├── tokenCount, wordCount, chunkCount
├── summaryEmbedding (vector)
├── containerTags[] ← namespace isolation (user_id, project_id)
└── createdAt, updatedAt

MemoryEntries table (fatti estratti)
├── id, memory      ← il fatto estratto ("Mario preferisce risposte concise")
├── version         ← numero di versione del fatto
├── context
│   ├── parents[]   ← [{relation: 'updates'|'extends'|'derives', memory, version}]
│   └── children[]  ← [{relation, memory, version}]
├── similarity      ← score di ricerca
├── metadata
├── sourceDocumentId ← da quale documento è stato estratto
└── updatedAt
```

### Come AdiuvAI salva i dati (confronto)
```
memory_core (PostgreSQL)
├── key, value_encrypted  ← Fernet AES-128
└── user_id

memory_associative (PostgreSQL + pgvector)
├── content_encrypted     ← cifrato
├── embedding (1536-dim)  ← colonna presente ma MAI usata per search
├── entity_type, entity_id
└── user_id

memory_episodic (PostgreSQL)
├── summary_encrypted     ← "User: [200 char]\nAssistant: [200 char]"
├── session_id
└── user_id

memory_proactive (PostgreSQL)
├── pattern_encrypted, confidence ← schema vuoto, nessun dato
└── user_id
```

### Differenza chiave nel salvataggio
| | Supermemory | AdiuvAI |
|---|-----------|--------|
| **Cosa salva** | Fatti strutturati estratti da LLM | Testo grezzo cifrato |
| **Relazioni** | Graph con UPDATE/EXTEND/DERIVE + versioning | Nessuna relazione |
| **Embeddings** | Generati e usati attivamente per search | Colonna presente ma inutilizzata |
| **Encryption** | Nessuna (plaintext) | Fernet per-user |
| **Processing** | Pipeline: Extract → Chunk → Embed → Index | Store diretto senza processing |

---

## 4. SUPERMEMORY - Cosa Prendere Come Ispirazione

> **NON integriamo Supermemory SaaS.** Ci ispiriamo al design per implementare in-house.

### Concetti da adottare
1. **Relazioni tra memorie**: UPDATE (sostituisce), EXTEND (arricchisce), DERIVE (inferisce)
2. **isLatest flag**: tracciamento della versione corrente di un fatto
3. **Automatic forgetting**: fatti temporali con `expires_at`, episodi che decadono
4. **User Profile duale**: `static` (fatti stabili) + `dynamic` (attività recente)
5. **Fact extraction post-conversazione**: LLM estrae fatti strutturati dopo ogni chat

### Concetti da NON adottare (non rilevanti)
- Connectors (Google Drive, Gmail, etc.) — AdiuvAI è un'app desktop, non un aggregatore
- Multi-modal extraction (PDF, video) — fuori scope
- Hybrid RAG+Memory search — non richiesto ora

---

## 4. ANALISI COSTI/BENEFICI - OPZIONI

### OPZIONE SCARTATA: Supermemory SaaS Integration

| | Dettaglio |
|---|----------|
| **Costo** | $0-19/mo per <100 utenti (Free/Pro) |
| **Pro** | Implementazione rapida, SOTA benchmarks |
| **Contro Fatali** | Viola privacy (plaintext obbligatorio), vendor lock-in, latenza API esterna, architettura Cloudflare Workers non self-hostabile facilmente |
| **Verdetto** | **SCARTATA** — incompatibile con zero-trust e preferenza in-house |

### OPZIONE SCELTA: Enhancement In-House Ispirato a Supermemory

**Approccio**: evoluzione incrementale dell'architettura esistente in 4 fasi.

---

## 5. PIANO DI IMPLEMENTAZIONE PROPOSTO

### FASE 1 — Memory Graph + Contradiction Resolution
**Effort**: ~3-5 giorni | **Costo LLM extra**: ~$0.002/conversazione (GPT-4o-mini)

**Cosa cambia nel DB:**
- Nuova tabella `memory_fact` (sostituisce progressivamente `memory_associative`)
  ```
  memory_fact:
    id, user_id
    content_encrypted    -- il fatto estratto, cifrato
    category             -- 'preference' | 'fact' | 'episode' | 'goal' | 'relationship'
    entity_type          -- a cosa si riferisce: 'user' | 'project' | 'task' | 'person'
    entity_id            -- opzionale, FK
    is_latest            -- boolean, come Supermemory
    superseded_by_id     -- FK → memory_fact (relazione UPDATE)
    extends_id           -- FK → memory_fact (relazione EXTEND)
    derived_from_ids     -- JSON array di FK (relazione DERIVE)
    confidence           -- 0.0-1.0
    source               -- 'extracted' | 'explicit' | 'inferred'
    expires_at           -- nullable, per fatti temporali
    last_accessed_at     -- per decay scoring
    created_at, updated_at
  ```

**Come funziona:**
1. Post-conversazione, GPT-4o-mini riceve transcript (ultimi 2000 char) + prompt strutturato
2. LLM estrae JSON array di fatti: `[{content, category, entity_type, is_temporal, expires_at}]`
3. Per ogni fatto estratto, sistema verifica con fatti esistenti (keyword match su decrypt in-memory)
4. Se contraddizione trovata → vecchio fatto `is_latest=false`, `superseded_by_id=nuovo`
5. Se arricchimento → nuovo fatto ha `extends_id=vecchio`
6. Tutto cifrato prima di persistenza

**Stima costi LLM (GPT-4o-mini @ $0.15/1M input, $0.60/1M output):**
- Input: ~2500 tokens/conversazione (transcript + system prompt)
- Output: ~300 tokens (JSON fatti estratti)
- Costo: ~$0.0006/conversazione → **~$0.06 per 100 conversazioni/giorno**

---

### FASE 2 — Automatic Forgetting + Decay
**Effort**: ~1-2 giorni | **Costo LLM extra**: $0 (puro heuristico)

**Meccanismi:**
1. **TTL-based expiry**: fatti con `expires_at` vengono ignorati dopo la data
2. **Access decay**: `last_accessed_at` + scoring formula: `score = confidence * (1 / (1 + days_since_access * 0.05))`
3. **Background cleanup** (cron/periodic): soft-delete fatti con score < 0.1 da >30 giorni
4. **Episodic consolidation**: dopo N episodi per sessione, consolida in un singolo summary

**Nessun costo LLM** — pura logica temporale e scoring matematico.

---

### FASE 3 — User Profile Auto-Generato
**Effort**: ~2-3 giorni | **Costo LLM extra**: ~$0.001/aggiornamento

**Come funziona:**
1. Nuova mini-tabella `user_profile`:
   ```
   user_profile:
     user_id (PK)
     static_encrypted   -- JSON: fatti stabili (nome, ruolo, preferenze durature)
     dynamic_encrypted  -- JSON: attività recente (ultimi 3-5 topic, task in corso)
     updated_at
   ```
2. Dopo ogni estrazione fatti (Fase 1), profilo viene aggiornato:
   - `static`: fatti con `category IN ('preference', 'fact', 'relationship')` e `confidence > 0.7`
   - `dynamic`: ultimi 5 fatti con `category = 'goal'` o episodi recenti
3. Profilo iniettato nel system prompt a OGNI conversazione (prima del context attuale)
4. Aggiornamento trigger: post-extraction, batch di fatti nuovi → GPT-4o-mini "aggiorna profilo"

**Stima costi:**
- Input: ~1000 tokens (profilo attuale + nuovi fatti)
- Output: ~500 tokens (profilo aggiornato)
- Costo: ~$0.0005/aggiornamento → **trascurabile**

**Alternativa zero-costo LLM:** il profilo `static` è calcolato come aggregazione diretta dei fatti con `is_latest=true` + alta confidence. Il `dynamic` è gli ultimi N episodi. Nessuna LLM call, solo query SQL. Meno elegante ma $0.

---

### FASE 4 — LLM Episode Summarization
**Effort**: ~1-2 giorni | **Costo LLM extra**: ~$0.001/episodio

**Cosa cambia:**
- Il campo `summary_encrypted` in `memory_episodic` passa da troncamento 200 char a summary LLM
- GPT-4o-mini genera un riassunto strutturato: `{topic, user_intent, outcome, key_facts_mentioned}`
- Async: non blocca la risposta. Avviene dopo che la risposta è già stata inviata al client

**Stima costi:**
- Input: ~1500 tokens (conversazione completa)
- Output: ~200 tokens (summary strutturato)
- Costo: ~$0.0004/episodio → **~$0.04 per 100 conversazioni/giorno**

---

## 6. RIEPILOGO COSTI TOTALI

### Costi LLM aggiuntivi stimati (< 100 utenti, ~100 conversazioni/giorno)

| Fase | Costo/conv | Costo/giorno | Costo/mese |
|------|------------|--------------|------------|
| Fase 1 (Fact Extraction) | $0.0006 | $0.06 | ~$1.80 |
| Fase 2 (Forgetting) | $0 | $0 | $0 |
| Fase 3 (User Profile) | $0-0.0005 | $0-0.05 | $0-1.50 |
| Fase 4 (Episode Summary) | $0.0004 | $0.04 | ~$1.20 |
| **TOTALE** | **~$0.001-0.002** | **~$0.10-0.15** | **~$3-4.50** |

### Confronto con Supermemory SaaS
| | In-House | Supermemory Free | Supermemory Pro |
|---|---------|------------------|-----------------|
| Costo/mese | ~$3-4.50 (LLM) | $0 (ma limiti) | $19/mo |
| Privacy | E2E mantenuta | Plaintext obbligatorio | Plaintext obbligatorio |
| Limiti | Solo LLM rate limits | 1M tokens, 10K search | 3M tokens, 100K search |
| Personalizzazione | Totale | Nessuna | Nessuna |
| Vendor lock-in | Zero | Alto | Alto |

**Verdetto**: l'implementazione in-house costa meno di $5/mese, mantiene la privacy, e offre personalizzazione totale.

---

## 7. MATRICE BENEFICI

| Feature | Impatto UX | Effort | Priorità |
|---------|-----------|--------|----------|
| Fact Extraction + Graph | ALTO - l'AI ricorda tutto automaticamente | Medio | P0 |
| Contradiction Resolution | ALTO - niente informazioni obsolete | Basso (incluso in P0) | P0 |
| Automatic Forgetting | MEDIO - meno noise nel context | Basso | P1 |
| User Profile | ALTO - personalizzazione immediata | Medio | P1 |
| Episode Summarization | MEDIO - recall migliore | Basso | P2 |

---

## 8. ANALISI CRITICA: COME SUPERMEMORY INIETTA IL CONTESTO

### Il flusso Supermemory (Python SDK)

```python
from supermemory import Supermemory
client = Supermemory()  # richiede SUPERMEMORY_API_KEY

# ── PRE-LLM: recupera profilo + memorie rilevanti ──
profile = client.profile(
    container_tag="user_123",       # = user_id di AdiuvAI
    q="What sneakers should I buy?" # = il messaggio dell'utente
)

# profile.profile.static  → ["Senior engineer at Acme", "Prefers dark mode"]
# profile.profile.dynamic → ["Working on auth migration"]
# profile.search_results  → memorie rilevanti per la query

# ── Assemblaggio system prompt ──
context = f"""Static profile:
{chr(10).join(profile.profile.static)}

Dynamic profile:
{chr(10).join(profile.profile.dynamic)}

Relevant memories:
{chr(10).join(r.get("memory","") for r in profile.search_results.results)}"""

messages = [{"role": "system", "content": f"User context:\n{context}"}, *conversation]
# → passa al tuo LLM

# ── POST-LLM: salva conversazione (Supermemory estrae fatti automaticamente) ──
client.add(
    content="\n".join(f"{m['role']}: {m['content']}" for m in conversation),
    container_tag="user_123",
)
```

### Cosa succede sotto: `client.add()` → HTTPS → Supermemory cloud

1. Supermemory riceve il **plaintext completo** della conversazione
2. Il **loro LLM** estrae fatti, preferenze, entità
3. Costruisce relazioni graph (UPDATE/EXTEND/DERIVE) con fatti esistenti
4. Aggiorna il profilo utente (static + dynamic)
5. Applica forgetting su fatti temporali scaduti

### Come si confronta con il tuo `enrich_context()`:

| Aspetto | AdiuvAI (attuale) | Supermemory |
|---------|-----------------|-------------|
| **Dove vive la logica** | `memory_middleware.py` nel tuo backend | Cloud di terzi |
| **Come recupera contesto** | 4 query SQL → decrypt in-memory | 1 HTTPS call `client.profile()` |
| **Qualità contesto** | Raw key/value + troncamenti 200 char | Fatti strutturati + profilo curato |
| **Chi estrae fatti** | Nessuno (o l'utente via tool) | LLM automatico su ogni `add()` |
| **Latenza retrieval** | ~5-15ms (DB locale) | ~50-200ms (HTTPS) |
| **Latenza storage** | ~2ms (INSERT SQL) | ~200-500ms (HTTPS + LLM extraction) |
| **Privacy** | Plaintext solo in-memory, cifrato a riposo | **Plaintext permanente su server terzi** |

---

## 9. VALUTAZIONE CRITICA ONESTA

### BENEFICI REALI dell'integrazione Supermemory

1. **Extraction automatica** — Non dover fare nulla: `client.add(conversation)` e i fatti vengono estratti. Risparmi ~3-5 giorni dev della Fase 1.

2. **Contradiction resolution SOTA** — Il loro graph engine è #1 sui benchmark. Implementarlo in-house richiede un LLM prompt ben ingegnerizzato + logica di matching.

3. **User Profiles pronti** — `client.profile()` restituisce static+dynamic in ~50ms. In-house devi costruire la logica di aggregazione.

4. **Temporal forgetting** — Gestiscono scadenza e noise filtering. In-house è semplice (TTL + cron) ma loro lo fanno meglio con LLM.

### PROBLEMI CRITICI dell'integrazione

1. **PRIVACY DISTRUTTA** — Il punto più grave. Tutto il modello E2E di AdiuvAI si basa su: "il backend non persiste mai plaintext". Supermemory riceve e **tiene** tutti i dati utente in chiaro. Per un'app che vende privacy, è un dealbreaker.

2. **LATENZA AGGIUNTA** — Ogni conversazione aggiunge:
   - +50-200ms PRE-LLM (profile fetch via HTTPS)
   - +200-500ms POST-LLM (add + extraction)
   - vs. ~5-15ms totali con DB locale
   - Su connessione instabile: timeout → memoria persa

3. **SINGLE POINT OF FAILURE** — Se `supermemory.ai` è down, la tua app perde TUTTA la memoria. Non ha fallback locale. Le tue 4 tabelle PostgreSQL attuali sono resilienti.

4. **VENDOR LOCK-IN** — I fatti estratti vivono nel loro cloud. Se chiudono, cambi pricing, o limiti free tier → migrazione dolorosa. Con la soluzione in-house hai ownership totale.

5. **COSTI CHE SCALANO MALE** — Free tier: 1M tokens/mese = ~250 conversazioni medie. Con 100 utenti attivi: 
   - ~30 conv/utente/mese = 3000 conv = ~12M tokens → **Scale plan $399/mo**
   - In-house: $3-5/mo per le stesse 3000 conv con GPT-4o-mini

6. **ARCHITETTURA OVERHAUL** — Devi:
   - Rimuovere/sostituire le 4 tabelle memory
   - Riscrivere i 9 tool dell'agente per usare l'SDK
   - Rimuovere la logica di encryption
   - Cambiare il contratto WebSocket (se i tool memory cambiano)
   - **Effort paradossale**: più lavoro per integrare che per migliorare in-house

7. **NON SELF-HOSTABILE** — Il repo GitHub è MIT ma il core è Cloudflare Workers + KV + Postgres. Self-hosting richiede Cloudflare infra o riscrittura significativa.

### BILANCIO FINALE

| Pro | Peso |
|-----|------|
| Extraction + Graph + Forgetting gratis | ★★★★ |
| User profiles automatici | ★★★ |
| Zero dev effort per le feature memory | ★★★ |
| **Totale Pro** | **10/15** |

| Contro | Peso |
|--------|------|
| Privacy distrutta (dealbreaker per il brand) | ★★★★★ |
| Vendor lock-in su funzionalità core | ★★★★ |
| Costi $399/mo a regime vs $5/mo in-house | ★★★★ |
| Latenza +200-700ms per conversazione | ★★★ |
| Single point of failure | ★★★ |
| **Totale Contro** | **19/25** |

> **Verdetto: l'integrazione Supermemory SaaS è netta-negativa per AdiuvAI.**
> I benefici (extraction, graph, profiles) sono replicabili in-house a costo inferiore,
> senza sacrificare privacy, ownership e resilienza.

---

## 10. PROSSIMI PASSI
- [ ] Approvazione piano di miglioramento in-house (4 fasi)
- [ ] Design schema migration per `memory_fact` e `user_profile`
- [ ] Implementazione Fase 1 (fact extraction + graph)
- [ ] Test extraction con conversazioni reali
- [ ] Implementazione Fasi 2-4 incrementalmente
