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

# Long-term memory

Long-term memory persists important information across sessions and over time — user preferences, task history, key facts, or long-lived state. Short-term memory restores a session history, while long-term memory retrieves relevant content by query; long-term memory lets an agent remember facts **across different sessions**.

Why you need it:

* Continuous conversation experience across sessions;
* Retain learnings and user-specific information over many interactions;
* Avoid repetitive questions, improving satisfaction and efficiency;
* Support long-term strategy optimization such as personalization or task tracking.

## Single entry point: `LongTermMemory`

Whatever backend you use, you interact with `veadk.memory.long_term_memory.LongTermMemory`. It plugs directly into an agent as its memory service and selects the storage backend through `backend`.

```python lines theme={null}
from veadk.memory.long_term_memory import LongTermMemory

ltm = LongTermMemory(backend="viking", app_name="ltm_demo")
```

### Parameters

| Parameter | Type | Default | Description |
| :- | :- | :- | :- |
| `backend` | `"local" \| "opensearch" \| "redis" \| "viking" \| "mem0" \| "openviking" \| "tos_context"` | `"opensearch"` | Selects the backend. `viking_mem` is deprecated and maps to `viking`. |
| `backend_config` | `dict` | `{}` | Backend-specific settings. If `index` is absent, VeADK fills it from `index` or `app_name`. |
| `top_k` | `int` | `5` | Number of most-similar chunks to retrieve. |
| `index` | `str` | `""` | Index/collection name for storing memories. Without backend\_config, falls back to `app_name`, then `default_app`; set a nonempty index when supplying a configuration dictionary |
| `app_name` | `str` | `""` | The owning application name; used for data isolation and as the `index` fallback. |
| `user_id` | `str` | `""` | **Deprecated**, kept only for backward compatibility. |

<Note>
  Vector backends (`local`, `opensearch`, and `redis`) embed memories locally and require the extensions extra and an embedding model. `viking`, `mem0`, `openviking`, and `tos_context` use external services and do not need local embedding.
</Note>

## Choosing a backend

Use `local` for debugging. In production, select `viking`, `mem0`, or `tos_context` according to your existing services and data-governance requirements.

| Backend | Storage | Requires | Use case | Docs |
| :- | :- | :- | :- | :- |
| `local` | In-memory vector index | `extensions` + embedding | Local debugging | [In-memory](/productions/veadk/preview/en/components/memory/local) |
| `viking` | VikingDB memory (managed) | Volcengine account | Managed memory | [VikingDB](/productions/veadk/preview/en/components/memory/vikingdb) |
| `mem0` | Mem0 memory (managed) | Mem0 API key | Managed memory | [Mem0](/productions/veadk/preview/en/components/memory/mem0) |
| `opensearch` | OpenSearch vector store | OpenSearch + embedding | Self-hosted vector search | [OpenSearch](/productions/veadk/preview/en/components/memory/opensearch) |
| `redis` | Redis vector store | Redis (RediSearch) + embedding | Self-hosted vector search | [Redis](/productions/veadk/preview/en/components/memory/redis) |
| `openviking` | OpenViking user memory | OpenViking service | Entity, event, and preference memory | [OpenViking](/productions/veadk/preview/en/components/memory/openviking) |
| `tos_context` | TOS ContextBucket (managed) | Volcengine account and TOS SDK `>=2.9.4b1` | Managed memory inference with per-user isolation | [TOS ContextBucket](/productions/veadk/preview/en/components/memory/tos-context) |

## Binding to an Agent

Passing `long_term_memory` to an `Agent` **auto-injects the `load_memory` tool** so the agent can retrieve past sessions at run time.

```python lines theme={null}
from veadk import Agent, Runner
from veadk.memory.long_term_memory import LongTermMemory

APP_NAME = "ltm_demo"
ltm = LongTermMemory(backend="viking", app_name=APP_NAME)

root_agent = Agent(
    name="ltm_agent",
    instruction="Answer the user. If the answer might be in past conversations, use the `load_memory` tool.",
    long_term_memory=ltm,
)
runner = Runner(agent=root_agent, app_name=APP_NAME)
```

## Managing memory

### Write: `add_session_to_memory`

