Sessions & Remote Agents
Stateful conversations and remote agent connectivity
Sessions enable agents to remember conversations across restarts and connect to remote agents.
from praisonaiagents import Agent
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant",
memory={"session_id": "my-session-123"},
)
agent.start("My name is Alice")The user sends follow-up messages; the session keeps context across process restarts and remote agents.
Quick Start
- Start with session_id
python from praisonaiagents import Agent agent = Agent( name="Assistant", instructions="You are a helpful assistant", memory={"session_id": "my-session-123"}, ) agent.start("My name is Alice") - Resume in a new process
python agent = Agent( name="Assistant", instructions="You are a helpful assistant", memory={"session_id": "my-session-123"}, ) agent.start("What's my name?") # Remembers: "Alice"
Using the Session Class
For advanced control over memory and knowledge, use the Session class:
from praisonaiagents import Session
# Create a session
session = Session(
session_id="chat_123",
user_id="user_456"
)
# Create agent within session context
agent = session.Agent(
name="Assistant",
instructions="You are a helpful assistant"
)# First conversation
response1 = agent.start("My name is John")
# Later conversation (remembers context)
response2 = agent.start("What's my name?")
# Agent responds: "Your name is John"# Save custom state
session.save_state({"topic": "Python", "level": "beginner"})
# Later, restore state
state = session.restore_state()
print(state["topic"]) # "Python"Memory Integration
Sessions can maintain memory across conversations:
# Session with memory configuration
session = Session(
session_id="chat_123",
user_id="user_456",
memory=True # Enable memory with defaults
)
# Add memories directly
session.add_memory("User prefers technical explanations")
# Search memories
memories = session.search_memory("preferences")
# Agent automatically uses session memory
agent = session.Agent(name="Assistant", memory=True)Knowledge Integration
Attach knowledge bases to sessions:
# Session with knowledge
session = Session(
session_id="research_session",
user_id="researcher_1",
knowledge={
"vector_store": {
"provider": "chroma",
"config": {"collection_name": "research_docs"}
}
}
)
# Add knowledge to session
session.add_knowledge("research_paper.pdf")
session.add_knowledge("Important finding: AI improves efficiency by 40%")
# Search knowledge
results = session.search_knowledge("efficiency improvements")
# Agents use session knowledge
agent = session.Agent(
name="Research Assistant",
knowledge=True
)Remote Agents
Connecting to Remote Agents
from praisonaiagents import Session
# Connect to remote agent
session = Session(
agent_url="http://192.168.1.10:8000/agent"
)# Send message to remote agent
response = session.chat("Hello remote agent!")
# Response includes full context
print(response['content'])
print(response['metadata'])try:
response = session.chat("Process this data")
except TimeoutError:
print("Remote agent timeout")
except ConnectionError:
print("Could not connect to remote agent")Remote Agent Server
Create an agent server for remote access:
# remote_agent_server.py
from flask import Flask, request, jsonify
from praisonaiagents import Agent
app = Flask(__name__)
# Create your agent
agent = Agent(
name="Remote Assistant",
instructions="You are a helpful remote assistant.",
tools=[...], # Your tools
memory=True
)
@app.route('/agent', methods=['POST'])
def handle_message():
data = request.json
message = data.get('message', '')
session_id = data.get('session_id')
# Process message
response = agent.chat(message, session_id=session_id)
return jsonify({
'content': response,
'session_id': session_id,
'metadata': {
'agent_name': agent.name,
'timestamp': datetime.now().isoformat()
}
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)Session Configuration
Local Session Options
session = Session(
# Required
session_id="unique_session_id",
# Optional
user_id="user_identifier",
session_ttl=3600, # Expire after 1 hour (None = never)
# Memory configuration (use memory= consolidated param)
memory=True, # Enable memory with defaults
# Knowledge configuration
knowledge={
"vector_store": {
"provider": "chroma",
"config": {
"collection_name": "session_knowledge",
"path": ".sessions/knowledge"
}
}
}
)Remote Session Options
session = Session(
# Remote agent URL
agent_url="https://api.example.com/agent",
# Optional timeout (default: 30 seconds)
timeout=60,
# Optional headers for authentication
headers={
"Authorization": "Bearer token",
"X-API-Key": "api_key"
}
)State Management
Saving Session State
# Save current state
session.save_state()
# State includes:
# - Session metadata
# - Memory contents
# - Knowledge references
# - Agent configurationsRestoring Session State
# Create new session instance
session = Session(session_id="chat_123")
# Restore previous state
session.restore_state()
# Continue where you left off
agent = session.Agent(name="Assistant")
response = agent.chat("What were we discussing?")State Persistence Location
By default, session state is saved to:
.sessions/{session_id}/state.json– Session metadata.sessions/{session_id}/memory/– Memory databases.sessions/{session_id}/knowledge/– Knowledge databases
Sub-agent transcripts (from session.Agent(...)) live inside that same state.json under metadata["agent_histories"], not in separate per-agent files.
Advanced Features
Session Context
Access session context programmatically:
# Get session context
context = session.get_context()
print(f"Session ID: {context['session_id']}")
print(f"User ID: {context['user_id']}")
print(f"Created: {context['created_at']}")
print(f"Messages: {context['message_count']}")Multi-Agent Sessions
Use multiple agents within a session:
session = Session(session_id="team_session")
# Create multiple agents in session
researcher = session.Agent(
name="Researcher",
instructions="You research topics"
)
writer = session.Agent(
name="Writer",
instructions="You write content"
)
# Agents share session memory and knowledge
research = researcher.chat("Research AI trends")
article = writer.chat("Write an article about the research")Each sub-agent’s chat history persists into the parent session’s record under metadata["agent_histories"][agent_key] (PraisonAI PR #4126), so:
- Multiple sub-agents under one
Sessionshare one file. session.close()/save_state()cannot overwrite an unrelated user’s session even when the sanitised sub-agent names would collide.- Deleting, forking, or exporting the parent takes the sub-agent transcripts with it.
from praisonaiagents import Session
session = Session(session_id="chat")
researcher = session.Agent(name="Researcher", role="research")
writer = session.Agent(name="Writer", role="draft")
researcher.start("Find recent quantum-computing papers.")
writer.start("Draft a two-paragraph summary.")
session.close() # Both transcripts saved under metadata["agent_histories"]
# on the "chat" record. Any unrelated user session named
# "chat_researcher_research" or "chat_writer_draft" is untouched.Sub-agent transcripts written by pre-#4126 versions that carry the tags (parent_session_id + agent_key) are migrated automatically on the next save โ no flag needed, no recency limit (PraisonAI PR #4162).
To recover untagged pre-tag transcripts (older records that predate the tagging change), opt in with PRAISONAI_SESSION_LEGACY_AGENT_KEYS=1 (accepts 1 / true / yes / on). Set it only when you know which on-disk records are legacy sub-agent transcripts โ an untagged id like "chat_support_agent" may be a real user session.
Session Middleware
Add custom middleware to sessions:
def logging_middleware(message, response):
print(f"[{datetime.now()}] Message: {message}")
print(f"[{datetime.now()}] Response: {response[:100]}...")
return response
session = Session(
session_id="logged_session",
middleware=[logging_middleware]
)Session Expiry & Cleanup
Sessions can auto-expire after a fixed lifetime and release their resources with a single close() call.
from praisonaiagents import Session
# Session expires 1 hour after creation
session = Session(
session_id="chat_123",
session_ttl=3600,
)
agent = session.Agent(
name="Assistant",
instructions="You are a helpful assistant",
)
agent.start("Hello!")
# Later โ gate on expiry before answering
if session.is_expired():
print("Session expired, please start a new one")
else:
agent.start("Continue our chat")
# Always release resources when done
session.close()| Parameter | Type | Default | Description |
|---|---|---|---|
session_ttl | Optional[int] | None | Lifetime in seconds. None = never expire. Must be >= 0; negative raises ValueError. |
| Method | Returns | Description |
|---|---|---|
is_expired() | bool | True once time_to_expiry() == 0. Always False when session_ttl is None. |
time_to_expiry() | Optional[float] | Seconds left before expiry (clamped to 0). None if no TTL set. |
close() | None | Flushes agent chat histories, closes memory connections, clears knowledge and agents. No-op on remote sessions. |
Poll before each turn
session = Session(session_id="chat", session_ttl=1800)
agent = session.Agent(name="Assistant")
while True:
if session.is_expired():
print("Session expired")
session.close()
break
user_input = input("You: ")
print(agent.start(user_input))Show remaining time
remaining = session.time_to_expiry()
if remaining is not None:
print(f"{int(remaining)}s left in this session")Cleanup with close()
session = Session(session_id="chat", session_ttl=600)
try:
agent = session.Agent(name="Assistant")
agent.start("Quick question")
finally:
session.close()Pick a TTL that matches your UX
Use 30โ60 min for chat assistants, 24 h for long-running bots, None for batch jobs.
Use monotonic semantics, not wall-clock
is_expired() measures elapsed runtime; it does not reflect calendar time. Do not compare internal timestamps against time.time().
Always close() in a finally block
Even without TTL, close() releases memory-adapter connections and flushes pending chat history.
Negative TTL is a programming error
The constructor raises ValueError immediately โ surface this to the developer, do not catch silently.
Use Cases
Maintain conversation history across support interactions
session = Session(
session_id=f"support_{ticket_id}",
user_id=customer_id
)Remember user preferences and past interactions
session = Session(
session_id=f"assistant_{user_id}",
memory={"provider": "rag"}
)Share context between team members
session = Session(
session_id=f"project_{project_id}",
knowledge={...}
)Deploy agents across multiple servers
session = Session(
agent_url="https://agent.region.example.com"
)Complete Example
from praisonaiagents import Session, Task, AgentTeam
# Create or restore session
session = Session(
session_id="personal_assistant",
user_id="john_doe",
memory={
"provider": "rag",
"use_embedding": True
},
knowledge={
"vector_store": {
"provider": "chroma",
"config": {"collection_name": "personal_docs"}
}
}
)
# Try to restore previous state
try:
session.restore_state()
print("Restored previous session")
except:
print("Starting new session")
# Create session agent
assistant = session.Agent(
name="Personal Assistant",
instructions="""You are a personal assistant that remembers everything.
Use your memory and knowledge to provide personalised help.""",
memory=True,
knowledge=True
)
# Add some knowledge
session.add_knowledge("calendar.pdf")
session.add_memory("User prefers morning meetings")
# Have a conversation
response = assistant.chat("Schedule a meeting for tomorrow")
print(response)
# Save state for next time
session.save_state()from praisonaiagents import Session
import asyncio
# Connect to remote agents
async def connect_to_agents():
# Connect to different remote agents
research_session = Session(
agent_url="http://research-server:8000/agent"
)
analysis_session = Session(
agent_url="http://analysis-server:8000/agent"
)
# Send tasks in parallel
research_task = research_session.chat_async("Research market trends")
analysis_task = analysis_session.chat_async("Analyse competitor data")
# Wait for results
research_result = await research_task
analysis_result = await analysis_task
return research_result, analysis_result
# Run the distributed system
results = asyncio.run(connect_to_agents())Database Session Persistence
For database-backed persistence without manual session management, see the HostedAgent persistence guide.
Persistence backends:
- Session Mirror โ local-first sink for replicating a session’s append-only records to a remote backend (postgres/supabase/turso adapters land in the wrapper alongside #3645).
Best Practices
Use meaningful session IDs
Prefer stable IDs such as support_{ticket_id} or assistant_{user_id} so resume and cleanup stay predictable.
Save state after important interactions
Call session.save_state() or use MemoryConfig(auto_save=...) so long-running workflows survive restarts.
Handle remote failures gracefully
Wrap session.chat() in try/except for TimeoutError and ConnectionError; set explicit timeout= on remote sessions.
Validate session IDs and authenticate remotes
Treat session IDs as opaque handles โ authenticate remote agent URLs with headers or tokens, not shared IDs alone.
Auto-Save Sessions
Use MemoryConfig.auto_save to automatically persist sessions by name after each interaction, eliminating the need for manual save_state() calls.
from praisonaiagents import Agent, MemoryConfig
# Automatically save session state under the given name
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
memory=MemoryConfig(
auto_save="my-assistant-session", # Session name
user_id="user123",
)
)
# Each interaction is auto-persisted
agent.start("Remember that I prefer dark mode")
# Session saved automatically โ no manual save_state() neededAuto-Save vs Manual Save
| Approach | Code | When to Use |
|---|---|---|
auto_save | MemoryConfig(auto_save="name") | Most applications โ zero boilerplate, per-turn persistence stays in sync |
| Manual | session.save_state() | Save-point control; idempotent as of PR #1897 |
| History injection | MemoryConfig(history=True) | Auto-inject past messages into context |
Next Steps
Bot session reset policies (idle / daily)
CardDeep dive into memory capabilities
CardDeploy agents for remote access