# Background Jobs

Os background jobs mantêm e otimizam a memória ao longo do tempo — agrupando fatos em clusters, consolidando padrões, pontuando importância e atualizando resumos. Eles rodam periodicamente (não durante o processamento de mensagens) e melhoram a qualidade do retrieval sem impactar a latência de resposta.

```mermaid
flowchart LR
    A["Scheduler\n(periodic)"] --> B["Clustering"]
    A --> C["Consolidation"]
    A --> D["Importance\nScoring"]
    A --> E["Summary\nRefresh"]
```

## Visão Geral

O `arandu` fornece quatro categorias de background jobs:

| Job | Propósito | Usa LLM? | Frequência |
|-----|-----------|----------|------------|
| **Clustering** | Agrupar fatos relacionados semanticamente | Sim (resumos) | A cada 4-8 horas |
| **Consolidation** | Detectar padrões, contradições, tendências | Sim | A cada 4-8 horas |
| **Memify** | Converter fatos episódicos em conhecimento procedural/semântico | Sim | Diário |
| **Sleep-time compute** | Pontuar importância, atualizar resumos, detectar comunidades | Parcialmente | A cada 4-8 horas |

Todos os jobs são expostos como funções async que você pode chamar diretamente ou agendar com seu task runner preferido (APScheduler, Celery, cron, etc.).

!!! info "Paralelo com neurociência"
    Os background jobs espelham o **processamento durante o sono** no cérebro. Durante o sono, o cérebro consolida memórias, transfere informações do hipocampo (curto prazo) para o neocórtex (longo prazo), poda conexões irrelevantes e fortalece as importantes. Esses jobs realizam as mesmas operações na memória do seu agente.

---

## Clustering

O clustering agrupa fatos relacionados em clusters semânticos, tornando o retrieval mais contextual e habilitando detecção de comunidades.

### Fact Clustering

```python
from arandu import cluster_user_facts, ClusteringResult

result: ClusteringResult = await cluster_user_facts(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    embeddings=embedding_provider,
    config=memory_config,
)
```

**Como funciona:**

1. Agrupa fatos por `(entity_type, entity_key)` — fatos sobre a mesma entidade ficam juntos
2. Gera um resumo de 2-3 frases por cluster usando um LLM
3. Calcula e armazena embeddings do cluster para detecção de comunidades posterior
4. Idempotente — atualiza clusters existentes em vez de criar duplicatas

### Detecção de Comunidades

```python
from arandu import detect_communities, CommunityDetectionResult

result: CommunityDetectionResult = await detect_communities(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    embeddings=embedding_provider,
    config=memory_config,
)
```

**Como funciona:**

1. Compara embeddings de clusters usando similaridade de cosseno
2. Agrupa clusters acima do `community_similarity_threshold` (padrão 0.75)
3. Cria registros `MemoryMetaObservation` com tipo `"entity_community"`
4. Exemplo: uma comunidade "trabalho" pode incluir clusters sobre colegas, projetos e fatos da empresa

### Configuração

| Parâmetro | Default | Descrição |
|-----------|---------|-----------|
| `cluster_max_age_days` | `90` | Idade máxima dos fatos a incluir no clustering |
| `community_similarity_threshold` | `0.75` | Threshold de similaridade de cosseno para agrupar clusters |

---

## Consolidation

A consolidation analisa eventos e fatos recentes para detectar padrões de ordem superior — insights, contradições, tendências e preferências comportamentais.

### Consolidação Periódica (L2)

```python
from arandu import run_consolidation, ConsolidationResult

result: ConsolidationResult = await run_consolidation(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    config=memory_config,
)
```

**Como funciona:**

1. Analisa eventos e fatos em uma janela de lookback (`consolidation_lookback_days`)
2. Detecta padrões entre fatos:
   - **Insights** — Compreensão emergente de múltiplos fatos
   - **Padrões** — Comportamentos ou preferências repetidos
   - **Contradições** — Fatos conflitantes que precisam de resolução
   - **Tendências** — Mudanças ao longo do tempo
3. Gera registros `MemoryMetaObservation`
4. Marca eventos com emoções (emoção, intensidade, nível de energia)

### Consolidação de Perfil (L3)

```python
from arandu import run_profile_consolidation

await run_profile_consolidation(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    config=memory_config,
)
```

**Como funciona:**

1. Atualiza resumos de entidades via LLM — uma visão de nível mais alto de cada entidade
2. Atualiza a visão geral do perfil
3. Disparado periodicamente (menos frequente que L2)

### Configuração

| Parâmetro | Default | Descrição |
|-----------|---------|-----------|
| `consolidation_min_events` | `3` | Mínimo de eventos antes de rodar consolidation |
| `consolidation_lookback_days` | `7` | Quantos dias olhar para trás em busca de padrões |

!!! info "Paralelo com neurociência"
    A consolidation espelha a **consolidação de memória durante o sono** do cérebro. O hipocampo repete experiências recentes, o neocórtex detecta padrões e os integra em estruturas de conhecimento existentes, e contradições são sinalizadas para resolução. A consolidação L2 é análoga ao replay durante o sono de ondas lentas (SWS), enquanto a consolidação de perfil L3 é análoga ao papel do sono REM na integração de memórias em conhecimento semântico.

---

## Memify

O memify converte fatos episódicos (eventos específicos) em conhecimento procedural e semântico (conhecimento geral). Ele também gerencia a vitalidade dos fatos — quão "vivo" um fato está com base em menções recentes.

### Executar Memify

```python
from arandu import run_memify, MemifyResult

result: MemifyResult = await run_memify(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    config=memory_config,
)
```

**Como funciona:**

