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

# Session Storage

> Conversation history within a thread, backed by Postgres

Session storage is the simplest of the three memory layers: the agent remembers what was said earlier in the same conversation thread. It's on by default for Agno-backed agents and lives in a per-agent Postgres schema xpander manages for you.

Every thread has its own history. As long as messages share a `session_id`, the agent sees the full history up to the configured limit. Start a new thread and the slate is clean.

Multiple users can share a thread and they see the same conversation, but it's still self-contained.

```mermaid theme={"dark"}
graph LR
    Alice
    Bob
    subgraph SG1[" "]
        direction TB
        S1["Session 1"]
        DB1[("Session Storage")]
        S1 --- DB1
    end
    subgraph SG2[" "]
        direction TB
        S2["Session 2"]
        DB2[("Session Storage")]
        S2 --- DB2
    end
    subgraph SG3[" "]
        direction TB
        S3["Session 3"]
        DB3[("Session Storage")]
        S3 --- DB3
    end
    Agent["Support Bot"]
    Alice --- S1
    Alice --- S2
    Bob --- S1
    Bob --- S3
    S1 ------ Agent
    S2 ------ Agent
    S3 ------ Agent
    style SG1 fill:none,stroke:none
    style SG2 fill:none,stroke:none
    style SG3 fill:none,stroke:none
```

<Note>
  Session storage is wired in automatically only for **Agno**. The SDK helpers on this page raise `NotImplementedError` on LangChain, OpenAI Agents SDK, and AWS Strands. For those frameworks, manage session continuity through the framework's own state primitives. See the [framework pages](/developers/frameworks/agno) for details.
</Note>

## Configuration

The settings below live on `agent.agno_settings` and are toggled in the agent's Memory tab in [Agent Studio](https://app.xpander.ai).

<Card title="Configure memory in Agent Studio" icon="sliders" href="/guides/agents/memory-state">
  UI walkthrough for toggling session storage and tuning history depth.
</Card>

Read them back from the loaded agent to confirm what's live:

```python theme={"dark"}
from xpander_sdk import Agents

xpander_agent = await Agents().aget(agent_id="agt_01H...")
print(xpander_agent.agno_settings.session_storage)
print(xpander_agent.agno_settings.num_history_runs)
```

| Setting                       | What it controls                                                                                                     | Default |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------- |
| `session_storage`             | Whether the framework writes turn-by-turn history to Postgres.                                                       | `True`  |
| `num_history_runs`            | How many prior runs to load into context at the start of each turn. One run = one user message + one agent response. | `10`    |
| `max_tool_calls_from_history` | Cap on tool calls replayed from history. `0` means no cap.                                                           | `0`     |
| `session_summaries`           | Generate a summary of each completed session for monitoring views. Doesn't affect context.                           | `False` |

`num_history_runs` is the big knob. Tune it down to `3` or `5` for high-volume tool agents, up to `20` or more for long analytical conversations. Higher numbers mean longer memory but more tokens per turn.

### When to turn it off

The default is on because most agents benefit from it. Reasons to flip `session_storage` off:

* One-shot tools that don't have conversational threads (a webhook handler that returns a single result, a scheduled enrichment job).
* Performance-sensitive paths where the per-turn DB read is meaningful overhead.
* Agents handling regulated data where you don't want any conversation persistence at all.

The framework skips the DB wiring on the next agent load.

## Inspect sessions from code

The session helpers are on the loaded agent. They let you:

* List every session by `user_id`
* Get full message history for every session
* Delete a session and its message history

```python highlight={6,11,15} theme={"dark"}
from xpander_sdk import Agents

agent = await Agents().aget(agent_id="agt_01H...")

# Every session a given user has had with this agent.
sessions = await agent.aget_user_sessions(user_id="user@example.com")
for s in sessions:
    print(s.session_id, len(s.messages))

# A specific session by ID.
session = await agent.aget_session(session_id="sess_abc")
print(session.messages)

# Wipe one.
await agent.adelete_session(session_id="sess_abc")
```

If you'd rather reach into Postgres directly (custom queries, an admin UI of your own), `agent.aget_db()` returns the same connection the framework reads and writes through:

```python theme={"dark"}
db = await agent.aget_db(async_db=True)
# agno.db.postgres.AsyncPostgresDb, scoped to this agent's schema.
```

Most session work goes through the agent methods above; reach for the DB only when those don't expose what you need.

## Troubleshooting

<AccordionGroup>
  <Accordion title="My agent doesn't remember the previous turn when I invoke through the REST API">
    By default, every REST invocation gets a fresh `session_id`. To get continuity across calls, pass the same `session_id` (or the same task's parent ID) on each request. The chat panel and Slack integration manage this for you; programmatic clients have to do it explicitly.
  </Accordion>

  <Accordion title="Can I share sessions across two different agents?">
    No. Each agent has its own Postgres schema, so sessions are scoped to one agent. If you need agent A to see what agent B did, use the [agent-to-agent (A2A) pattern](/developers/deployment/invocation-channels#agent-to-agent-a2a): one agent invokes the other and gets the result back as a tool response.
  </Accordion>

  <Accordion title="How do I purge old sessions for compliance?">
    Iterate `agent.aget_user_sessions(user_id)` for the affected user, filter by date, and call `agent.adelete_session(session_id)` per match. Schedule the job through any cron mechanism in your infrastructure; xpander doesn't run retention policies on your behalf.
  </Accordion>

  <Accordion title="Postgres connection errors when running the handler locally">
    Session storage is on by default, so the agent's wiring expects a reachable Postgres. For cloud-hosted agents this is automatic. For self-hosted or air-gapped deployments, check the connection string with `await agent.aget_connection_string()` and confirm the host is reachable, or toggle `session_storage` off in [Agent Studio](https://app.xpander.ai).
  </Accordion>
</AccordionGroup>

## What to read next

<CardGroup cols={2}>
  <Card title="User memories" icon="user" href="/developers/memory/user-memories">
    Facts about a specific user that persist across all their sessions.
  </Card>

  <Card title="Agent memories" icon="building" href="/developers/memory/agent-memories">
    Org-wide knowledge the agent always carries.
  </Card>

  <Card title="Agno framework" icon="cube" href="/developers/frameworks/agno">
    The full args-dict reference, including every session-storage field `aget_args` wires up.
  </Card>

  <Card title="Output Response Filtering" icon="filter" href="/developers/tools/output-response-filtering">
    Trim chatty connector responses before they reach the LLM and bloat session history.
  </Card>
</CardGroup>
