> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions & Remote Agents

> Stateful conversations and remote agent connectivity

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

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    User([👤 User]) --> Agent[🤖 Agent]
    Agent --> Memory{memory=}
    Memory -->|session_id| Store[📁 Session Store]
    Store --> Resume([🔄 Resume Later])
    
    classDef user fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef agent fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef store fill:#10B981,stroke:#7C90A0,color:#fff
    
    class User,Resume user
    class Agent,Memory agent
    class Store store
```

## Quick Start

<Steps>
  <Step title="Start with session_id">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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")
    ```
  </Step>

  <Step title="Resume in a new process">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    agent = Agent(
        name="Assistant",
        instructions="You are a helpful assistant",
        memory={"session_id": "my-session-123"},
    )
    agent.start("What's my name?")  # Remembers: "Alice"
    ```
  </Step>
</Steps>

## Using the Session Class

For advanced control over memory and knowledge, use the `Session` class:

<CodeGroup>
  ```python Creating Sessions theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  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"
  )
  ```

  ```python Conversation Continuity theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # 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"
  ```

  ```python State Persistence theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # Save custom state
  session.save_state({"topic": "Python", "level": "beginner"})

  # Later, restore state
  state = session.restore_state()
  print(state["topic"])  # "Python"
  ```
</CodeGroup>

### Memory Integration

Sessions can maintain memory across conversations:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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

<Note>
  Remote agents follow the Google ADK (Agent Development Kit) pattern for standardised communication.
</Note>

<CodeGroup>
  ```python Basic Connection theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  from praisonaiagents import Session

  # Connect to remote agent
  session = Session(
      agent_url="http://192.168.1.10:8000/agent"
  )
  ```

  ```python Send Messages theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # Send message to remote agent
  response = session.chat("Hello remote agent!")

  # Response includes full context
  print(response['content'])
  print(response['metadata'])
  ```

  ```python Error Handling theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  try:
      response = session.chat("Process this data")
  except TimeoutError:
      print("Remote agent timeout")
  except ConnectionError:
      print("Could not connect to remote agent")
  ```
</CodeGroup>

### Remote Agent Server

Create an agent server for remote access:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Save current state
session.save_state()

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

### Restoring Session State

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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

## Advanced Features

### Session Context

Access session context programmatically:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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")
```

### Session Middleware

Add custom middleware to sessions:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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()
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Session Lifecycle"
        Create[🆕 Create<br/>session_ttl=3600] --> Active[✅ Active]
        Active -->|time_to_expiry > 0| Active
        Active -->|elapsed >= ttl| Expired[⏰ Expired]
        Active -->|close called| Closed[🧹 Closed]
        Expired -->|close called| Closed
    end

    classDef create fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef active fill:#10B981,stroke:#7C90A0,color:#fff
    classDef expired fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef closed fill:#8B0000,stroke:#7C90A0,color:#fff

    class Create create
    class Active active
    class Expired expired
    class Closed closed
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant App
    participant Session
    participant Agent

    User->>App: "Continue chat"
    App->>Session: is_expired()?
    alt Expired
        Session-->>App: true
        App-->>User: "Session expired, starting fresh"
        App->>Session: close()
        App->>Session: Session(session_ttl=...)
    else Still valid
        Session-->>App: false
        App->>Agent: start(message)
        Agent-->>User: Response
    end
```

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

<Tabs>
  <Tab title="Poll before each turn">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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))
    ```
  </Tab>

  <Tab title="Show remaining time">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    remaining = session.time_to_expiry()
    if remaining is not None:
        print(f"{int(remaining)}s left in this session")
    ```
  </Tab>

  <Tab title="Cleanup with close()">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    session = Session(session_id="chat", session_ttl=600)
    try:
        agent = session.Agent(name="Assistant")
        agent.start("Quick question")
    finally:
        session.close()
    ```
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Pick a TTL that matches your UX">
    Use 30–60 min for chat assistants, 24 h for long-running bots, `None` for batch jobs.
  </Accordion>

  <Accordion title="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()`.
  </Accordion>

  <Accordion title="Always close() in a finally block">
    Even without TTL, `close()` releases memory-adapter connections and flushes pending chat history.
  </Accordion>

  <Accordion title="Negative TTL is a programming error">
    The constructor raises `ValueError` immediately — surface this to the developer, do not catch silently.
  </Accordion>
