# Configuration

All memory system parameters are configured through a single `MemoryConfig` dataclass. Every parameter has a sensible default - override only what matters for your use case.

```python
from arandu import MemoryClient, MemoryConfig

config = MemoryConfig(
    extraction_timeout_sec=15.0,
    topk_facts=30,
    enable_reranker=True,
)

memory = MemoryClient(
    database_url="postgresql+psycopg://...",
    llm=provider,
    embeddings=provider,
    config=config,
)
```

---

## Extraction

Parameters controlling how facts, entities, and relationships are extracted from messages.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `extraction_timeout_sec` | `float` | `30.0` | Timeout per LLM call during extraction. On timeout, extraction returns an empty result (fail-safe) - no exception is raised. See [Fail-safe Behavior](#fail-safe-timeout) |
| `enable_informed_extraction` | `bool` | `True` | Enable memory-aware informed extraction. When `True` (default), the write pipeline performs alias lookup + pre-retrieval before a single LLM call that receives existing knowledge as context, eliminating duplicates at the source. When `False`, uses the legacy blind extraction flow (entity scan + fact extraction + relation extraction + reconciliation). Falls back to blind extraction automatically on failure. See [Write Pipeline - Memory-Aware Extraction](concepts/write-pipeline.md#stage-1-memory-aware-extraction) |
| `informed_extraction_topk` | `int` | `10` | Number of existing facts to retrieve per entity during the pre-retrieval step of informed extraction. Only used when the entity has no `profile_text` (profiles replace individual fact retrieval when available). Higher values give the LLM more context about existing knowledge but cost more prompt tokens |
| `informed_extraction_context_budget_tokens` | `int` | `800` | Maximum token budget for the existing knowledge context injected into the informed extraction LLM call. Distributed across all matched entities. Controls how much prior knowledge the LLM sees. Increase for entities with rich histories; decrease if prompt length is a concern |

### `occurred_at` Parameter (on `write()`)

The `write()` method accepts an optional `occurred_at` parameter (`datetime | None`, default: `None` which means "now"). This timestamp tells the extraction pipeline when the message was sent, and is used to resolve relative time references in the message text.

For example, if `occurred_at=datetime(2025, 6, 15)` and the message says "yesterday I went to the beach", the extraction resolves "yesterday" to June 14, 2025 and includes the absolute date in the fact text.

This is primarily useful for **historical imports** -- when you're ingesting past conversations and want the extraction to correctly resolve temporal references relative to when the message was originally sent, not when the import runs.

```python
from datetime import datetime, UTC

# Importing a historical conversation
result = await memory.write(
    agent_id="user_123",
    message="Yesterday I started my new job at Acme Corp",
    speaker_name="Rafael",
    occurred_at=datetime(2025, 3, 10, tzinfo=UTC),  # resolves "yesterday" to March 9
)
```

**Tips:**

- The extraction model is determined by the `LLMProvider` you inject into `MemoryClient`. To use a cheaper model for extraction, inject a provider configured with that model
- Lower `extraction_timeout_sec` if you need faster responses at the cost of potentially missed extractions
- Set `enable_informed_extraction=False` to revert to the legacy extraction flow if your LLM provider struggles with the unified prompt (e.g., smaller models)
- Increase `informed_extraction_topk` (e.g., 20) for agents with many facts per entity where more context helps the LLM avoid duplicates
- Increase `informed_extraction_context_budget_tokens` (e.g., 1200) for complex domains where entities have extensive histories

---

## Entity Resolution

Parameters controlling how extracted entity mentions are resolved to canonical entity records.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `fuzzy_threshold` | `float` | `0.85` | Cosine similarity threshold for direct fuzzy match. Score ≥ this value resolves directly; score between 0.50 and this value forwards to LLM; score < 0.50 creates new entity. Lowering this value expands the fuzzy-resolve range and reduces LLM calls |
| `enable_llm_resolution` | `bool` | `True` | Whether to use an LLM for ambiguous fuzzy matches (0.50 - `fuzzy_threshold` range). When `False`, ambiguous candidates create a new entity instead |

**Tips:**

- Lower `fuzzy_threshold` (e.g., 0.75) to be more aggressive in matching similar entity names - this shrinks the "ambiguous" range that requires LLM calls
- Set `enable_llm_resolution=False` to skip the LLM fallback for ambiguous matches (faster, but may create more duplicate entities)
- The LLM model for entity resolution and reconciliation is determined by the `LLMProvider` you inject into `MemoryClient`

---

## Retrieval

Parameters controlling how facts are retrieved in response to queries.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `topk_facts` | `int` | `20` | Maximum number of facts to return |
| `topk_events` | `int` | `8` | Maximum number of events to consider for context |
| `event_max_scan` | `int` | `200` | Maximum events to scan during retrieval |
| `min_similarity` | `float` | `0.20` | Minimum cosine similarity for semantic search results |
| `min_confidence` | `float` | `0.55` | Minimum fact confidence to include in retrieval results |

!!! warning "`min_confidence` is a **read-time filter only**"
    All facts are persisted during write regardless of their confidence score. Filtering happens during `memory.retrieve()`. This is by design: confidence can be adjusted over time via reinforcement (NOOP confirmations), and discarding facts at write-time would be irreversible.
| `recency_half_life_days` | `int` | `14` | Half-life (in days) for exponential recency decay |
| `enable_reranker` | `bool` | `True` | Whether to use LLM reranking on retrieval results |
| `reranker_timeout_sec` | `float` | `5.0` | Timeout for reranker LLM calls |

**Tips:**

- Increase `topk_facts` (e.g., 50) for broader context at the cost of more noise
- Lower `min_similarity` (e.g., 0.10) to catch more distant semantic matches
- Increase `recency_half_life_days` (e.g., 30) if older facts should remain relevant longer
- Set `enable_reranker=False` for faster retrieval when precision is less critical

---

## Score Weights

Weights for the hybrid ranking formula that combines multiple retrieval signals.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `score_weights` | `dict` | `{"semantic": 0.70, "recency": 0.20, "importance": 0.10}` | Weights for each scoring signal (must sum to ~1.0) |

```python
config = MemoryConfig(
    score_weights={
        "semantic": 0.60,   # reduce semantic, boost other signals
        "recency": 0.25,
        "importance": 0.15,
    },
)
```

**Tips:**

- Increase `"recency"` weight for applications where freshness matters more than semantic relevance
- Increase `"importance"` weight to favor well-established entities and frequently mentioned facts

---

## Confidence

Parameters controlling confidence levels assigned to extracted facts.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `confidence_level_map` | `dict` | `{"explicit_statement": 0.95, "strong_inference": 0.80, "weak_inference": 0.60, "speculation": 0.40}` | Mapping from confidence level names to numeric scores |
| `confidence_default` | `float` | `0.60` | Default confidence when the LLM doesn't specify a level |

---

## Spreading Activation

Parameters controlling how context expands from seed facts along entity relationships.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `spreading_activation_hops` | `int` | `2` | Maximum number of relationship hops from seed facts |
| `spreading_decay_factor` | `float` | `0.50` | Score decay multiplier per hop (0.5 = halved each hop) |
| `spreading_max_related_entities` | `int` | `5` | Maximum related entities to follow per seed |
| `spreading_facts_per_entity` | `int` | `3` | Maximum facts to pull from each related entity |

---

## Context Compression

Parameters controlling how retrieved facts are compressed into the final context string.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `context_max_tokens` | `int` | `2000` | Maximum tokens in the formatted context output |
| `hot_tier_ratio` | `float` | `0.50` | Share of token budget for highest-scored facts |
| `warm_tier_ratio` | `float` | `0.30` | Share of token budget for supporting facts |

The remaining budget (1 - hot - warm = 0.20) goes to the cold tier (background context).

---

## Emotional Trends

Parameters for detecting emotional patterns in user messages.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `emotional_trend_window_days` | `int` | `30` | Window for analyzing emotional trends |
| `emotional_trend_min_events` | `int` | `5` | Minimum events required to detect a trend |

---

## Clustering

Parameters for the fact clustering background job.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `cluster_max_age_days` | `int` | `90` | Maximum age of facts to include in clustering |
| `cluster_min_facts` | `int` | `2` | Minimum facts per cluster |
| `community_similarity_threshold` | `float` | `0.75` | Cosine similarity threshold for grouping clusters into communities |
| `community_min_clusters` | `int` | `2` | Minimum clusters to form a community |

---

## Consolidation

Parameters for the consolidation background job.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `consolidation_min_events` | `int` | `3` | Minimum events before running consolidation |
| `consolidation_lookback_days` | `int` | `7` | How far back (in days) to look for patterns |

---

## Sleep-Time Compute

Parameters for background importance scoring and summary refresh.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `importance_recency_halflife_days` | `int` | `30` | Half-life for recency signal in importance scoring |
| `summary_refresh_interval_days` | `int` | `7` | Days before an entity summary is considered stale |

---

## Memify

Parameters for the memify (episodic → procedural knowledge) background job.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `vitality_stale_threshold` | `float` | `0.2` | Vitality score below which a fact is considered stale |
| `memify_merge_similarity_threshold` | `float` | `0.90` | Similarity threshold for merging similar procedures |

---

## Procedural Memory

Parameters for directive/procedural memory retrieval.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `directive_max_tokens` | `int` | `300` | Maximum tokens for procedural directives |
| `directive_cache_ttl_minutes` | `int` | `30` | Cache TTL for directive lookups |
| `contradiction_similarity_threshold` | `float` | `0.80` | Threshold for detecting contradictory directives |

---

## Locale / Deployment

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `timezone` | `str` | `"UTC"` | IANA timezone for interpreting relative time references |

The `timezone` parameter affects how relative time references ("yesterday", "last week", "this morning") are interpreted during fact extraction and retrieval. All timestamps in the database are stored in **UTC** regardless of this setting.

For example: if `timezone="Asia/Tokyo"` and the user says "yesterday", the SDK interprets "yesterday" relative to Tokyo time (JST), not UTC.

---

## Open Catalog (Deployer Extensions)

Parameters for extending the built-in attribute catalog with custom entries.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `extra_attribute_keys` | `set[str]` | `set()` | Additional attribute keys recognized during extraction |
| `attribute_aliases` | `dict[str, str]` | `{}` | Aliases for attribute keys (e.g., `{"hometown": "city"}`) |
| `extra_namespaces` | `set[str]` | `set()` | Additional entity namespaces beyond built-in types |
| `extra_self_references` | `frozenset[str]` | `frozenset()` | Additional words treated as self-references (e.g., `{"yo"}` for Spanish) |
| `extra_relationship_hints` | `frozenset[str]` | `frozenset()` | Additional relationship hint words for entity resolution |

---

## Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `max_facts_per_event` | `int` | `100` | Maximum facts extracted from a single message |
| `embedding_dimensions` | `int` | `1536` | Dimensionality of embedding vectors (must match your provider) |
