fennec-memory
Production-grade memory, intelligent caching, and persistence for LLM and RAG applications
fennec-memory gives your AI application a complete memory stack — from short-term conversation buffers and semantic long-term memory, to a multi-level intelligent cache with semantic deduplication, to a durable persistence layer with encryption, versioning, and multi-tenant support.
What's Inside
The library is organized into three independent but composable subsystems:
| Subsystem | Module | Purpose |
|---|---|---|
| Memory | fennec_memory.memory |
Conversation and agent memory types |
| Cache | fennec_memory.cache |
Multi-level semantic + key-value cache |
| Persistence | fennec_memory.persistence |
Durable storage with security and versioning |
Installation
pip install fennec-memory
Install optional extras based on your stack:
pip install fennec-memory[redis] # Redis storage backend
pip install fennec-memory[faiss] # FAISS vector index for semantic cache
pip install fennec-memory[openai] # OpenAI embeddings
pip install fennec-memory[huggingface] # HuggingFace / sentence-transformers
pip install fennec-memory[ollama] # Ollama local embeddings
pip install fennec-memory[crypto] # Encryption for persistence layer
pip install fennec-memory[all] # Everything
Memory System
Conversation Memory Types
from fennec_memory.memory import (
ConversationBufferMemory,
ConversationBufferWindowMemory,
ConversationSummaryMemory,
ConversationEntityMemory,
)
# Simple buffer — keeps full history
mem = ConversationBufferMemory()
mem.add("user", "What is RAG?")
mem.add("assistant", "RAG stands for Retrieval-Augmented Generation.")
print(mem.get_history())
# Sliding window — keeps last N turns
window_mem = ConversationBufferWindowMemory(window_size=5)
# Summary memory — compresses old turns into a summary
summary_mem = ConversationSummaryMemory()
# Entity memory — tracks named entities across the conversation
entity_mem = ConversationEntityMemory()
Long-Term Memory
from fennec_memory.memory import LongTermMemory, MemoryConfig
config = MemoryConfig(
max_long_term=10_000,
importance_threshold=0.6,
enable_decay=True,
decay_rate=0.01,
enable_persistence=True,
persistence_path="./memory_store",
)
ltm = LongTermMemory(config=config)
ltm.store("The user prefers concise answers.", importance=0.85)
results = ltm.retrieve("user preferences", top_k=5)
Semantic Memory
from fennec_memory.memory import SemanticMemory
sem = SemanticMemory()
sem.add("Paris is the capital of France.")
sem.add("The Eiffel Tower is in Paris.")
results = sem.search("French landmarks", top_k=3)
for r in results:
print(r.text, r.score)
Intelligent Memory Manager
from fennec_memory.memory import AIMemoryManager, MemoryConfig
manager = AIMemoryManager(config=MemoryConfig())
# Automatically routes to short-term, working, or long-term
manager.remember("User said they are a software engineer.", importance=0.7)
# Retrieve relevant memories for a query
context = manager.recall("What do I know about this user?", top_k=5)
User Profile Manager
from fennec_memory.memory import UserProfileManager
profiles = UserProfileManager()
profiles.update("user_123", preferences={"language": "Arabic", "tone": "formal"})
profile = profiles.get("user_123")
print(profile.preferences)
Privacy & Security
from fennec_memory.memory import SensitiveDataMasker, MemoryEncryptor, AccessController, Permission
masker = SensitiveDataMasker()
safe_text = masker.mask("My SSN is 123-45-6789")
# "My SSN is ***-**-****"
encryptor = MemoryEncryptor(key="your-secret-key")
encrypted = encryptor.encrypt("sensitive memory content")
decrypted = encryptor.decrypt(encrypted)
RAG Context Builder
from fennec_memory.memory import ContextBuilder, Document
builder = ContextBuilder()
docs = [Document(content="...", metadata={"source": "wiki"})]
context = builder.build(query="What is RAG?", memories=mem.get_history(), documents=docs)
print(context.formatted_prompt)
Cache System
Multi-Level Semantic Cache
from fennec_memory.cache import MultiLevelCache, CacheConfig, StorageBackend
config = CacheConfig(
storage_backend=StorageBackend.SQLITE, # or REDIS, MEMORY
semantic_threshold=0.92, # cosine similarity for cache hit
ttl_seconds=3600,
)
cache = MultiLevelCache(config=config)
# Store a response
cache.set(query="What is the capital of France?", response="Paris.")
# Retrieve — returns on exact or semantic match
result = cache.get("Capital city of France?")
if result:
print(result.response) # "Paris." — semantic hit
print(result.similarity) # 0.96
Cache Manager with Embeddings
from fennec_memory.cache import CacheManager, CacheConfig
from fennec_memory.cache import OpenAIEmbeddingProvider, EmbeddingConfig
embedder = OpenAIEmbeddingProvider(
config=EmbeddingConfig(api_key="sk-..."),
)
cache_manager = CacheManager(config=CacheConfig(), embedder=embedder)
Redis Backend
from fennec_memory.cache import CacheConfig, StorageBackend, RedisConfig
config = CacheConfig(
storage_backend=StorageBackend.REDIS,
redis=RedisConfig(host="localhost", port=6379, db=0),
)
Multi-Tenant Cache
from fennec_memory.cache import TenantManager, TenantConfig
tenants = TenantManager()
tenants.register("tenant_a", TenantConfig(max_entries=5000, ttl_seconds=1800))
tenants.register("tenant_b", TenantConfig(max_entries=1000, ttl_seconds=600))
Embedding Providers
from fennec_memory.cache import (
OpenAIEmbeddingProvider,
HuggingFaceEmbeddingProvider,
OllamaEmbeddingProvider,
)
# OpenAI
provider = OpenAIEmbeddingProvider(api_key="sk-...")
# HuggingFace (local)
provider = HuggingFaceEmbeddingProvider(model="sentence-transformers/all-MiniLM-L6-v2")
# Ollama (local)
provider = OllamaEmbeddingProvider(model="nomic-embed-text")
Persistence System
Persistence Manager
from fennec_memory.persistence import PersistenceManager, PersistenceManagerConfig, StorageType
config = PersistenceManagerConfig(
default_storage=StorageType.KEY_VALUE,
enable_versioning=True,
enable_encryption=True,
)
pm = PersistenceManager(config=config)
# Store data
await pm.save(key="session:abc123", data={"messages": [...]})
# Retrieve
result = await pm.load(key="session:abc123")
print(result.data)
Storage Backends
from fennec_memory.persistence import KeyValueStorage, VectorStorage, DatabaseStorage, ObjectStorage
# Key-value store
kv = KeyValueStorage()
await kv.set("key", {"value": 42})
data = await kv.get("key")
# Vector store
vs = VectorStorage()
await vs.upsert(id="doc1", vector=[0.1, 0.2, ...], metadata={"source": "wiki"})
results = await vs.search(query_vector=[0.1, 0.2, ...], top_k=5)
Versioning & Snapshots
from fennec_memory.persistence import VersionManager, BackupManager
version_mgr = VersionManager()
version_mgr.save_version(key="config:v1", data={...})
history = version_mgr.get_history("config:v1")
backup_mgr = BackupManager()
snapshot = backup_mgr.create_snapshot("session:abc123")
backup_mgr.restore(snapshot)
Security & Encryption
from fennec_memory.persistence import EncryptionEngine, AccessControlManager, DataSanitizer, Permission
enc = EncryptionEngine(secret_key="your-32-byte-key")
encrypted = enc.encrypt(b"sensitive payload")
plain = enc.decrypt(encrypted)
acl = AccessControlManager()
acl.grant(user="alice", resource="session:*", permission=Permission.READ)
acl.check(user="bob", resource="session:xyz", permission=Permission.WRITE)
Storage Routing
from fennec_memory.persistence import StorageRouter, RoutingRule, DataTier
router = StorageRouter()
router.add_rule(RoutingRule(tier=DataTier.HOT, storage_type=StorageType.KEY_VALUE))
router.add_rule(RoutingRule(tier=DataTier.COLD, storage_type=StorageType.OBJECT))
Integration with fennec-community
fennec-memory is designed to work seamlessly alongside fennec-community and fennec-guard:
from fennec_memory.memory import AIMemoryManager, ContextBuilder
from fennec_memory.cache import MultiLevelCache
from fennec_community.rag.core import RAGSystem
memory = AIMemoryManager()
cache = MultiLevelCache()
rag = RAGSystem(...)
def chat(user_id: str, query: str) -> str:
# Check semantic cache first
cached = cache.get(query)
if cached:
return cached.response
# Retrieve relevant memories
past_context = memory.recall(query, top_k=5)
# Run RAG
answer = rag.query(query, extra_context=past_context)
# Store in memory and cache
memory.remember(f"Q: {query} A: {answer}", importance=0.6)
cache.set(query=query, response=answer)
return answer
Requirements
- Python >= 3.9
- pydantic >= 2.0
- numpy >= 1.24
All other dependencies are optional — install only what you need.
License
MIT License — see LICENSE for details.
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub.
Release files for fennec-memory 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fennec_memory-0.1.0.tar.gz | 113.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fennec_memory-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 247.3 kB
Release files / fennec_memory-0.1.0.tar.gz
| Download URL | fennec_memory-0.1.0.tar.gz |
|---|---|
| Size | 113.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec4852b041134be7b55b544c0c696133d73f1547127054512777e2d3d084c66c
|
|
BLAKE2b-256 checksum How to use checksums |
9969101f5a21ac1d52435f8a7b88698015067c14dbd0af227f128381815dd117
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Release files / fennec_memory-0.1.0-py3-none-any.whl
| Download URL | fennec_memory-0.1.0-py3-none-any.whl |
|---|---|
| Size | 133.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
13b4c4d65828f0f9d1a848c36cff2bf20d88e108adc94a4cfd2227e9caa34461
|
|
BLAKE2b-256 checksum How to use checksums |
7192920b1a6786530b022819e416ead06ef948a435442897c60e4e31e0fae926
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|