When a session ends or hits a checkpoint, call the async `add_session_to_memory` to persist it. `LongTermMemory` filters events according to the auto-save policy — by default keeping only user text events to improve retrieval quality. You can customize the filtering rules with the `auto_save_memory_policy` parameter before passing events to the backend.

```python lines theme={null}
completed_session = await runner.session_service.get_session(
    app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID
)
await ltm.add_session_to_memory(completed_session)
```

`add_session_to_memory` accepts an optional `auto_save_memory_policy` keyword argument to override the default filtering policy:

```python lines theme={null}
from veadk.memory import MemoryAutoSavePolicy

await ltm.add_session_to_memory(
    completed_session,
    auto_save_memory_policy=MemoryAutoSavePolicy(preset="all"),
)
```

### Retrieve: `search_memory`

Besides the agent's automatic retrieval via `load_memory`, you can call the async `search_memory` directly for semantic search — useful for debugging or custom RAG:

```python lines theme={null}
response = await ltm.search_memory(
    app_name=APP_NAME,
    user_id=USER_ID,
    query="favorite project",
)
print(response.memories)
```

<Note>
  `get_user_profile(user_id)` is supported only by the `viking` backend; others return an empty string.
</Note>

## Auto-save sessions

Set `auto_save_session=True` on the `Agent` with long-term memory configured, and VeADK persists sessions automatically — no manual `add_session_to_memory`.

```python lines theme={null}
from veadk import Agent
from veadk.memory.long_term_memory import LongTermMemory

agent = Agent(
    name="ltm_agent",
    auto_save_session=True,
    long_term_memory=LongTermMemory(backend="viking", app_name="ltm_demo"),
)
```

Auto-save checks thresholds in the end-of-run callback; VeADK exposes `MIN_MESSAGES_THRESHOLD` and `MIN_TIME_THRESHOLD` env vars to tune the save cadence: by default it saves after 10 accumulated events or a 60-second interval; additionally, when you switch `session_id` and start a new turn, VeADK saves the previous session to long-term memory.

Auto-save uses incremental writes: each save only persists the events that are new since the last save, rather than the entire session. If there are no new events between two saves, the write is skipped.

### Controlling what gets saved: `auto_save_memory_policy`

The `Agent` accepts an `auto_save_memory_policy` parameter that controls which events are written to long-term memory during auto-save. The same value is passed as the `auto_save_memory_policy` keyword argument to `add_session_to_memory`.

The parameter type is `MemoryAutoSavePolicyInput`, which accepts one of:

* A string preset: `"default"`, `"all"`, or `"custom"`;
* A `MemoryAutoSavePolicy` instance;
* A `dict` with the same fields as `MemoryAutoSavePolicy`;
* `None` (equivalent to `"default"`).

| Preset | What is saved |
| :- | :- |
| `"default"` | Saves only user-role text events (the default). The `openviking` backend includes assistant-role events as well due to its own limitations. |
| `"all"` | Saves all roles and all event types, including thoughts and empty text. |
| `"custom"` | Starts with unrestricted roles and event types, but still excludes thoughts and empty text by default; explicit fields can override these choices |

Using a preset string:

```python lines theme={null}
from veadk import Agent
from veadk.memory.long_term_memory import LongTermMemory

agent = Agent(
    name="ltm_agent",
    auto_save_session=True,
    auto_save_memory_policy="all",
    long_term_memory=LongTermMemory(backend="viking", app_name="ltm_demo"),
)
```

Using a `MemoryAutoSavePolicy` instance for fine-grained control:

```python lines theme={null}
from veadk import Agent
from veadk.memory import MemoryAutoSavePolicy
from veadk.memory.long_term_memory import LongTermMemory

agent = Agent(
    name="ltm_agent",
    auto_save_session=True,
    auto_save_memory_policy=MemoryAutoSavePolicy(
        preset="custom",
        include_roles=["user", "assistant"],
        include_event_types=["text", "function_call", "function_response"],
        include_thought=False,
    ),
    long_term_memory=LongTermMemory(backend="viking", app_name="ltm_demo"),
)
```

Full fields of `MemoryAutoSavePolicy`:

