Memory Providers¶
FastAgentic provides a unified memory abstraction for agent state persistence. Memory providers handle short-term context, long-term recall, and session management.
Philosophy¶
| Type | FastAgentic Builds | Integrate Instead |
|---|---|---|
| Session memory | Redis (simple) | - |
| Checkpoints | Redis/Postgres | - |
| Long-term memory | Abstract interface | Mem0, Zep |
| Semantic search | None | Mem0, Zep, custom |
FastAgentic provides simple built-in options and interfaces to specialized memory systems.
Memory Types¶
Short-Term Memory (Session)¶
Holds context within a single conversation/session:
from fastagentic import App
from fastagentic.memory import RedisSessionMemory
app = App(
session_memory=RedisSessionMemory(
url="redis://localhost:6379",
ttl_seconds=3600, # 1 hour
),
)
Long-Term Memory (Cross-Session)¶
Persists user context across sessions:
from fastagentic import App
from fastagentic.integrations.mem0 import Mem0Provider
app = App(
memory=Mem0Provider(api_key="..."),
)
Checkpoint Memory (Durable Runs)¶
Stores agent execution state for resume:
Provider Interface¶
All memory providers implement this interface:
from abc import ABC, abstractmethod
from typing import Any
class MemoryProvider(ABC):
"""Abstract base for memory providers."""
@abstractmethod
async def add(
self,
user_id: str,
content: str | list[dict],
metadata: dict = None,
) -> str:
"""
Add memory content.
Args:
user_id: User identifier
content: Text or messages to memorize
metadata: Optional metadata (category, tags, etc.)
Returns:
Memory ID
"""
...
@abstractmethod
async def search(
self,
user_id: str,
query: str,
limit: int = 10,
filters: dict = None,
) -> list[dict]:
"""
Search memories.
Args:
user_id: User identifier
query: Search query
limit: Max results
filters: Optional filters (category, date range, etc.)
Returns:
List of memory objects with score
"""
...
@abstractmethod
async def get(self, user_id: str, memory_id: str) -> dict | None:
"""Get specific memory by ID."""
...
@abstractmethod
async def get_all(self, user_id: str, limit: int = 100) -> list[dict]:
"""Get all memories for user."""
...
@abstractmethod
async def update(
self,
user_id: str,
memory_id: str,
content: str = None,
metadata: dict = None,
) -> None:
"""Update existing memory."""
...
@abstractmethod
async def delete(self, user_id: str, memory_id: str) -> None:
"""Delete specific memory."""
...
@abstractmethod
async def delete_all(self, user_id: str) -> int:
"""Delete all memories for user. Returns count deleted."""
...
Built-in Providers¶
RedisProvider¶
Simple key-value memory without semantic search:
from fastagentic.memory import RedisProvider
memory = RedisProvider(
url="redis://localhost:6379",
prefix="memory:",
ttl_seconds=None, # No expiration
)
Capabilities: - Fast read/write - Simple key-value storage - No semantic search - Good for: Session state, simple recall
Methods:
# Add memory (stored as JSON)
memory_id = await memory.add(
user_id="user_123",
content="User prefers dark mode",
metadata={"category": "preferences"},
)
# Get by key pattern
memories = await memory.get_all(user_id="user_123")
# No semantic search - exact match only
# search() returns all memories (no ranking)
PostgresProvider¶
Relational storage with optional pgvector:
from fastagentic.memory import PostgresProvider
memory = PostgresProvider(
url="postgres://user:pass@localhost/db",
table="agent_memories",
# Optional: Enable vector search with pgvector
vector_enabled=True,
embedding_model="text-embedding-3-small",
)
Capabilities: - Relational queries - Full-text search - Vector search (with pgvector) - Good for: Enterprise, complex queries
Integrated Providers¶
Mem0Provider¶
Specialized AI memory with automatic extraction:
from fastagentic.integrations.mem0 import Mem0Provider
memory = Mem0Provider(
api_key="...",
# Optional: self-hosted config
config={
"vector_store": {"provider": "qdrant", ...},
"llm": {"provider": "openai", ...},
},
)
Capabilities: - Automatic memory extraction from conversations - Semantic search - Memory consolidation - Entity recognition - Good for: Personalization, long-term user context
See Mem0 Integration for details.
ZepProvider¶
Session memory with auto-summarization:
from fastagentic.integrations.zep import ZepProvider
memory = ZepProvider(
api_key="...",
# Or self-hosted
url="http://localhost:8000",
)
Capabilities: - Conversation history with summarization - Semantic search - Entity extraction - Temporal awareness - Good for: Chat applications, session context
Using Memory in Agents¶
Automatic Injection¶
Inject relevant memories into agent context:
from fastagentic import agent_endpoint
from fastagentic.memory import inject_memory
@agent_endpoint(
path="/chat",
runnable=...,
memory=inject_memory(
provider=Mem0Provider(...),
strategy="relevant",
max_memories=10,
),
)
async def chat(message: str, ctx: AgentContext) -> str:
# Memories automatically in ctx.memories
# and injected into agent's context
...
Injection Strategies¶
# Semantic similarity to current query
inject_memory(strategy="relevant", max_memories=10, min_relevance=0.7)
# Most recent memories
inject_memory(strategy="recent", max_memories=20)
# All memories (use with caution)
inject_memory(strategy="all", max_memories=50)
# Custom strategy
inject_memory(
strategy="custom",
selector=lambda ctx, memories: filter_by_category(memories, "important"),
)
Manual Access¶
@agent_endpoint(path="/chat", runnable=...)
async def chat(message: str, ctx: AgentContext) -> str:
# Access memory provider directly
memory = ctx.memory
# Search for relevant context
memories = await memory.search(
user_id=ctx.user.id,
query=message,
limit=5,
)
# Build context
memory_context = "\n".join([
f"- {m['content']}" for m in memories
])
# Run agent with context
response = await agent.run(
message,
context={"memories": memory_context},
)
# Store new memories from conversation
await memory.add(
user_id=ctx.user.id,
content=[
{"role": "user", "content": message},
{"role": "assistant", "content": response},
],
)
return response
Memory Hooks¶
Intercept memory operations:
from fastagentic.hooks import hook, HookContext
@hook("on_memory_add")
async def before_memory_add(ctx: HookContext):
# Filter sensitive content
if contains_pii(ctx.memory_content):
ctx.memory_content = redact_pii(ctx.memory_content)
@hook("on_memory_search")
async def after_memory_search(ctx: HookContext):
# Log memory access
await audit_log.record(
user=ctx.user.id,
action="memory_search",
query=ctx.memory_query,
results_count=len(ctx.memory_results),
)
Session Memory¶
Separate from long-term memory, session memory handles within-conversation context:
from fastagentic import App
from fastagentic.memory import RedisSessionMemory
app = App(
# Long-term memory
memory=Mem0Provider(...),
# Session memory (separate)
session_memory=RedisSessionMemory(
url="redis://localhost:6379",
ttl_seconds=3600, # 1 hour
max_messages=50, # Keep last 50 messages
),
)
Session Memory Interface¶
class SessionMemory(ABC):
"""Session-scoped conversation memory."""
@abstractmethod
async def get_messages(self, session_id: str) -> list[dict]:
"""Get conversation history."""
...
@abstractmethod
async def add_message(self, session_id: str, message: dict) -> None:
"""Add message to history."""
...
@abstractmethod
async def clear(self, session_id: str) -> None:
"""Clear session history."""
...
@abstractmethod
async def summarize(self, session_id: str) -> str:
"""Get summary of conversation."""
...
Checkpoint Memory¶
For durable runs, checkpoint memory stores execution state:
from fastagentic import App
app = App(
durable_store="redis://localhost:6379",
)
@agent_endpoint(
path="/long-task",
runnable=...,
durable=True, # Enables checkpointing
)
async def long_task(input: Input) -> Output:
...
Checkpoints are managed automatically by the durable run system. See Architecture for details.
Privacy and Compliance¶
User Data Isolation¶
# Memories are always scoped by user_id
await memory.search(user_id="user_a", query="...") # Only user_a's memories
await memory.search(user_id="user_b", query="...") # Only user_b's memories
GDPR Right to Deletion¶
@app.delete("/users/{user_id}/data")
async def delete_user_data(user_id: str, ctx: AppContext):
# Delete all memories
deleted_count = await ctx.memory.delete_all(user_id)
# Delete session data
await ctx.session_memory.clear(user_id)
# Delete checkpoints
await ctx.checkpoint_store.delete_user(user_id)
return {"deleted_memories": deleted_count}
Encryption¶
from fastagentic.memory import EncryptedProvider
memory = EncryptedProvider(
provider=Mem0Provider(...),
encryption_key=os.getenv("MEMORY_ENCRYPTION_KEY"),
)
Metrics¶
# Memory operations
fastagentic_memory_operations_total{provider="mem0", operation="add"} 1234
fastagentic_memory_operations_total{provider="mem0", operation="search"} 5678
fastagentic_memory_latency_ms{provider="mem0", operation="search", quantile="p99"} 145
# Memory size
fastagentic_memory_count{provider="mem0"} 50234
fastagentic_memory_bytes{provider="redis"} 1048576
Choosing a Provider¶
| Use Case | Recommended Provider |
|---|---|
| Simple session state | RedisProvider |
| Conversation history | ZepProvider |
| Long-term personalization | Mem0Provider |
| Enterprise/compliance | PostgresProvider |
| Semantic search required | Mem0Provider, ZepProvider |
| Self-hosted requirement | Any (all support self-host) |
Custom Provider¶
Implement your own:
from fastagentic.memory import MemoryProvider
class MyCustomProvider(MemoryProvider):
def __init__(self, connection_string: str):
self.db = connect(connection_string)
async def add(self, user_id: str, content: str, metadata: dict = None) -> str:
memory_id = generate_id()
await self.db.insert({
"id": memory_id,
"user_id": user_id,
"content": content,
"metadata": metadata or {},
"created_at": datetime.utcnow(),
})
return memory_id
async def search(self, user_id: str, query: str, limit: int = 10, filters: dict = None) -> list[dict]:
# Implement your search logic
...
# Implement other methods...