> For the complete documentation index, see [llms.txt](https://docs.interactive.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.interactive.ai/agents/concepts/memory-and-state.md).

# Sessions, memory & state

> **Context** — This page maps every kind of state an agent holds, who writes it, who sees it, and where it lives. The distinction that trips everyone up at least once: **variables** are agent-visible, **metadata** is not.
>
> YAML examples follow **manifest schema 6.1.1**. Manifest and content shapes are schema-versioned and differ across runtime versions — see [Versioning & compatibility](/agents/operations/versioning.md).

## The state model

```
Customer ──── has many ──── Sessions ──── contain ──── Events (offset-ordered)
   │                            │
   ├─ variables (agent-visible) ├─ metadata (integration-only)
   └─ metadata (integration-only)└─ mode: auto | manual
```

### Customers (optional)

A **customer** is the stable identity across conversations — keyed by an id your integration chooses (a CRM id, an email, a ticket-system user id). Customers carry:

* **Variables** — agent-visible context (see below).
* **Metadata** — integration-only key/values the agent never sees.
* A display name.

Customers are a convenience for **customer-facing** agents — they let you carry variables and group sessions across one end-user's conversations. An agent that isn't customer-facing doesn't need the concept at all: a [backend automation](/agents/concepts/autonomous-routines.md) is triggered with typed input and never references a customer, and even a simple chat integration can open sessions without modelling end-users as customers. Reach for customers only when you have a recurring end-user whose context should persist across sessions.

### Sessions

A **session** is one conversation. A customer can have many (a "new conversation" button, one per support ticket). Sessions carry:

* The **event log**: every message, tool call, and status change, each with a monotonically increasing integer `offset`. The offset is your resume-and-dedupe cursor — see [Integrating the SDK](/agents/guides/integrating-the-sdk.md).
* **Metadata** — integration-only. Well-known keys the runtime understands:

  | Key                 | Effect                                                                                                                                                  |
  | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `session_key`       | Stable human-meaningful id (e.g. a ticket id) used to name and group traces — see [Observability](/agents/guides/observability.md#trace-naming).        |
  | `event_webhook_url` | Where the agent POSTs events for webhook-mode delivery (the SDK writes this for you).                                                                   |
  | `external_id`       | Convention for finding a session by your channel's conversation id.                                                                                     |
  | `step_outputs`      | Written by the runtime: validated outputs of [think nodes](/agents/concepts/autonomous-routines.md#node-types) (autonomous routines), keyed by node id. |
* **Mode** — `auto` (the engine replies to customer messages) or `manual` (a human has taken over; the engine stays silent while your integration posts human-authored messages). See the [handover section of the SDK guide](/agents/guides/integrating-the-sdk.md#8-human-handover).

## Variables vs metadata

|                      | Variables                                                                                                      | Metadata                                                                     |
| -------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Visible to the agent | **Yes** — injected into context on the next turn                                                               | **No** — never reaches a prompt                                              |
| Lives on             | Customer                                                                                                       | Customer or session                                                          |
| Written by           | Your integration (SDK), any time                                                                               | Your integration; a few keys by the runtime                                  |
| Use for              | Anything the agent should *know*: plan tier, loyalty status, open-ticket count, "documents were just uploaded" | Anything you need to *look up later*: channel ids, webhook URLs, bookkeeping |

```python
# Agent-visible — readable from routines/policies on the next turn.
await client.customers.set_variables(
    customer.id,
    {"loyalty_tier": "gold", "open_tickets": 3},
)

# Integration-only — the agent does NOT see this.
await sess.update_metadata({"chatwoot_conversation_id": "789"})
```

Variables take effect on the **next turn** — the engine snapshots context when a turn starts. Any JSON-serialisable value works (values are stringified for the model). Variables are referenced naturally from content: a routine condition can say "the customer's `loyalty_tier` is gold".

Variables are configured per-deployment through the SDK at runtime — they are **not** declared in the manifest.

## Step outputs

Each [think node](/agents/concepts/autonomous-routines.md#node-types) persists its validated JSON to `session.metadata.step_outputs[<node-id>]`, merged across the nodes of a run. Downstream nodes see the inference call and result in history; your integration can read the typed values off the session after the fact — useful for auditing what the agent concluded mid-flow.

## Storage backends

Where all of this lives is one manifest decision:

| Configuration                 | Backend    | Survives restart | Use for                                        |
| ----------------------------- | ---------- | ---------------- | ---------------------------------------------- |
| omit `agent_config.database`  | In-memory  | **No**           | Demos, tests, stateless autonomous-only agents |
| `agent_config.database` block | PostgreSQL | Yes              | Production conversational agents               |

```yaml
agent_config:
  database:
    hostname: agent-postgres.internal.example.com
    port: 5432
    user: postgres
    password: ${DB_PASSWORD}
    dbname: postgres
    sslmode: require
```

(`hostname` and `password` are required; `port`/`user`/`dbname`/`sslmode` default to `5432`/`postgres`/`postgres`/`require`.)

With in-memory storage, a restart or redeploy erases every session — open conversations reset mid-dialogue. If customers ever come back to continue a conversation, use Postgres. Schema migrations run automatically at boot.

The knowledge base is a **separate** Postgres concern (`agent_config.search`, see [Knowledge base & retrieval](/agents/concepts/knowledge-base.md)) — the two may share a server but are configured independently.

## Lifecycle notes

* **Ephemeral autonomous sessions** — a triggered run without a `session_id` creates a throwaway customer + session and deletes both after the callback settles. Pass your own `session_id` to keep the run's history. See [Autonomous routines](/agents/concepts/autonomous-routines.md).
* **History is the agent's memory.** There is no hidden long-term memory beyond what this page lists: the event log, variables, metadata, and step outputs. What you see in the session is what the model can know.

## See also

* [Integrating the SDK](/agents/guides/integrating-the-sdk.md) — reading and writing all of this from code
* [Routines](/agents/concepts/routines.md) — think nodes and step outputs
* [Deploying](/agents/guides/deploying.md) — provisioning the database


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.interactive.ai/agents/concepts/memory-and-state.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
