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

# Agent memory

> Remember information about returning callers across separate conversations using persistent key-value storage.

Use Agent Memory when your agent needs to remember information about returning callers – preferences, past bookings, or verification status – across separate conversations. Without it, every call starts from scratch.

> [!NOTE]
>
> Early access — contact your PolyAI representative before production use.

## How it works

Agent Memory is a key-value store attached to a user identifier (such as a phone number). Persist small, structured data between conversations so your agent can:

* Skip repeated questions for returning callers
* Greet callers by name or reference past interactions
* Resume interrupted conversations where the caller left off
* Track handoff history and resolution status

Memory is read **at the start of each turn** and cached for that turn. It is written **at the end of a conversation** – not on every turn.

You can:

* **Read memory** using `conv.memory.get("key")`
* **Write memory** by setting `conv.state["key"] = value` (if the key is listed in `state_keys`)

## Configuration

### Enable Agent Memory

Agent Memory is configured by PolyAI, not self-served. Contact your PolyAI representative to enable it for your project. They will apply a configuration equivalent to the example below on your behalf:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "memory": {
    "repeat_caller": {
      "analytics_enabled": true,
      "state_keys": ["booking_day", "preferred_language"],
      "identifier_blacklist": ["+440000000000"]
    }
  }
}
```

Use the field table below to decide what to request – which `state_keys` to persist, whether you need analytics, and any identifiers to exclude.

| Field | Description |
| - | - |
| `analytics_enabled` | Adds repeat caller metrics to Studio analytics dashboards |
| `state_keys` | Keys from `conv.state` that should be saved to memory at the end of the conversation |
| `identifier_blacklist` | Optional list of identifiers to exclude (e.g., test phone numbers) |

Only include keys you explicitly need in `state_keys`. Memory is persisted at the end of the conversation, so only values set during the call are saved.

## Using memory in functions

### Reading memory

Use `conv.memory.get("key")` in any function to retrieve a previously stored value:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def start_function(conv: Conversation):
    name = conv.memory.get("caller_name")
    if name:
        return {"utterance": f"Welcome back, {name}. How can I help you today?"}
```

### Writing memory

Set values in `conv.state` – they are persisted to memory at the end of the conversation if the key is listed in `state_keys`:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def collect_name(conv: Conversation, caller_name: str):
    conv.state["caller_name"] = caller_name
    return {"content": f"Thanks, {caller_name}. I'll remember you next time."}
```

> [!WARNING]
>
> Only keys listed in `state_keys` in your config are persisted. Setting `conv.state["key"] = value` for a key not in `state_keys` will not save it to memory.

### Full example: returning caller

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def start_function(conv: Conversation):
    booking_day = conv.memory.get("booking_day")
    cheese_type = conv.memory.get("cheese_type")

    if booking_day and cheese_type:
        return {
            "utterance": f"I see you previously booked {cheese_type} for {booking_day}. Would you like to book again?"
        }
```

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
def book_delivery(conv: Conversation, cheese_type: str, booking_day: str):
    conv.state["booking_day"] = booking_day
    conv.state["cheese_type"] = cheese_type
    return {"content": f"Booked {cheese_type} for {booking_day}."}
```

## Repeat caller analytics

When `analytics_enabled` is set to `true`, Agent Memory automatically tracks five metrics for each returning caller:

| Metric | Description |
| - | - |
| `REPEAT_CALLER_CONV_ID` | Conversation ID of the caller's first interaction |
| `REPEAT_CALLER_DATETIME` | Timestamp of the first interaction |
| `REPEAT_CALLER_QA` | QA outcome from the first interaction |
| `REPEAT_CALLER_HANDOFF_REASON` | Reason for handoff in the first interaction |
| `REPEAT_CALLER_HANDOFF_TO` | Handoff destination from the first interaction |

These metrics appear in your [dashboards](https://docs.poly.ai/analytics/dashboards/introduction.md) and can be used to track repeat caller patterns and resolution rates.

> [!NOTE]
>
> Repeat caller metrics reference the **first** interaction in the retention window, not the most recent — chaining calls would allow identification beyond the retention period.

## Memory behavior

### Timing

* Memory is **fetched once per turn** from the memory service and cached. Multiple `conv.memory.get()` calls in the same turn do not trigger additional lookups.
* Memory is **written at the end of the conversation** (after the end function executes). Values set in `conv.state` during a function on turn 1 are not available through `conv.memory` on turn 2 of the same call.

### Persistence

Each write acts as a **patch** – it updates or adds specific keys without removing existing ones. If conversation 1 writes `{"cheese_type": "gouda"}` and conversation 2 writes `{"booking_day": "Friday"}`, the next lookup returns both fields.

### Expiry

All memory identifiers and fields expire at the end of your contracted retention period (for GDPR compliance). Retention periods vary by customer agreement – check your contract for specifics, or speak to your PolyAI representative. Once expired, data is automatically deleted and no longer accessible.

### Identifiers

The current supported identifier is the **caller's phone number**. This is set automatically – you do not need to configure it.

> [!NOTE]
>
> Additional identifiers (email, account ID) and cross-channel linking are planned.

## Compliance

> [!WARNING]
>
> Before going live with Agent Memory, inform your clients so they can update privacy notices and confirm compliance with applicable data protection laws.

Key compliance considerations:

* Agent Memory is **not intended for automated decision-making** that significantly impacts end users
* Do not store sensitive PII in a single field – separate fields allow independent expiry
* Custom memory fields **cannot** be used to build caller profiles
* Timestamps stored in memory should be rounded to the hour to prevent linking calls across the retention window
* All data expires at the end of your contracted retention period

If your use case goes beyond analytics, call recovery, or personalisation, raise a request with your legal team before proceeding.

## FAQ

> [accordion] Can I store nested JSON?
>
> Values are stored as JSON-encoded strings. You can store structured data in a single field, but it is recommended to keep fields flat so they can expire independently – especially for anything containing PII.

> [accordion] Can I check if any memory exists?
>
> Yes. Use Python's `in` operator:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> if "booking_day" in conv.memory:
>     # Memory exists for this key
> ```

> [accordion] Can I prevent accidental overwrites?
>
> Not natively – the latest write always wins. Guard against overwrites in your code:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> if "cheese_type" not in conv.memory:
>     conv.state["cheese_type"] = value
> ```

> [accordion] When are memory writes committed?
>
> Memory is persisted at the end of the conversation, after the [end function](https://docs.poly.ai/tools/end-tool.md) executes. Values set in `conv.state` during a function are not available in `conv.memory` until the next call.

> [accordion] Does memory work across channels?
>
> Currently, memory is scoped by phone number. Support for linking identifiers across channels (voice, SMS, webchat) is planned for future releases.

> [accordion] How do I get all stored memory fields?
>
> Use the `fields()` method:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> all_memory = conv.memory.fields()  # Returns a dict of all fields
> ```

> [accordion] What read patterns does conv.memory support?
>
> `conv.memory` is read-only and behaves like a mapping. Use whichever pattern is clearest for your case:
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> # Membership check
> if "booking_day" in conv.memory:
>     ...
>
> # Item access (raises KeyError if missing)
> last_order = conv.memory["last_order_id"]
>
> # Safe access with default
> visits = conv.memory.get("visit_count", 0)
>
> # All stored fields
> all_memory = conv.memory.fields()
>
> # Number of stored fields
> count = len(conv.memory)
> ```
>
> Writes go through `conv.state` for keys configured in `state_keys`; assigning directly to `conv.memory` is not supported.