1. Agrupa fatos relacionados por entidade e tópico
2. Gera resumos destilados (conhecimento procedural/semântico)
3. Verifica vitalidade — fatos mencionados recentemente são mantidos; fatos obsoletos podem ser deprecados
4. Mescla procedimentos similares para prevenir fragmentação de conhecimento

### Scoring de Vitalidade

```python
from arandu import compute_vitality

vitality_scores = await compute_vitality(
    session=db_session,
    user_id="user_123",
    config=memory_config,
)
```

A vitalidade mede quão "vivo" um fato está com base em:

- **Recência** — Quando o fato foi confirmado ou mencionado pela última vez?
- **Reforço** — Quantas vezes esse fato foi confirmado (decisões NOOP)?
- **Importância** — Quão relevante esse fato é para o perfil do usuário?

!!! info "Paralelo com neurociência"
    O memify espelha a **curva de esquecimento** descrita por Hermann Ebbinghaus (1885). Memórias decaem exponencialmente ao longo do tempo a menos que sejam reforçadas através de prática de recuperação. Fatos com alta vitalidade (acessados frequentemente) resistem ao decay, enquanto fatos de baixa vitalidade vão se apagando gradualmente — assim como o cérebro poda conexões sinápticas para informações não utilizadas.

---

## Sleep-Time Compute

O sleep-time compute executa três jobs de manutenção direcionados que melhoram a qualidade do retrieval:

### Job 1: Entity Importance Scoring

```python
from arandu import compute_entity_importance, EntityImportanceResult

result: EntityImportanceResult = await compute_entity_importance(
    session=db_session,
    user_id="user_123",
    config=memory_config,
)
```

Computação pura em SQL (sem chamadas LLM). Pontua cada entidade de 0.0 a 1.0 usando quatro sinais normalizados:

| Sinal | Peso | Descrição |
|-------|------|-----------|
| Densidade de fatos | 0.30 | Número de fatos relativos a outras entidades |
| Recência | 0.25 | Decay exponencial (half-life de 30 dias) |
| Frequência de retrieval | 0.25 | Quão frequentemente fatos sobre essa entidade são recuperados |
| Grau de relacionamento | 0.20 | Número de relacionamentos entrantes + saintes |

O importance score é usado como sinal no scoring de retrieval e como fator de prioridade para atualização de resumos.

### Job 2: Entity Summary Refresh

```python
from arandu import refresh_entity_summaries, SummaryRefreshResult

result: SummaryRefreshResult = await refresh_entity_summaries(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    config=memory_config,
)
```

Atualiza resumos obsoletos de entidades:

- **Condição de obsolescência**: `summary_text IS NULL` ou última atualização > 7 dias atrás
- **Prioridade**: entidades com `importance_score` mais alto são atualizadas primeiro
- **Limite**: 10 entidades por execução (previne timeout)
- Gera resumos de 2-3 frases a partir dos fatos da entidade usando um LLM

### Job 3: Entity Community Detection

```python
from arandu import detect_entity_communities

result = await detect_entity_communities(
    session=db_session,
    user_id="user_123",
    llm=llm_provider,
    embeddings=embedding_provider,
    config=memory_config,
)
```

Encontra grupos de entidades relacionadas usando o grafo de relacionamentos:

1. Carrega entidades ativas e arestas (strength >= 0.3)
2. Executa Union-Find (com path compression + union by rank) para encontrar componentes conectados
3. Filtra por threshold mínimo de entidades
4. Gera resumo LLM e embedding para cada comunidade
5. Deduplica contra comunidades existentes (overlap de membros Jaccard)
6. Armazena como registros `MemoryMetaObservation`

!!! info "Paralelo com neurociência"
    O sleep-time compute espelha o **processamento offline durante o sono**. O cérebro não apenas armazena memórias passivamente durante o sono — ele as reorganiza ativamente. O importance scoring é análogo ao processo de **homeostase sináptica** (Tononi & Cirelli), onde sinapses fortemente ativadas são mantidas enquanto fracamente ativadas são podadas. O summary refresh espelha a formação de **memórias de essência** — representações comprimidas que capturam a essência de episódios detalhados.

---

## Agendamento

O `arandu` não inclui um scheduler — você traz o seu. Todas as funções de background são simples callables async que podem ser integradas com qualquer sistema de agendamento.

### Exemplo: APScheduler

```python
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from arandu import (
    cluster_user_facts,
    run_consolidation,
    compute_entity_importance,
    refresh_entity_summaries,
)

scheduler = AsyncIOScheduler()

async def maintenance_cycle():
    async with get_session() as session:
        for user_id in await get_active_users(session):
            await compute_entity_importance(session, user_id, config)
            await refresh_entity_summaries(session, user_id, llm, config)
            await cluster_user_facts(session, user_id, llm, embeddings, config)
            await run_consolidation(session, user_id, llm, config)

scheduler.add_job(maintenance_cycle, "interval", hours=4)
scheduler.start()
```

### Exemplo: Loop Simples

```python
import asyncio

async def background_loop():
    while True:
        await maintenance_cycle()
        await asyncio.sleep(4 * 3600)  # a cada 4 horas
```

### Cadência Recomendada

| Job | Frequência | Custo |
|-----|-----------|-------|
| Entity importance | A cada 4h | Barato (apenas SQL) |
| Summary refresh | A cada 4h | Moderado (LLM, limitado a 10/execução) |
| Clustering | A cada 4-8h | Moderado (LLM para resumos) |
| Consolidation | A cada 4-8h | Moderado (LLM para detecção de padrões) |
| Memify | Diário | Moderado (LLM para destilação) |
| Community detection | Diário | Moderado (LLM + embeddings) |

Execute importance scoring primeiro — sua saída é usada pelo summary refresh para priorizar entidades.
