Sessions & Remote Agents

Stateful conversations and remote agent connectivity

Sessions enable agents to remember conversations across restarts and connect to remote agents.

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")

The user sends follow-up messages; the session keeps context across process restarts and remote agents.

Diagram

session_id

๐Ÿ‘ค User

๐Ÿค– Agent

memory=

๐Ÿ“ Session Store

๐Ÿ”„ Resume Later

Quick Start

  1. 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")
  2. 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:

Creating Sessions
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"
)
Conversation Continuity
# 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"
State Persistence
# 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:

python
# 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:

python
# 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

Basic Connection
from praisonaiagents import Session

# Connect to remote agent
session = Session(
    agent_url="http://192.168.1.10:8000/agent"
)
Send Messages
# Send message to remote agent
response = session.chat("Hello remote agent!")

# Response includes full context
print(response['content'])
print(response['metadata'])
Error Handling
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:

python
# 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

python
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

python
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

python
# Save current state
session.save_state()

# State includes:
# - Session metadata
# - Memory contents
# - Knowledge references
# - Agent configurations

Restoring Session State

python
# 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:

python
# 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:

python
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 Session share 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.
python
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:

python
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.

python
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()
Diagram

Session Lifecycle

time_to_expiry > 0

elapsed >= ttl

close called

close called

๐Ÿ†• Create
session_ttl=3600

โœ… Active

โฐ Expired

๐Ÿงน Closed

Diagram
AgentSessionAppUserAgentSessionAppUseralt[Expired][Still valid]“Continue chat”is_expired()?true“Session expired, starting fresh”close()Session(session_ttl=…)falsestart(message)Response
ParameterTypeDefaultDescription
session_ttlOptional[int]NoneLifetime in seconds. None = never expire. Must be >= 0; negative raises ValueError.
MethodReturnsDescription
is_expired()boolTrue 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()NoneFlushes agent chat histories, closes memory connections, clears knowledge and agents. No-op on remote sessions.

Poll before each turn

python
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

python
remaining = session.time_to_expiry()
if remaining is not None:
    print(f"{int(remaining)}s left in this session")

Cleanup with close()

python
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

Complete Example

Stateful Local Assistant
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()
Remote Agent Client
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.

python
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() needed

Auto-Save vs Manual Save

ApproachCodeWhen to Use
auto_saveMemoryConfig(auto_save="name")Most applications โ€” zero boilerplate, per-turn persistence stays in sync
Manualsession.save_state()Save-point control; idempotent as of PR #1897
History injectionMemoryConfig(history=True)Auto-inject past messages into context

Next Steps

Related