Python SDK
The official Python SDK for Recall provides a powerful, type-safe interface to the hybrid memory system.
Installation
bashpip install recall-memory
Requirements
- Python 3.8 or higher
- Redis 6.0+ (local or cloud)
- Mem0 API key
Quick Start
pythonfrom recall import RecallClient# Initialize the clientclient = RecallClient(redis_url="redis://localhost:6379",mem0_api_key="your-api-key")# Store a memorymemory = client.add(content="User prefers Python for data science",user_id="user_123",priority="high")# Search memoriesresults = client.search(query="programming preferences",user_id="user_123")
Client Configuration
Environment Variables
The SDK automatically reads from environment variables:
pythonimport osfrom recall import RecallClient# Set environment variablesos.environ["RECALL_REDIS_URL"] = "redis://localhost:6379"os.environ["RECALL_MEM0_API_KEY"] = "your-api-key"os.environ["RECALL_ENVIRONMENT"] = "production"# Client auto-configures from environmentclient = RecallClient()
Configuration File
Load configuration from YAML or JSON:
pythonfrom recall import RecallClient# From YAML fileclient = RecallClient.from_config("recall.yaml")# From JSON fileclient = RecallClient.from_config("recall.json")# From dictionaryconfig = {"redis": {"url": "redis://localhost:6379"},"mem0": {"api_key": "your-api-key"},"cache": {"ttl": 3600}}client = RecallClient.from_dict(config)
Advanced Configuration
pythonfrom recall import RecallClient, CacheConfig, SyncConfigfrom recall.serializers import MessagePackSerializerclient = RecallClient(redis_url="redis://localhost:6379",mem0_api_key="your-api-key",# Cache configurationcache_config=CacheConfig(ttl=3600,max_memory="1gb",eviction_policy="allkeys-lru",compression=True,serializer=MessagePackSerializer()),# Sync configurationsync_config=SyncConfig(mode="lazy",batch_size=100,interval=60),# Connection configurationredis_connection_pool_kwargs={"max_connections": 50,"socket_keepalive": True,"socket_keepalive_options": {1: 1, # TCP_KEEPIDLE2: 1, # TCP_KEEPINTVL3: 5, # TCP_KEEPCNT}},# Performance optionsenable_pipelining=True,enable_lua_scripts=True,# Monitoringenable_metrics=True,metrics_port=9090)
Type Safety
The SDK includes comprehensive type hints:
pythonfrom recall import RecallClient, Memory, Priorityfrom typing import List, Optionaldef store_user_preference(client: RecallClient,user_id: str,preference: str,priority: Priority = Priority.MEDIUM) -> Memory:"""Store a user preference with type safety."""return client.add(content=preference,user_id=user_id,priority=priority)def get_preferences(client: RecallClient,user_id: str,category: Optional[str] = None) -> List[Memory]:"""Retrieve user preferences with filtering."""filters = {"category": category} if category else Nonereturn client.search(query="preferences",user_id=user_id,filters=filters)
Async Support
AsyncRecallClient
pythonimport asynciofrom recall import AsyncRecallClientasync def main():# Initialize async clientclient = AsyncRecallClient(redis_url="redis://localhost:6379",mem0_api_key="your-api-key")# Async operationsmemory = await client.add(content="Async memory operation",user_id="user_123")# Concurrent operationstasks = []for i in range(10):task = client.add(content=f"Memory {i}",user_id="user_123")tasks.append(task)memories = await asyncio.gather(*tasks)print(f"Created {len(memories)} memories concurrently")# Async context managerasync with AsyncRecallClient() as client:await client.add(content="Auto-cleanup", user_id="user_123")asyncio.run(main())
Async Streaming
pythonimport asynciofrom recall import AsyncRecallClientasync def stream_memories():client = AsyncRecallClient()# Stream search resultsasync for memory in client.stream_search(query="user interactions",user_id="user_123",batch_size=10):print(f"Processing: {memory.content}")# Process each memory as it arrives# Stream all memoriesasync for batch in client.stream_all(user_id="user_123",batch_size=50):print(f"Batch of {len(batch)} memories")# Process batchasyncio.run(stream_memories())
Context Managers
Automatic Resource Management
pythonfrom recall import RecallClient# Automatic cleanup with context managerwith RecallClient() as client:client.add(content="Memory", user_id="user_123")# Connection automatically closed# Transaction supportwith client.transaction() as tx:tx.add(content="Memory 1", user_id="user_123")tx.add(content="Memory 2", user_id="user_123")# Atomic commit or rollback
Decorators
Caching Decorator
pythonfrom recall.decorators import recall_cachefrom recall import RecallClientclient = RecallClient()@recall_cache(client, ttl=3600)def expensive_computation(user_id: str, query: str):"""This function's results will be cached."""# Expensive operationreturn complex_calculation(user_id, query)# First call: computes and cachesresult = expensive_computation("user_123", "data")# Second call: returns from cacheresult = expensive_computation("user_123", "data")
Memory Decorator
pythonfrom recall.decorators import rememberfrom recall import RecallClientclient = RecallClient()@remember(client, priority="high")def user_action(user_id: str, action: str):"""Automatically stores function calls as memories."""# Perform actionreturn f"Completed {action}"# Function call is automatically rememberedresult = user_action("user_123", "changed settings")# Memory stored: "user_123 performed: changed settings"
Data Models
Memory Model
pythonfrom recall.models import Memory, Priorityfrom datetime import datetime# Create a memory objectmemory = Memory(id="mem_123",content="User preference",user_id="user_123",priority=Priority.HIGH,created_at=datetime.now(),metadata={"category": "preferences","source": "settings"})# Access propertiesprint(memory.content)print(memory.priority.value) # "high"print(memory.age_seconds)print(memory.to_dict())
Batch Operations
pythonfrom recall.models import MemoryBatch# Create batchbatch = MemoryBatch()batch.add(content="Memory 1", user_id="user_123")batch.add(content="Memory 2", user_id="user_123")batch.add(content="Memory 3", user_id="user_123")# Execute batchresults = client.add_batch(batch)# Batch with validationbatch = MemoryBatch(validate=True, max_size=100)try:batch.add(content="", user_id="") # Raises ValidationErrorexcept ValidationError as e:print(f"Invalid memory: {e}")
Serialization
Custom Serializers
pythonfrom recall import RecallClientfrom recall.serializers import (JSONSerializer,MessagePackSerializer,PickleSerializer,ProtobufSerializer)# JSON (default)client = RecallClient(serializer=JSONSerializer())# MessagePack (faster, smaller)client = RecallClient(serializer=MessagePackSerializer())# Pickle (Python objects)client = RecallClient(serializer=PickleSerializer())# Protocol Buffersclient = RecallClient(serializer=ProtobufSerializer())# Custom serializerclass CustomSerializer:def serialize(self, obj):# Custom serialization logicreturn custom_encode(obj)def deserialize(self, data):# Custom deserialization logicreturn custom_decode(data)client = RecallClient(serializer=CustomSerializer())
Middleware
Request Middleware
pythonfrom recall import RecallClientfrom recall.middleware import Middlewareclass LoggingMiddleware(Middleware):def before_request(self, method, *args, **kwargs):print(f"Calling {method} with args={args}, kwargs={kwargs}")def after_request(self, method, result):print(f"{method} returned {result}")return resultdef on_error(self, method, error):print(f"{method} failed with {error}")raise error# Add middlewareclient = RecallClient()client.add_middleware(LoggingMiddleware())# All requests now loggedclient.add(content="Test", user_id="user_123")
Built-in Middleware
pythonfrom recall.middleware import (RetryMiddleware,RateLimitMiddleware,MetricsMiddleware,CacheMiddleware)client = RecallClient()# Add retry logicclient.add_middleware(RetryMiddleware(max_retries=3))# Add rate limitingclient.add_middleware(RateLimitMiddleware(max_requests=100,window_seconds=60))# Add metrics collectionclient.add_middleware(MetricsMiddleware(prometheus_port=9090))
Testing
Mock Client
pythonfrom recall.testing import MockRecallClientimport pytest@pytest.fixturedef recall_client():"""Fixture providing mock client for tests."""return MockRecallClient()def test_memory_storage(recall_client):# Add memorymemory = recall_client.add(content="Test memory",user_id="test_user")assert memory.id.startswith("mem_")# Verify storageassert recall_client.call_count("add") == 1assert recall_client.last_call("add").content == "Test memory"# Searchresults = recall_client.search(query="test",user_id="test_user")assert len(results) == 1
Test Utilities
pythonfrom recall.testing import (create_test_memory,populate_test_data,assert_memory_equal)# Create test datamemory = create_test_memory(content="Test content",priority="high")# Populate with sample dataclient = RecallClient()populate_test_data(client, user_id="test_user", count=100)# Assert memories are equalassert_memory_equal(memory1, memory2)
Monitoring
Metrics Collection
pythonfrom recall import RecallClientfrom recall.monitoring import MetricsCollector# Enable metricsclient = RecallClient(enable_metrics=True)# Access metricsmetrics = client.get_metrics()print(f"Total operations: {metrics.total_operations}")print(f"Cache hit rate: {metrics.cache_hit_rate:.2%}")print(f"Average latency: {metrics.avg_latency_ms:.2f}ms")# Export to Prometheusclient.export_metrics_prometheus(port=9090)# Export to StatsDclient.export_metrics_statsd(host="localhost",port=8125,prefix="recall")
Logging
pythonimport loggingfrom recall import RecallClient# Configure logginglogging.basicConfig(level=logging.DEBUG)# Client with debug loggingclient = RecallClient(debug=True)# Custom loggerlogger = logging.getLogger("my_app")client = RecallClient(logger=logger)# Log levelsclient.set_log_level(logging.WARNING)
Error Handling
Exception Hierarchy
pythonfrom recall.exceptions import (RecallError,ConnectionError,AuthenticationError,ValidationError,CacheError,SyncError,RateLimitError,TimeoutError)try:client.add(content="", user_id="")except ValidationError as e:# Handle validation errorsprint(f"Invalid input: {e.field} - {e.message}")except ConnectionError as e:# Handle connection issuesprint(f"Connection failed: {e.service} - {e.message}")except RecallError as e:# Catch all Recall errorsprint(f"Error: {e}")
Retry Logic
pythonfrom recall import RecallClientfrom recall.retry import exponential_backoffclient = RecallClient(retry_config={"max_attempts": 3,"backoff": exponential_backoff(base=2, max_delay=30),"retry_on": [ConnectionError, TimeoutError]})# Operations automatically retry on failurememory = client.add(content="Important", user_id="user_123")
CLI Usage
The SDK includes a CLI tool:
bash# Check statusrecall status# Add memoryrecall add "User preference" --user-id user_123 --priority high# Search memoriesrecall search "preferences" --user-id user_123 --limit 10# Get statisticsrecall stats# Clear cacherecall cache clear --user-id user_123# Export datarecall export --format json --output memories.json# Import datarecall import memories.json
Best Practices
Connection Pooling
pythonfrom recall import RecallClientfrom redis.connection import ConnectionPool# Share connection pool across clientspool = ConnectionPool(host='localhost',port=6379,max_connections=50)client1 = RecallClient(redis_connection_pool=pool)client2 = RecallClient(redis_connection_pool=pool)
Memory Management
python# Use appropriate priority levelsclient.add(content="Critical user data",user_id="user_123",priority="critical" # Never evicted)client.add(content="Temporary preference",user_id="user_123",priority="low", # First to evictmetadata={"expires_at": "2024-12-31"})
Performance Optimization
python# Batch operations for better performancememories = [{"content": f"Memory {i}", "user_id": "user_123"}for i in range(1000)]# Slow: Individual callsfor memory in memories:client.add(**memory)# Fast: Batch callclient.add_batch(memories)# Pipeline for multiple operationswith client.pipeline() as pipe:pipe.add(content="Memory 1", user_id="user_123")pipe.add(content="Memory 2", user_id="user_123")pipe.search(query="test", user_id="user_123")results = pipe.execute()
Migration Guide
From Mem0
python# Before (Mem0)from mem0 import Memorym = Memory()m.add("Memory content", user_id="user_123")# After (Recall)from recall import RecallClientclient = RecallClient()client.add(content="Memory content", user_id="user_123")
From Redis
python# Before (Redis)import redisr = redis.Redis()r.set("user:123:pref", "dark_mode")# After (Recall)from recall import RecallClientclient = RecallClient()client.add(content="Prefers dark mode",user_id="user_123",metadata={"key": "user:123:pref"})
Next Steps
- Review TypeScript SDK for Node.js applications
- Explore API Reference for detailed method documentation
- Check Examples for real-world use cases