| Field | Type | Default | Description |
| :- | :- | :- | :- |
| `preset` | `"default" \| "all" \| "custom"` | `"default"` | Selects the base preset. Fields you do not explicitly override keep the preset's defaults. |
| `include_roles` | `list["user" \| "assistant" \| "system"] \| None` | Depends on preset | Only save events from these roles. Set to `None` to disable role filtering. |
| `exclude_roles` | `list["user" \| "assistant" \| "system"]` | `[]` | Exclude events from these roles. |
| `include_authors` | `list[str] \| None` | Depends on preset | Only save events from these authors (`author`). Set to `None` to disable author filtering. |
| `exclude_authors` | `list[str]` | `[]` | Exclude events from these authors. |
| `include_event_types` | `list[MemoryEventType] \| None` | Depends on preset | Only save these event types. Set to `None` to disable event-type filtering. |
| `exclude_event_types` | `list[MemoryEventType]` | `[]` | Exclude these event types. |
| `text_only` | `bool` | Depends on preset | When `True` and `include_event_types` is not set, only text and thought content is kept. |
| `include_thought` | `bool` | Depends on preset | Whether to save thought content. |
| `include_empty_text` | `bool` | Depends on preset | Whether to save events with no actual content. |

`MemoryEventType` includes the following event types: `text`, `thought`, `function_call`, `function_response`, `tool_call`, `tool_response`, `media`, `executable_code`, `code_execution_result`, `transcription`, `error`.

<Note>
  String presets provide a quick configuration shortcut. When you pass a `MemoryAutoSavePolicy` instance or `dict`, the policy starts from the base preset indicated by `preset`; only the fields you explicitly set override the preset, while all other fields keep the preset's default behavior.
</Note>

## Cross-session example

First complete [model configuration](/productions/veadk/preview/en/components/agent/model) and [local memory embedding configuration](/productions/veadk/preview/en/components/memory/local), then run this end-to-end flow: session #1 tells the agent a fact and auto-archives it, then a **brand-new** session #2 asks a question — and the agent recalls the fact via memory retrieval (not the context window). This uses the `local` backend, which needs `pip install "veadk-python[extensions]"`.

```python lines theme={null}
import asyncio

from veadk import Agent, Runner
from veadk.memory.long_term_memory import LongTermMemory

APP_NAME = "ltm_demo"
USER_ID = "user-42"


def build_runner() -> Runner:
    ltm = LongTermMemory(backend="local", app_name=APP_NAME)
    agent = Agent(
        name="ltm_agent",
        instruction=(
            "You are a personal assistant. When the user asks about something they "
            "told you earlier, use the `load_memory` tool to recall it."
        ),
        long_term_memory=ltm,
        auto_save_session=True,
    )
    return Runner(agent=agent, app_name=APP_NAME, user_id=USER_ID)


async def main() -> None:
    runner = build_runner()

    print(
        "Session 1 ->",
        await runner.run(
            messages="Note this: I'm allergic to peanuts and I'm vegetarian.",
            session_id="session-1",
        ),
    )

    print(
        "Session 2 ->",
        await runner.run(
            messages="Recommend a dish for me, considering my dietary restrictions.",
            session_id="session-2",
        ),
    )


if __name__ == "__main__":
    asyncio.run(main())
```

In session #2 the agent recognizes the same user's preferences left in session #1 and answers coherently and personally (e.g. a peanut-free vegetarian dish).

## Isolation and save boundaries

Long-term memory does not guarantee permanent storage: `local` keeps data in one instance and does not filter retrieval by user. Mem0 does not use index as a service-side isolation key; OpenViking requires explicit owner/context and peer mapping. Follow each backend page to establish application and user isolation

The time threshold is not a background timer and does not guarantee a final save before process exit. Explicitly save and verify retrieval for information that must be retained. An empty `search_memory()` result can also indicate a backend error. Repeatedly saving an entire session manually can duplicate writes; auto-save incremental behavior does not apply to arbitrary manual calls

The memory-management snippets belong inside the same async workflow: define APP\_NAME, USER\_ID, and SESSION\_ID, and verify a nonempty Session before saving. The cross-session example provides a complete entry point. The all policy can send thoughts, tool inputs and outputs, and media information to storage; establish retention requirements before enabling it
