Tipos de Memoria: Curta, Longa, Episodica, Semantica
Entenda cada tipo, quando usar, e como eles se complementam num agente de producao
Memoria e o que separa um chatbot descartavel de um assistente que realmente conhece o usuario. Sem memoria, cada conversa comeca do zero. O usuario repete preferencias, contexto se perde, e o agente nunca evolui. Um sistema de memoria bem desenhado transforma a experiencia de "falar com uma maquina" para "falar com alguem que te conhece".
Existem quatro tipos fundamentais de memoria para agentes de IA, cada um servindo um proposito diferente. A chave e entender quando usar cada um e como combiná-los para criar agentes que aprendem e se adaptam com o tempo.
📊 Os 4 Tipos de Memoria
Context window do LLM. Dura uma sessao. Inclui as mensagens da conversa atual. Volatil: some ao encerrar.
Persiste entre sessoes. Preferencias do usuario, configuracoes, historico de decisoes. Armazenada em banco de dados.
Eventos passados especificos: "na terça o usuario pediu relatorio em PDF e preferiu formato paisagem". Fatos pontuais recuperaveis.
Conhecimento geral acumulado: "usuario trabalha com marketing, usa Next.js, prefere tom tecnico". Perfil que evolui.
Comparacao Detalhada
| Tipo | Duracao | Storage | Exemplo |
|---|---|---|---|
| Short-term | 1 sessao | Context window | "Estamos falando sobre o modulo de pagamentos" |
| Long-term | Indefinida | DB / arquivo | "Usuario prefere respostas curtas e diretas" |
| Episodica | Indefinida | DB com timestamp | "Em 05/03 usuario mudou stack de React para Svelte" |
| Semantica | Indefinida | Vector store / DB | "Usuario e dev fullstack com foco em SaaS B2B" |
Quando Usar Cada Tipo
Short-term: Toda conversa
E automatica: as mensagens na context window sao a short-term memory. O desafio e quando a conversa fica grande demais e voce precisa comprimir ou sumarizar (veremos no topico 5).
Long-term: Preferencias e configuracoes
Use para tudo que o usuario so deveria dizer uma vez: idioma preferido, formato de resposta, timezone, stack tecnologica, nome do projeto. Persiste entre sessoes, carregado no system prompt.
Episodica: Fatos com data e contexto
Para eventos que tem relevancia temporal: "deploy falhou em 03/03", "usuario cancelou feature X na sprint passada". Util para agentes que precisam de historico de acoes.
Semantica: Knowledge base do usuario
Para busca por similaridade: "o que esse usuario sabe sobre Docker?" ou "quais decisoes de arquitetura ja foram tomadas?". Embeddings + vector store brilham aqui.
💡 Dica
Nao tente implementar os 4 tipos de uma vez. Comece com short-term (ja vem gratis) + long-term (um JSON ou tabela SQLite com preferencias). Adicione episodica quando precisar de historico, e semantica quando o volume de conhecimento justificar embeddings.
Fazer
- ●Mapear quais informacoes seu agente precisa lembrar entre sessoes
- ●Categorizar memorias por tipo para facilitar retrieval
- ●Testar com cenarios reais: usuario volta 3 dias depois, o agente lembra?
Evitar
- ●Guardar tudo indiscriminadamente (vira ruido que prejudica o agente)
- ●Confundir short-term com long-term (sessao vs persistente)
- ●Injetar toda a memoria no prompt sem curadoria (estoura context)
Implementacoes Praticas de Memoria
SQLite, vector stores, markdown files - escolha a ferramenta certa pro seu caso
A teoria dos 4 tipos de memoria e util, mas o que importa e como voce implementa na pratica. A boa noticia: voce nao precisa de infraestrutura complexa. Um arquivo SQLite resolve 80% dos casos. Para busca semantica, pgvector ou Pinecone adicionam similaridade sem muita complexidade. E para agentes pessoais, um simples arquivo markdown (como CLAUDE.md) pode ser suficiente.
SQLite para Memoria Estruturada
A abordagem mais pratica e robusta para comecar. Zero infraestrutura, um unico arquivo, queries SQL poderosas.
-- Tabela de memorias com tipos e relevancia
CREATE TABLE memories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tenant_id TEXT NOT NULL,
content TEXT NOT NULL,
memory_type TEXT NOT NULL, -- 'preference', 'episodic', 'semantic'
salience REAL DEFAULT 1.0, -- 0.0 a 5.0 (maior = mais relevante)
created_at INTEGER NOT NULL,
accessed_at INTEGER NOT NULL,
access_count INTEGER DEFAULT 0
);
-- Indice para busca rapida por tenant + tipo
CREATE INDEX idx_memories_tenant_type
ON memories(tenant_id, memory_type);
-- Inserir uma memoria
INSERT INTO memories (tenant_id, content, memory_type, salience,
created_at, accessed_at)
VALUES ('user_123', 'Prefere respostas em portugues',
'preference', 4.0, unixepoch(), unixepoch());
-- Buscar memorias mais relevantes do usuario
SELECT content, memory_type, salience FROM memories
WHERE tenant_id = 'user_123'
ORDER BY salience DESC, accessed_at DESC
LIMIT 20;
O campo salience e fundamental: nem toda memoria tem o mesmo peso. "Usuario se chama Carlos" tem salience 5.0, enquanto "usuario mencionou que estava chovendo" tem salience 0.5. Isso permite carregar apenas o que importa no prompt.
Vector Stores para Busca Semantica
Quando voce tem centenas de memorias e precisa encontrar as relevantes sem query exata. A busca e por significado, nao por keyword.
Extensao PostgreSQL. Roda no mesmo banco. Sem infraestrutura extra. Ideal para quem ja usa Postgres. Supabase inclui nativamente.
Managed service. Escala automaticamente. Free tier generoso. Boa DX com SDK TypeScript. Nao precisa gerenciar infra.
Open-source, roda local. Bom para prototipacao e agentes pessoais. Sem custo. API simples em Python e JS.
// Exemplo com pgvector (via Supabase)
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(url, key)
// Gerar embedding do texto
const embedding = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: 'Usuario prefere formato JSON para relatorios'
})
// Salvar memoria com embedding
await supabase.from('memories').insert({
tenant_id: 'user_123',
content: 'Usuario prefere formato JSON para relatorios',
embedding: embedding.data[0].embedding,
memory_type: 'preference'
})
// Buscar memorias semanticamente similares
const { data } = await supabase.rpc('match_memories', {
query_embedding: queryEmbedding,
match_threshold: 0.7,
match_count: 10,
filter_tenant: 'user_123'
})
Markdown Files para Agentes Pessoais
A abordagem mais simples possivel. O Claude Code usa exatamente isso com CLAUDE.md e MEMORY.md. Zero infra, versionavel com git, legivel por humanos.
# MEMORY.md - Memoria do Agente ## Preferencias do Usuario - Idioma: portugues (Brasil) - Tom: tecnico mas acessivel - Formato preferido: exemplos de codigo antes de teoria ## Projetos Ativos - SaaS de analytics: Next.js + Supabase, em producao - Bot Telegram: TypeScript, multi-agente, em dev ## Decisoes Tomadas - 2026-03-05: Escolheu SQLite para memoria (simplicidade) - 2026-03-07: Migrou router de regras para LLM classifier - 2026-03-09: Adicionou Codex como agente de codigo
Funciona incrivelmente bem para agentes pessoais (1 usuario). Para SaaS multi-tenant, migre para SQLite ou Postgres. O padrao de leitura-no-inicio-da-sessao + escrita-quando-aprende e o mesmo independente do storage.
💡 Dica
Regra de ouro para escolher storage: 1 usuario? Markdown. Ate 1000 usuarios? SQLite. Escala grande + busca semantica? PostgreSQL + pgvector. Nao comece com Pinecone se voce tem 5 usuarios. Migrar para cima e facil; comecar complexo e caro.
Fazer
- ●Comecar com SQLite e migrar quando necessario
- ●Usar salience scoring para priorizar memorias no prompt
- ●Manter backup das memorias (sao dados valiosos do usuario)
- ●Implementar uma funcao unificada getMemories(tenantId, type, limit)
Evitar
- ●Criar embeddings para tudo (caro e desnecessario no inicio)
- ●Guardar mensagens inteiras da conversa como memoria
- ●Ignorar o custo de embedding calls em volume alto
- ●Armazenar dados sensiveis sem criptografia
Context Passing entre Agentes
Handoff estruturado, shared state, message queues para multiagentes
Em sistemas multiagentes, o maior desafio nao e fazer cada agente funcionar isoladamente. E passar contexto entre eles sem perder informacao. Quando o Research Agent encontra dados e passa para o Writer Agent, o Writer precisa saber exatamente o que foi encontrado, o que o usuario pediu, e quais restricoes existem. Se o handoff for mal feito, o Writer vai pedir ao usuario para repetir tudo.
Existem tres abordagens principais para context passing, cada uma com tradeoffs de complexidade, latencia e confiabilidade.
Padrao 1: Structured Handoff Messages
O agente que termina sua tarefa cria um objeto JSON estruturado com tudo que o proximo agente precisa. Simples, explicito, sem estado compartilhado.
interface HandoffMessage {
from: string // ID do agente remetente
to: string // ID do agente destinatario
task: string // Descricao da tarefa delegada
context: {
original_request: string // O que o usuario pediu
work_done: string // O que ja foi feito
results: any // Dados produzidos
constraints: string[] // Restricoes a respeitar
}
conversation_summary: string // Resumo da conversa ate aqui
metadata: {
timestamp: number
turn_count: number
tokens_used: number
}
}
// Exemplo real
const handoff: HandoffMessage = {
from: 'research-agent',
to: 'writer-agent',
task: 'Escrever artigo sobre MCP baseado na pesquisa',
context: {
original_request: 'Artigo tecnico sobre MCP para devs',
work_done: 'Pesquisa completa: 5 fontes, 3 code samples',
results: { sources: [...], code_samples: [...] },
constraints: ['max 2000 palavras', 'tom tecnico', 'incluir exemplos']
},
conversation_summary: 'Usuario pediu artigo sobre MCP. ' +
'Pesquisa concluida com 5 fontes oficiais.',
metadata: { timestamp: Date.now(), turn_count: 4, tokens_used: 3200 }
}
Padrao 2: Shared State Store
Todos os agentes leem e escrevem num estado compartilhado (Redis, banco de dados, objeto em memoria). Cada agente atualiza sua parte e le o que precisa dos outros.
// Estado compartilhado entre agentes (in-memory ou Redis)
interface SharedState {
task_id: string
user_id: string
original_request: string
agents: {
[agentId: string]: {
status: 'pending' | 'running' | 'done' | 'error'
output: any
updated_at: number
}
}
conversation_history: Message[]
}
// Research agent atualiza seu output
state.agents['research'] = {
status: 'done',
output: { sources: [...], summary: '...' },
updated_at: Date.now()
}
// Writer agent le o output do research
const researchResults = state.agents['research'].output
if (state.agents['research'].status === 'done') {
// Pode comecar a escrever com os dados da pesquisa
}
Vantagem: agentes podem rodar em paralelo e consumir resultados uns dos outros sem acoplamento direto. Desvantagem: precisa de lock/concurrency control e pode ficar complexo com muitos agentes.
Padrao 3: Message Queue
Agentes se comunicam via fila de mensagens (BullMQ, RabbitMQ, SQS). Desacoplamento maximo, ideal para sistemas distribuidos e processamento assincrono.
Node.js + Redis. Simples de configurar. Suporta retry, delay, prioridade. Ideal para monolitos distribuidos.
AWS managed. Escala infinita. Pay-per-message. Bom para microservicos em cloud. Sem servidor pra gerenciar.
EventEmitter ou callback chain no mesmo processo. Zero latencia de rede. Suficiente para monolitos Node.js.
💡 Dica
Para SaaS em estagio inicial, use Structured Handoff Messages com um objeto em memoria. E o mais simples de implementar e debugar. Quando escalar, migre para shared state com Redis. Message queues so fazem sentido quando voce tem agentes rodando em processos/servidores separados.
Fazer
- ●Sempre incluir conversation_summary no handoff
- ●Logar cada handoff com contexto completo para debug
- ●Validar que o agente receptor tem os dados que precisa
- ●Implementar timeout para handoffs que nunca completam
Evitar
- ●Passar a conversa inteira no handoff (caro e ruidoso)
- ●Assumir que o agente receptor sabe o contexto
- ●Handoffs circulares: A passa para B que passa de volta para A
- ●Usar message queue para 2 agentes no mesmo processo
Tenant Isolation em Memoria
Isolamento por usuario, Row Level Security, namespace prefixes e protecao de dados
Em qualquer SaaS com agentes de IA, as memorias de um usuario nunca podem vazar para outro. Isso nao e opcional. Se o Agente do Usuario A acessa uma memoria do Usuario B, voce tem um data breach. A boa noticia: implementar isolamento correto desde o inicio e simples e previne dores de cabeca enormes depois.
Existem 3 niveis de isolamento, do mais simples ao mais robusto. A escolha depende do seu estagio e do nivel de seguranca exigido pelo seu mercado.
Nivel 1: Coluna tenant_id (Mais Comum)
Todos os dados na mesma tabela, filtrados por tenant_id em cada query. Funciona bem para a maioria dos SaaS. O risco e esquecer o filtro em alguma query.
-- Toda query DEVE incluir tenant_id
-- CORRETO:
SELECT * FROM memories
WHERE tenant_id = $1 AND memory_type = 'preference'
ORDER BY salience DESC;
-- ERRADO (data breach!):
SELECT * FROM memories
WHERE memory_type = 'preference'
ORDER BY salience DESC;
-- Funcao helper que forca o filtro
function getMemories(tenantId: string, type?: string) {
if (!tenantId) throw new Error('tenant_id required')
let query = db.prepare(
'SELECT * FROM memories WHERE tenant_id = ?'
)
// Nunca permita query sem tenant_id
}
Nivel 2: Row Level Security (PostgreSQL)
O banco de dados garante o isolamento automaticamente. Mesmo que voce esqueca o WHERE, o RLS impede acesso a dados de outro tenant. E a camada de seguranca mais solida.
-- Habilitar RLS na tabela
ALTER TABLE memories ENABLE ROW LEVEL SECURITY;
-- Politica: usuario so ve suas proprias memorias
CREATE POLICY tenant_isolation ON memories
FOR ALL
USING (tenant_id = current_setting('app.current_tenant'));
-- Antes de cada request, setar o tenant
SET app.current_tenant = 'user_123';
-- Agora qualquer SELECT retorna apenas dados do user_123
-- Mesmo sem WHERE tenant_id =, o RLS filtra automaticamente
SELECT * FROM memories; -- so retorna dados do user_123
-- Supabase faz isso nativamente com auth.uid()
CREATE POLICY tenant_isolation ON memories
FOR ALL
USING (tenant_id = auth.uid());
Com Supabase, o RLS ja vem integrado ao sistema de autenticacao. Cada request autenticado so acessa dados do proprio usuario. Sem codigo extra.
Nivel 3: Namespace Prefixes (Vector Stores)
Para vector stores que nao suportam RLS nativamente, use namespaces ou prefixos para garantir isolamento nas buscas por similaridade.
// Pinecone: usar namespace por tenant
const index = pinecone.index('memories')
// Salvar no namespace do tenant
await index.namespace('tenant_user_123').upsert([{
id: 'mem_001',
values: embedding,
metadata: { content: '...', type: 'preference' }
}])
// Buscar APENAS no namespace do tenant
const results = await index.namespace('tenant_user_123').query({
vector: queryEmbedding,
topK: 10,
includeMetadata: true
})
// Impossivel acessar dados de outro namespace
⚠️ Alerta de Seguranca
Em sistemas de IA, vazamento de memoria entre tenants e especialmente perigoso: memorias podem conter informacoes pessoais, decisoes de negocios, dados financeiros. Trate isolamento de memoria com o mesmo rigor que voce trata autenticacao. Teste com pelo menos 2 usuarios simultaneos e verifique que um nunca ve dados do outro.
Fazer
- ●Implementar isolamento desde o dia 1 (dificil de adicionar depois)
- ●Usar RLS se estiver em PostgreSQL/Supabase
- ●Testar isolamento com multi-user scenarios
- ●Centralizar acesso a memorias em uma camada que forca tenant_id
Evitar
- ●Queries sem filtro de tenant (mesmo "temporariamente")
- ●Confiar que "o frontend filtra" (backend deve garantir)
- ●Memoria global compartilhada entre todos os tenants
- ●Adiar isolamento para "depois do MVP" (nunca funciona)
Compactacao e Sumarizacao
Sliding window, sumarizacao automatica, extracao de fatos chave e descarte de ruido
Toda context window tem limite. Uma conversa longa de 100 turnos pode consumir 50k+ tokens, sobrando pouco espaco para instrucoes e ferramentas. A compactacao de memoria resolve isso: sumariza conversas antigas, extrai fatos chave e descarta ruido, mantendo o agente funcional mesmo apos horas de interacao.
O padrao mais usado e Sliding Window + Summary: mantenha as N mensagens mais recentes intactas, e substitua as mais antigas por um resumo compacto. O agente mantem o contexto recente com detalhes e o historico com os pontos essenciais.
Sliding Window + Summary Pattern
O padrao dominante para gerenciar contexto em conversas longas. Usado pelo Claude Code, ChatGPT e a maioria dos agentes em producao.
Context window acima de 80% do limite
LLM cria resumo das mensagens antigas
Troca mensagens antigas pelo resumo
Agente segue com resumo + mensagens recentes
async function compactConversation(messages: Message[], maxTokens: number) {
const tokenCount = estimateTokens(messages)
if (tokenCount < maxTokens * 0.8) return messages // Ainda tem espaco
// Dividir: mensagens antigas (para sumarizar) e recentes (manter)
const splitIndex = Math.floor(messages.length * 0.6)
const oldMessages = messages.slice(0, splitIndex)
const recentMessages = messages.slice(splitIndex)
// Pedir ao LLM para sumarizar as mensagens antigas
const summary = await llm.chat([
{ role: 'system', content: 'Resuma esta conversa em bullet points. ' +
'Mantenha: decisoes tomadas, fatos importantes, tarefas pendentes. ' +
'Descarte: saudacoes, perguntas ja respondidas, tentativas falhas.' },
{ role: 'user', content: JSON.stringify(oldMessages) }
])
// Retornar: system prompt + resumo + mensagens recentes
return [
{ role: 'system', content: `Resumo da conversa anterior:\n${summary}` },
...recentMessages
]
}
Extracao de Fatos Chave
Alem de sumarizar, extraia fatos que devem virar memoria de longo prazo. Nem tudo na conversa merece ser lembrado para sempre, mas algumas coisas sim.
const extractionPrompt = `Analise esta conversa e extraia APENAS fatos
que o agente deve lembrar em sessoes futuras. Categorize cada fato:
- preference: Algo que o usuario prefere ou nao gosta
- decision: Uma decisao tomada sobre o projeto
- fact: Um fato objetivo sobre o usuario ou seu contexto
- task: Uma tarefa mencionada para o futuro
Formato JSON:
[{"content": "...", "type": "...", "salience": 1-5}]
Nao inclua:
- Saudacoes ou smalltalk
- Perguntas que ja foram respondidas
- Detalhes tecnicos transitorios (erros debugados, etc)
- Informacoes que o agente ja tem no system prompt`
// Resultado:
[
{"content": "Usuario prefere TypeScript sobre JavaScript",
"type": "preference", "salience": 4},
{"content": "Decidiu usar Supabase em vez de Firebase",
"type": "decision", "salience": 5},
{"content": "Deadline do MVP e 15 de abril",
"type": "fact", "salience": 5}
]
Decay e Limpeza de Memorias
Memorias nao acessadas perdem relevancia com o tempo. Implemente um decay natural para manter o store limpo e relevante.
Time-based Decay
Reduza salience de memorias nao acessadas: a cada 7 dias sem acesso, reduza salience em 0.5. Quando chegar a 0, pode ser arquivada ou deletada.
Access-based Boost
Quando uma memoria e acessada (incluida no prompt e usada pelo agente), aumente sua salience. Memorias uteis se reforçam naturalmente.
Deduplicacao Periodica
Rode um job semanal que identifica memorias duplicadas ou contraditorias. "Prefere React" e "Decidiu migrar para Svelte" precisam ser resolvidas: a mais recente vence.
💡 Dica
Uma boa regra: compacte quando a context window chegar a 80% da capacidade. Use um modelo barato (GPT-4o-mini ou Qwen 14B) para sumarizacao, nao o modelo principal. Sumarizar com Claude Opus e eficiente mas caro. O conteudo do resumo nao precisa de raciocinio complexo, so de compressao fiel.
Fazer
- ●Compactar proativamente (antes de estourar, nao depois)
- ●Manter as ultimas N mensagens intactas (contexto recente precisa de detalhes)
- ●Extrair fatos chave para long-term memory antes de descartar
- ●Logar quantas compactacoes ocorreram por sessao
Evitar
- ●Truncar mensagens antigas sem sumarizar (perda de contexto)
- ●Sumarizar com o modelo mais caro da stack
- ●Compactar agressivamente demais (perde nuances importantes)
- ●Nunca limpar memorias antigas (store cresce indefinidamente)
Exercicio: Sistema de Memoria
Implementar 3 tipos de memoria: historico de conversas, preferencias e knowledge base
Neste exercicio voce vai implementar um sistema completo de memoria para o agente do seu SaaS. O objetivo e que o agente lembre preferencias entre sessoes, recupere historico de interacoes e busque conhecimento relevante. Ao final, seu agente passa de "chatbot que esquece tudo" para "assistente que conhece o usuario".
Entregas do Exercicio
Conversation History (SQLite)
Tabela conversations com tenant_id, messages (JSON), created_at. Funcoes: saveConversation(), getRecentConversations(tenantId, limit). Compactacao quando ultrapassar 50 mensagens por sessao.
User Preferences (Database)
Tabela preferences com tenant_id, key, value, updated_at. Funcoes: setPreference(), getPreference(), getAllPreferences(). Carregadas automaticamente no system prompt de cada sessao.
Knowledge Base (Vector Store ou Search)
Tabela knowledge com tenant_id, content, embedding (se vector), type, salience. Funcoes: addKnowledge(), searchKnowledge(query). Busca por similaridade ou keyword. Extracao automatica de fatos das conversas.
Arquitetura Sugerida
memory/
index.ts // Exporta MemoryManager unificado
conversation.ts // CRUD de historico de conversas
preferences.ts // CRUD de preferencias do usuario
knowledge.ts // CRUD de knowledge base + busca
compaction.ts // Sumarizacao e limpeza
schema.sql // DDL das tabelas
// Interface unificada
class MemoryManager {
constructor(private db: Database, private tenantId: string) {}
// Conversation history
async saveMessages(messages: Message[]): Promise<void>
async getRecentMessages(limit: number): Promise<Message[]>
async compactIfNeeded(): Promise<boolean>
// Preferences
async setPreference(key: string, value: string): Promise<void>
async getPreferences(): Promise<Record<string, string>>
// Knowledge
async addKnowledge(content: string, type: string): Promise<void>
async search(query: string, limit: number): Promise<Knowledge[]>
async extractFacts(conversation: Message[]): Promise<Fact[]>
// Lifecycle
async loadForPrompt(): Promise<string> // Monta contexto pro system prompt
async cleanup(): Promise<void> // Decay, dedup, archive
}
Checklist de Validacao
💡 Dica
Use Vibe Coding aqui: descreva a interface MemoryManager para o Claude ou Copilot e deixe gerar a implementacao. Depois revise, teste e itere. O exercicio valida que voce entende os conceitos. Se a implementacao gerada funciona, voce validou tanto seu entendimento quanto a capacidade de delegar para IA.
Fazer
- ●Comecar com SQLite para tudo (simples e funcional)
- ●Implementar loadForPrompt() que monta o contexto automaticamente
- ●Testar com dados reais (suas proprias conversas com o agente)
- ●Medir tokens consumidos por memorias no prompt
Evitar
- ●Over-engineering: nao precisa de Kafka para 10 usuarios
- ●Pular o teste de isolamento multi-tenant
- ●Carregar todas as memorias no prompt (use salience para filtrar)
- ●Esquecer de implementar cleanup/decay de memorias antigas
📋 Resumo do Modulo 4.6
4 tipos de memoria: short-term (sessao), long-term (persistente), episodica (eventos) e semantica (conhecimento acumulado).
Implementacao pratica: SQLite resolve 80% dos casos. Vector stores para busca semantica. Markdown para agentes pessoais.
Context passing: structured handoff messages, shared state stores ou message queues conforme escala do sistema.
Tenant isolation: obrigatorio em SaaS. Use RLS no PostgreSQL ou filtro por tenant_id em toda query. Teste desde o dia 1.
Compactacao: sliding window + summary para conversas longas. Extraia fatos chave para long-term. Decay natural para memorias nao acessadas.
Na pratica: MemoryManager unificado com conversations, preferences e knowledge. loadForPrompt() para carregar contexto automaticamente.