</AccordionGroup>

***

## Use Cases

<CardGroup cols={2}>
  <Card icon="headset" title="Customer Support">
    Maintain conversation history across support interactions

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    session = Session(
        session_id=f"support_{ticket_id}",
        user_id=customer_id
    )
    ```
  </Card>

  <Card icon="user-robot" title="Personal Assistants">
    Remember user preferences and past interactions

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    session = Session(
        session_id=f"assistant_{user_id}",
        memory={"provider": "rag"}
    )
    ```
  </Card>

  <Card icon="users" title="Collaborative Work">
    Share context between team members

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    session = Session(
        session_id=f"project_{project_id}",
        knowledge={...}
    )
    ```
  </Card>

  <Card icon="cloud" title="Distributed Systems">
    Deploy agents across multiple servers

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    session = Session(
        agent_url="https://agent.region.example.com"
    )
    ```
  </Card>
</CardGroup>

## Complete Example

<CodeGroup>
  ```python Stateful Local Assistant theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  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()
  ```

  ```python Remote Agent Client theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  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())
  ```
</CodeGroup>

## Database Session Persistence

<Note>
  When using database-backed sessions (e.g., via `praisonai.db`), both messages and metadata automatically persist to your database. The `clear_session()` and `delete_session()` methods remove persisted messages and metadata respectively. `set_metadata()` and `get_metadata()` round-trip through the conversation store, ensuring metadata survives process restarts.
</Note>

For database-backed persistence without manual session management, see the [HostedAgent persistence guide](/docs/features/managed-agent-persistence).

## Best Practices

<AccordionGroup>
  <Accordion title="Use meaningful session IDs">
    Prefer stable IDs such as `support_{ticket_id}` or `assistant_{user_id}` so resume and cleanup stay predictable.
  </Accordion>

  <Accordion title="Save state after important interactions">
    Call `session.save_state()` or use `MemoryConfig(auto_save=...)` so long-running workflows survive restarts.
  </Accordion>

  <Accordion title="Handle remote failures gracefully">
    Wrap `session.chat()` in try/except for `TimeoutError` and `ConnectionError`; set explicit `timeout=` on remote sessions.
  </Accordion>

  <Accordion title="Validate session IDs and authenticate remotes">
    Treat session IDs as opaque handles — authenticate remote agent URLs with headers or tokens, not shared IDs alone.
  </Accordion>
</AccordionGroup>

## 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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
```

<Note>
  **Idempotent saves.** `Session.save_state()` is idempotent against the underlying session store: calling it repeatedly does not duplicate chat history. The session store must implement `set_chat_history(session_id, messages)`; the built-in `DefaultSessionStore` does. Custom stores that only implement `add_message()` will log a warning and may produce duplicates on repeated saves. (PraisonAI PR #1897)
</Note>

<Note>
  The standalone `auto_save` parameter on `Agent(...)` is **deprecated**. Use `memory=MemoryConfig(auto_save="name")` instead.
</Note>

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

<CardGroup cols={2}>
  <Card icon="rotate" href="/docs/features/bot-session-reset">
    Bot session reset policies (idle / daily)
  </Card>

  <Card icon="brain" href="/docs/features/advanced-memory">
    Deep dive into memory capabilities
  </Card>

  <Card icon="cloud" href="/deploy/deploy">
    Deploy agents for remote access
  </Card>
</CardGroup>

## Related

<CardGroup cols={2}>
  <Card icon="database" href="/features/session-persistence">
    Choose a storage backend so sessions survive restarts.
  </Card>

  <Card icon="brain" href="/features/memory">
    Persist and recall information across sessions and agents.
  </Card>
</CardGroup>
