The Problem with Timeless Memory
Most memory systems treat every stored piece of information as permanently important. A vector database doesn't know — or care — whether a memory was created 5 minutes ago or 5 months ago. When you search, all memories compete equally regardless of age.
This creates two problems for AI agents:
- Stale context dominance — old, possibly outdated information outranks recent updates because it has had more time to accumulate and has many variations that match different queries.
- Context window pollution — when an agent retrieves memories to inject into its prompt, stale memories consume tokens that should be used for fresh, relevant context.
Temporal memory solves this by treating time as a first-class dimension of retrieval. Memories have a lifecycle: they're created with full strength, can be reinforced by access, and gradually decay when no longer relevant.
The Scoring Formula
When Dakera retrieves memories, the final ranking score is a composite of multiple signals:
final_score = (relevance_weight * relevance_score)
+ (recency_weight * recency_score)
+ (importance_weight * importance_score)
- decay_penalty
Each component contributes different information:
- Relevance score — semantic similarity (HNSW) + keyword match (BM25), fused and reranked
- Recency score — how recently the memory was created or accessed
- Importance score — explicit or inferred criticality of the memory
- Decay penalty — time-based degradation based on the configured strategy
Memory Decay Strategies
Dakera implements 6 decay strategies, each modeling a different forgetting curve. The choice of strategy depends on the type of memory you're storing.
Exponential Decay
Memories lose strength rapidly at first, then more slowly. Models the classic Ebbinghaus forgetting curve. Best for working memory — scratchpads, intermediate reasoning steps, transient observations.
# strength(t) = initial_strength * e^(-lambda * t)
# Half-life of 24 hours: memory is at 50% after 1 day, 25% after 2 days
client.namespace.configure(
namespace="agent-scratch",
decay_strategy="exponential",
decay_half_life_hours=24
)
| Time | Strength |
|---|---|
| 0 hours | 100% |
| 24 hours | 50% |
| 48 hours | 25% |
| 72 hours | 12.5% |
| 7 days | 0.8% |
Logarithmic Decay
Slow initial decay that accelerates over time. Memories stay strong for a while, then fade quickly. Best for medium-term context — project notes, meeting summaries, weekly updates.
# strength(t) = 1 - log(1 + alpha * t) / log(1 + alpha * max_t)
client.namespace.configure(
namespace="project-notes",
decay_strategy="logarithmic",
decay_half_life_hours=168 # ~1 week
)
Linear Decay
Constant decay rate — memories lose the same amount of strength per unit time. Simple and predictable. Best for time-boxed contexts where you want memories to expire after a known duration.
# strength(t) = max(0, 1 - t / max_lifetime)
client.namespace.configure(
namespace="daily-standup",
decay_strategy="linear",
decay_half_life_hours=48
)
Step Decay
Discrete importance levels that downshift on schedule. Memory stays at full strength for a period, then drops to the next level. Models how we categorize memories into "recent", "relevant", "archive".
# strength(t) = step_levels[floor(t / step_interval)]
# Example: 1.0 for 7 days, 0.6 for 30 days, 0.2 after 90 days
client.namespace.configure(
namespace="customer-interactions",
decay_strategy="step",
decay_steps=[
{"until_hours": 168, "strength": 1.0}, # Fresh: 7 days
{"until_hours": 720, "strength": 0.6}, # Relevant: 30 days
{"until_hours": 2160, "strength": 0.2} # Archive: 90 days
]
)
Adaptive Decay
Decay rate adjusts based on access patterns. Memories that are frequently retrieved strengthen (like spaced repetition). Memories that are never accessed decay faster. This is the most sophisticated strategy and models long-term potentiation in biological memory.
# Each access resets the decay clock and slightly strengthens the memory
# Unused memories decay at an accelerating rate
client.namespace.configure(
namespace="user-preferences",
decay_strategy="adaptive",
decay_half_life_hours=720, # Base: 30 days
access_boost_factor=1.5, # Each access extends effective half-life by 50%
neglect_acceleration=1.2 # Unused memories decay 20% faster per period
)
No Decay
Some memories should never fade — user identity, critical facts, system configuration. Use no decay for truly permanent memories:
client.namespace.configure(
namespace="core-identity",
decay_strategy="none"
)
# These memories will always compete at full strength
client.memory.add(
namespace="core-identity",
content="The user's name is Alice Chen and she prefers to be called Alice",
importance=1.0
)
Importance Scoring
Importance scoring determines how much weight a memory carries independent of its age or relevance to the current query. There are two approaches: explicit and inferred.
Explicit Importance
The agent or application assigns an importance score at write time:
# Critical operational knowledge — never let this decay below threshold
client.memory.add(
namespace="ops",
content="Production database password was rotated on 2026-05-16. New credentials in vault.",
importance=1.0 # Maximum importance
)
# Casual observation — fine to forget
client.memory.add(
namespace="ops",
content="The user mentioned they enjoy the new dashboard color scheme",
importance=0.2 # Low importance
)
Inferred Importance
Dakera's ML query classifier can infer importance based on the content's characteristics. Memories containing:
- Named entities (people, organizations, products) score higher
- Temporal references ("always", "never", "every Monday") score higher
- Quantitative data (numbers, dates, measurements) score higher
- Action items or decisions score higher
- Filler words, pleasantries, or hedging language score lower
Recency Weighting at Query Time
Beyond passive decay, Dakera supports active recency weighting at query time. This lets the same namespace serve different query patterns:
# High recency weight: "what happened recently?"
recent_events = client.memory.search(
namespace="project-log",
query="recent progress updates",
limit=5,
recency_weight=0.7 # Heavily favor recent memories
)
# Low recency weight: "what's the overall architecture?"
architecture = client.memory.search(
namespace="project-log",
query="system architecture decisions",
limit=5,
recency_weight=0.1 # Relevance dominates, age barely matters
)
Temporal Queries
Sometimes the agent needs to answer explicitly temporal questions: "what did the user say last week about their budget?" or "has this error happened before?" Dakera supports temporal filtering alongside semantic search:
# Search within a time range
last_week = client.memory.search(
namespace="conversations",
query="budget discussion",
limit=5,
created_after="2026-05-09T00:00:00Z",
created_before="2026-05-16T00:00:00Z"
)
# Find the earliest memory matching a pattern
first_occurrence = client.memory.search(
namespace="incidents",
query="database connection timeout",
limit=1,
sort_by="created_at",
sort_order="asc"
)
How Temporal Memory Affects Benchmark Scores
The LoCoMo benchmark specifically tests temporal reasoning — one of three question categories (alongside single-hop and multi-hop). Systems without temporal awareness systematically fail questions like:
- "When did Alice change her mind about the project?"
- "What was the most recent update about the deadline?"
- "Has the user's preference on this topic changed over time?"
Dakera's temporal memory system is a significant contributor to its 87.6% overall LoCoMo score, particularly on Category 3 (temporal inference) questions where it achieves 70.7% — compared to systems without temporal awareness that typically score below 40% on the same category.
For more details on how we benchmark temporal reasoning, see our benchmark methodology post.
Choosing the Right Decay Strategy
| Use Case | Strategy | Half-Life |
|---|---|---|
| Scratch/working memory | Exponential | 1-24 hours |
| Conversation context | Exponential | 24-72 hours |
| Project notes | Logarithmic | 1-4 weeks |
| Customer interactions | Step | 7/30/90 day tiers |
| User preferences | Adaptive | 30+ days |
| Identity/facts | None | Infinite |
Implementation Pattern: Multi-Layer Memory
A production agent typically uses multiple namespaces with different decay strategies, forming a memory hierarchy:
from dakera import Dakera
client = Dakera(base_url="http://localhost:3300")
class AgentMemory:
"""Multi-layer memory with different temporal behaviors."""
def __init__(self, agent_id: str):
self.agent_id = agent_id
# Configure layers
self.layers = {
"working": f"{agent_id}-working", # Exponential, 4h
"session": f"{agent_id}-session", # Exponential, 48h
"learned": f"{agent_id}-learned", # Adaptive, 30d
"identity": f"{agent_id}-identity", # None (permanent)
}
def remember(self, content: str, layer: str = "session", importance: float = 0.5):
"""Store a memory in the appropriate layer."""
client.memory.add(
namespace=self.layers[layer],
content=content,
importance=importance
)
def recall(self, query: str, recency_weight: float = 0.3):
"""Search across all layers, merging results."""
all_results = []
for layer_name, namespace in self.layers.items():
results = client.memory.search(
namespace=namespace,
query=query,
limit=3,
recency_weight=recency_weight
)
for r in results:
r.layer = layer_name
all_results.extend(results)
# Sort by composite score across layers
all_results.sort(key=lambda r: r.score, reverse=True)
return all_results[:5]
# Usage
memory = AgentMemory("support-agent-1")
memory.remember("User's name is Alice", layer="identity", importance=1.0)
memory.remember("Alice asked about API rate limits", layer="session")
memory.remember("Working on response draft...", layer="working", importance=0.1)
Conclusion
Temporal memory transforms agents from stateless responders into systems that understand the passage of time. The key insight is that memory strength should not be binary (present or absent) — it exists on a spectrum that naturally evolves. Important memories persist. Ephemeral context fades. And the agent's recall patterns start to resemble the intelligent, adaptive behavior we expect from systems that truly "remember."