Session Management
Learn how to implement stateful applications with persistent
sessions, enabling memory across conversations, user-specific
contexts, and checkpoint-based recovery.
Overview
Session management in Praison Labs enables:
- Persistent conversations across multiple interactions
- User-specific memory and preferences
- State checkpointing and recovery
- Multi-agent state sharing
- Remote session connectivity
Basic Session Usage
Creating a Session
from praisonaiagents import Agent, Session
import uuid
# Create a unique session ID
session_id = str(uuid.uuid4())
# Create an agent
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant with memory"
)
# Create a session
session = Session(session_id=session_id, agent=agent)
# Interact with the session
response1 = session.chat("My name is Alice")
response2 = session.chat("What's my name?") # Will remember "Alice"
Persisting Session State
# Save session state
session.save("sessions/alice_session.pkl")
# Later, restore the session
restored_session = Session.load("sessions/alice_session.pkl")
# Continue conversation with context
response = restored_session.chat("What did we discuss earlier?")
Memory Integration
Short-term and Long-term Memory
from praisonaiagents import Agent, Session, Memory
# Configure memory
memory = Memory(
provider="sqlite", # or "chromadb", "mem0"
config={
"db_path": "memories.db",
"embedding_model": "text-embedding-ada-002"
}
)
# Create agent with memory
agent = Agent(
name="MemoryAgent",
instructions="Remember user preferences and past conversations",
memory=memory
)
# Session with persistent memory
session = Session(
session_id="user_123",
agent=agent,
persist_memory=True
)
# Memory is automatically saved and retrieved
session.chat("I prefer Python over JavaScript")
session.chat("My favourite colour is blue")
# Later sessions will remember
new_session = Session(session_id="user_123", agent=agent)
response = new_session.chat("What's my favourite programming language?")
# Response: "Based on our previous conversation, your favourite programming language is Python"
Memory Quality and Filtering
from praisonaiagents import Memory, QualityFilter
# Memory with quality scoring
memory = Memory(
provider="chromadb",
quality_threshold=0.7, # Only store high-quality memories
max_memories=1000 # Limit memory size
)
# Custom quality filter
def quality_scorer(memory_item):
# Score based on relevance, recency, and importance
relevance_score = memory_item.get("relevance", 0.5)
recency_factor = calculate_recency(memory_item["timestamp"])
importance = memory_item.get("importance", 0.5)
return (relevance_score * 0.4 +
recency_factor * 0.3 +
importance * 0.3)
memory.set_quality_scorer(quality_scorer)
Advanced Session Patterns
Multi-Agent Sessions
from praisonaiagents import Agent, Session, SharedState
# Shared state for agents
shared_state = SharedState()
# Create specialised agents
research_agent = Agent(
name="Researcher",
instructions="Research topics thoroughly"
)
writer_agent = Agent(
name="Writer",
instructions="Write based on research"
)
# Create session with multiple agents
session = Session(
session_id="project_x",
agents={
"research": research_agent,
"writer": writer_agent
},
shared_state=shared_state
)
# Agents share state
session.run_agent("research", "Research quantum computing")
session.run_agent("writer", "Write an article based on the research")
Session Checkpointing
class CheckpointedSession(Session):
def __init__(self, *args, checkpoint_interval=5, **kwargs):
super().__init__(*args, **kwargs)
self.checkpoint_interval = checkpoint_interval
self.interaction_count = 0
self.checkpoint_dir = f"checkpoints/{self.session_id}"
def chat(self, message):
response = super().chat(message)
self.interaction_count += 1
if self.interaction_count % self.checkpoint_interval == 0:
self.create_checkpoint()
return response
def create_checkpoint(self):
checkpoint_path = f"{self.checkpoint_dir}/checkpoint_{self.interaction_count}.pkl"
self.save(checkpoint_path)
print(f"Checkpoint created: {checkpoint_path}")
def restore_checkpoint(self, checkpoint_number):
checkpoint_path = f"{self.checkpoint_dir}/checkpoint_{checkpoint_number}.pkl"
restored = Session.load(checkpoint_path)
self.__dict__.update(restored.__dict__)
print(f"Restored to checkpoint {checkpoint_number}")
Session Context Building
from datetime import datetime
class ContextualSession(Session):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.context_window = 10 # Keep last 10 interactions
self.user_profile = {}
self.session_metadata = {
"created_at": datetime.now(),
"interactions": 0
}
def build_context(self):
# Build context from recent history
recent_history = self.get_history()[-self.context_window:]
context = {
"user_profile": self.user_profile,
"recent_topics": self.extract_topics(recent_history),
"session_duration": (datetime.now() - self.session_metadata["created_at"]).seconds,
"interaction_count": self.session_metadata["interactions"]
}
return context
def chat(self, message):
# Update metadata
self.session_metadata["interactions"] += 1
# Add context to agent
context = self.build_context()
self.agent.context = context
return super().chat(message)
def update_profile(self, key, value):
self.user_profile[key] = value
Remote Sessions
Connecting to Remote Agents
from praisonaiagents import Session
# Connect to remote agent
remote_session = Session(
agent_url="http://192.168.1.100:8000/agent",
session_id="user_456"
)
# Interact normally
response = remote_session.chat("Hello from remote client")
# Session state is maintained on the server
Distributed Session State
import redis
import json
class DistributedSession(Session):
def __init__(self, *args, redis_host="localhost", redis_port=6379, **kwargs):
super().__init__(*args, **kwargs)
self.redis_client = redis.Redis(host=redis_host, port=redis_port)
self.state_key = f"session:{self.session_id}"
def save_state(self):
# Save state to Redis
state = {
"history": self.get_history(),
"user_data": getattr(self, "user_data", {}),
"metadata": getattr(self, "metadata", {})
}
self.redis_client.set(
self.state_key,
json.dumps(state),
ex=3600 # Expire after 1 hour
)
def load_state(self):
# Load state from Redis
state_data = self.redis_client.get(self.state_key)
if state_data:
state = json.loads(state_data)
self.set_history(state["history"])
self.user_data = state["user_data"]
self.metadata = state["metadata"]
return True
return False
def chat(self, message):
# Load latest state
self.load_state()
# Process message
response = super().chat(message)
# Save updated state
self.save_state()
return response
State Operations
State Versioning
class VersionedSession(Session):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.state_versions = []
self.current_version = 0
def save_version(self, description=""):
version = {
"version": self.current_version,
"timestamp": datetime.now(),
"description": description,
"state": self.get_state()
}
self.state_versions.append(version)
self.current_version += 1
return self.current_version - 1
def restore_version(self, version_number):
for version in self.state_versions:
if version["version"] == version_number:
self.set_state(version["state"])
return True
return False
def list_versions(self):
return [
{
"version": v["version"],
"timestamp": v["timestamp"],
"description": v["description"]
}
for v in self.state_versions
]
State Merging
class MergableSession(Session):
def merge_sessions(self, other_session):
# Merge conversation histories
merged_history = self.get_history() + other_session.get_history()
merged_history.sort(key=lambda x: x.get("timestamp", 0))
# Merge user data
merged_user_data = {**self.user_data, **other_session.user_data}
# Create new session with merged state
merged_session = Session(
session_id=f"{self.session_id}_merged",
agent=self.agent
)
merged_session.set_history(merged_history)
merged_session.user_data = merged_user_data
return merged_session
Workflow Integration
Stateful Workflows
from praisonaiagents import Agent, Task, Workflow, Session
class StatefulWorkflow:
def __init__(self, session_id):
self.session = Session(session_id=session_id)
self.agents = self.create_agents()
self.workflow = None
def create_agents(self):
return {
"planner": Agent(name="Planner", instructions="Plan tasks"),
"executor": Agent(name="Executor", instructions="Execute tasks"),
"reviewer": Agent(name="Reviewer", instructions="Review results")
}
def create_workflow(self, objective):
# Load session state
session_context = self.session.get_context()
tasks = [
Task(
description=f"Plan steps for: {objective}",
agent=self.agents["planner"],
context=session_context
),
Task(
description="Execute the planned steps",
agent=self.agents["executor"],
depends_on=["task_1"]
),
Task(
description="Review and summarise results",
agent=self.agents["reviewer"],
depends_on=["task_2"]
)
]
self.workflow = Workflow(tasks=tasks)
def run(self, objective):
self.create_workflow(objective)
results = self.workflow.run()
# Save results to session
self.session.add_result(objective, results)
self.session.save(f"sessions/{self.session.session_id}_workflow.pkl")
return results
Best Practices
1. Session Lifecycle Management
class ManagedSession(Session):
def __enter__(self):
# Load existing state if available
try:
self.load(f"sessions/{self.session_id}.pkl")
except FileNotFoundError:
pass
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# Always save state on exit
self.save(f"sessions/{self.session_id}.pkl")
# Usage
with ManagedSession(session_id="user_789") as session:
response = session.chat("Process this request")
# State automatically saved on exit
2. Session Cleanup
import os
from datetime import datetime, timedelta
def cleanup_old_sessions(session_dir="sessions", days_to_keep=30):
cutoff_date = datetime.now() - timedelta(days=days_to_keep)
for filename in os.listdir(session_dir):
filepath = os.path.join(session_dir, filename)
# Check file age
file_modified = datetime.fromtimestamp(os.path.getmtime(filepath))
if file_modified < cutoff_date:
os.remove(filepath)
print(f"Removed old session: {filename}")
3. Security Considerations
import hmac
import hashlib
class SecureSession(Session):
def __init__(self, *args, secret_key=None, **kwargs):
super().__init__(*args, **kwargs)
self.secret_key = secret_key or os.urandom(32)
def generate_session_token(self):
# Generate secure session token
message = f"{self.session_id}:{datetime.now().isoformat()}"
signature = hmac.new(
self.secret_key,
message.encode(),
hashlib.sha256
).hexdigest()
return f"{message}:{signature}"
def verify_session_token(self, token):
try:
message, signature = token.rsplit(":", 1)
expected_signature = hmac.new(
self.secret_key,
message.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
except:
return False
Common Patterns
User Preference Management
session.update_preference("language", "en-GB")
session.update_preference("timezone", "Europe/London")
session.update_preference("output_format", "detailed")
Conversation Branching
# Save current state
branch_point = session.create_checkpoint()
# Explore one path
response1 = session.chat("What if we use approach A?")
# Return to branch point
session.restore_checkpoint(branch_point)
# Explore alternative path
response2 = session.chat("What if we use approach B?")
Session Analytics
def analyse_session(session):
return {
"total_interactions": len(session.get_history()),
"session_duration": session.get_duration(),
"topics_discussed": session.extract_topics(),
"user_satisfaction": session.calculate_satisfaction_score(),
"agent_performance": session.get_performance_metrics()
}
Troubleshooting
Memory Issues
- Use memory limits and cleanup strategies
- Implement sliding window for conversation history
- Store large data externally with references
State Corruption
- Implement state validation on load
- Keep backup versions
- Use atomic save operations
- Lazy load session data
- Cache frequently accessed state
- Use appropriate storage backend for scale
Responses are generated using AI and may contain
mistakes.