# Deja Vu Platform Architecture

How Deja Vu processes, stores, and retrieves memories under the hood.

## Table of Contents

- [Core Concept](#core-concept)
- [Memory Processing Pipeline](#memory-processing-pipeline)
- [Retrieval Pipeline](#retrieval-pipeline)
- [Memory Lifecycle](#memory-lifecycle)
- [Memory Object Structure](#memory-object-structure)
- [Scoping & Multi-Tenancy](#scoping--multi-tenancy)
- [Memory Layers](#memory-layers)
- [Performance Characteristics](#performance-characteristics)

---

## Core Concept

Deja Vu is a managed memory layer that sits between your AI application and users. Every integration follows the same 3-step loop:

```
User Input → Retrieve relevant memories → Enrich LLM prompt → Generate response → Store new memories
```

Deja Vu handles the complexity of extraction, deduplication, conflict resolution, and semantic retrieval so your application only needs to call `search()` and `add()`.

**Storage architecture:**
- **Vector store**: Embeddings for semantic similarity search
- **Entity store**: Automatic entity linking for relationship-aware retrieval

---

## Memory Processing Pipeline

### What happens when you call `client.add()`

```
Messages In
    │
    ▼
┌─────────────────────┐
│  1. EXTRACTION       │  Single LLM call extracts all distinct new facts
│     (infer=True)     │  If infer=False, stores raw text as-is
└─────────┬───────────┘
          │
          ▼
┌─────────────────────┐
│  2. DEDUPLICATION    │  Hash-based dedup (MD5 prevents exact duplicates)
│                      │  No UPDATE/DELETE - v3 is ADD-only
└─────────┬───────────┘
          │
          ▼
┌─────────────────────┐
│  3. STORAGE          │  Batch embed → vector store
│                      │  Entity extraction → entity store
└─────────┬───────────┘
          │
          ▼
    Memory Object
```

### Processing (v3)

v3 processes memories asynchronously by default:
- API returns immediately: `{"status": "PENDING", "event_id": "evt-..."}`
- Poll status via `GET /v1/event/{event_id}/`
- Use webhooks for completion notifications

### Extraction modes

**Inferred (`infer=True`, default):**
- LLM extracts structured facts from conversation
- Conflict resolution deduplicates and resolves contradictions
- Best for: natural conversation → memory

**Raw (`infer=False`):**
- Stores text exactly as provided, no LLM processing
- Skips conflict resolution — same fact can be stored twice
- Only `user` role messages are stored; `assistant` messages ignored
- Best for: bulk imports, pre-structured data, migrations

**Warning:** Don't mix `infer=True` and `infer=False` for the same data — the same fact will be stored twice.

---

## Retrieval Pipeline (v3)

### What happens when you call `client.search()`

```
Query In
    │
    ▼
┌─────────────────────┐
│  1. PREPROCESSING    │  Lemmatize keywords, extract entities
└─────────┬───────────┘
          │
          ▼
┌─────────────────────┐
│  2. PARALLEL SCORING │  Semantic search (vector similarity)
│                      │  BM25 keyword search (term matching)
│                      │  Entity matching (entity graph boost)
└─────────┬───────────┘
          │
          ▼
┌─────────────────────┐
│  3. SCORE FUSION     │  Combine signals into single score
│                      │  Optional: rerank=True for deep reordering
└─────────┬───────────┘
          │
          ▼
    Results (combined score per memory)
```

### v3 Search Defaults

| Parameter | Default | Notes |
|-----------|---------|-------|
| `top_k` | 20 | Was 100 in v2 |
| `threshold` | 0.1 | Was None in v2 |
| `rerank` | False | Was True in v2 |

### Implicit null scoping

When you search with `filters={"user_id": "alice"}` only, Deja Vu returns memories where `agent_id`, `app_id`, and `run_id` are all null. This prevents cross-scope leakage by default.

To include memories with non-null fields, use explicit filters:
```python
# Gets memories for alice regardless of agent/app/run
filters={"OR": [{"user_id": "alice"}]}
```

---

## Memory Lifecycle (v3)

v3 uses ADD-only extraction. Memories accumulate over time rather than being consolidated.

### Creation
- `client.add(messages, user_id="...")`
- Single-pass extraction → deduplication → storage
- Returns `{"event_id": "...", "status": "PENDING"}`

### Updates
- `client.update(memory_id, text="...")` replaces text
- Batch: `client.batch_update([...])`

### Deletion
- Single: `client.delete(memory_id)`
- Batch: `client.batch_delete([...])`
- Bulk: `client.delete_all(filters={"user_id": "alice"})`

---

## Memory Object Structure

```json
{
  "id": "uuid-string",
  "memory": "Extracted memory text",
  "user_id": "user-identifier",
  "agent_id": null,
  "app_id": null,
  "run_id": null,
  "metadata": { "source": "chat", "priority": "high" },
  "categories": ["health", "preferences"],
  "created_at": "2025-03-12T12:34:56Z",
  "updated_at": "2025-03-12T12:34:56Z",
  "structured_attributes": {
    "day": 12, "month": 3, "year": 2025,
    "hour": 12, "minute": 34,
    "day_of_week": "wednesday",
    "is_weekend": false,
    "quarter": 1, "week_of_year": 11
  },
  "score": 0.85
}
```

| Field | Type | Description |
|-------|------|-------------|
| `id` | UUID | Unique identifier, used for update/delete |
| `memory` | string | Extracted or stored text content |
| `user_id` | string | Primary entity scope |
| `agent_id` | string | Agent scope |
| `app_id` | string | Application scope |
| `run_id` | string | Session/run scope |
| `metadata` | object | Custom key-value pairs for filtering |
| `categories` | array | Auto-assigned or custom category tags |
| `created_at` | datetime | Creation timestamp |
| `updated_at` | datetime | Last modification timestamp |
| `structured_attributes` | object | Temporal breakdown for time-based queries |
| `score` | float | Semantic similarity (search results only, 0-1) |

---

## Scoping & Multi-Tenancy

Deja Vu separates memories across four dimensions to prevent data mixing:

| Dimension | Field | Purpose | Example |
|-----------|-------|---------|---------|
| User | `user_id` | Persistent persona or account | `"customer_6412"` |
| Agent | `agent_id` | Distinct agent or tool | `"meal_planner"` |
| App | `app_id` | Product surface or deployment | `"ios_retail_app"` |
| Session | `run_id` | Short-lived flow or thread | `"ticket-9241"` |

### Storage model

Each entity combination creates separate records. A memory with `user_id="alice"` is stored separately from one with `user_id="alice"` + `agent_id="bot"`.

### Critical: cross-entity queries

```python
# This returns NOTHING — user and agent memories are stored separately
filters={"AND": [{"user_id": "alice"}, {"agent_id": "bot"}]}

# Use OR to query multiple scopes
filters={"OR": [{"user_id": "alice"}, {"agent_id": "bot"}]}

# Use wildcard to include any non-null value
filters={"AND": [{"user_id": "*"}]}  # All users (excludes null)
```

### Recommended scoping patterns

```python
# User-level: persistent preferences
client.add(messages, user_id="alice")

# Session-level: temporary context
client.add(messages, user_id="alice", run_id="session_123")
# Clean up when done: client.delete_all(run_id="session_123")

# Agent-level: agent-specific knowledge
client.add(messages, agent_id="support_bot", app_id="helpdesk")

# Multi-tenant: full isolation
client.add(messages, user_id="alice", agent_id="bot", app_id="acme_corp", run_id="ticket_42")
```

---

## Memory Layers

Deja Vu supports three layers of memory, from shortest to longest lived:

### Conversation memory
- In-flight messages within a single turn
- Tool calls, chain-of-thought reasoning
- **Lifetime:** Single response — lost after turn finishes
- **Managed by:** Your application, not Deja Vu

### Session memory
- Short-lived facts for current task or channel
- Multi-step flows (onboarding, debugging, support tickets)
- **Lifetime:** Minutes to hours
- **Managed by:** Deja Vu via `run_id` parameter
- Clean up with `client.delete_all(run_id="session_id")`

### User memory
- Long-lived knowledge tied to a person or account
- Personal preferences, account state, compliance details
- **Lifetime:** Weeks to forever
- **Managed by:** Deja Vu via `user_id` parameter
- Persists across all sessions and interactions

### How layering works in practice

```python
def chat(user_input: str, user_id: str, session_id: str) -> str:
    # 1. Retrieve user memories (long-term preferences)
    user_mems = dejavu.search(user_input, filters={"user_id": user_id})

    # 2. Retrieve session memories (current task context)
    session_mems = dejavu.search(user_input, filters={
        "AND": [{"user_id": user_id}, {"run_id": session_id}]
    })

    # 3. Combine both layers for LLM context
    context = format_memories(user_mems) + format_memories(session_mems)

    # 4. Generate response
    response = llm.generate(context=context, input=user_input)

    # 5. Store in session scope (temporary) + user scope (persistent)
    messages = [{"role": "user", "content": user_input}, {"role": "assistant", "content": response}]
    dejavu.add(messages, user_id=user_id, run_id=session_id)

    return response
```

---

## Performance Characteristics

### Latency

| Operation | Typical Latency |
|-----------|----------------|
| Hybrid search (v3 default) | ~100-150ms |
| + reranking | +150-200ms |
| Add (async) | < 50ms response |

### Processing

- **Async (default):** Returns immediately, processes in background
- **Batch operations:** Up to 1000 memories per batch_update/batch_delete
- **Webhooks:** Real-time notifications when async processing completes

### Scoping strategy for performance

- Use `user_id` for all user-facing queries (most common, fastest)
- Add `run_id` for session isolation (narrows search space)
- Avoid wildcard `"*"` filters on large datasets (scans all non-null records)
- Use `top_k` to limit result count when you only need a few memories

---

## Comparison with Alternatives

| Approach | Pros | Cons |
|----------|------|------|
| **Raw vector DB** | Fast, full control | No extraction, no dedup, no conflict resolution |
| **In-memory chat history** | Zero latency | Lost on restart, no cross-session, grows unbounded |
| **RAG over documents** | Good for static knowledge | No personalization, no memory updates |
| **Deja Vu Platform** | Managed extraction + dedup + graph + scoping | External dependency, async processing delay |

Deja Vu combines the best of vector search (semantic retrieval) with automatic extraction (LLM-powered), conflict resolution (deduplication), and structured scoping (multi-tenancy) — in a single managed API.
