Skip to main content
Memory lets agents remember past conversations, user preferences, and context across sessions.
A subset of Memory is now callable directly over MCP — see MCP Memory Tools.
Replaces the deprecated auto_save="name" kwarg — see Legacy Agent Parameters.

Grow memory autonomously

With self_improve="background" and memory=True, the same guarded post-turn review that autonomously grows skills can also autonomously persist durable facts and preferences via store_memory — off the hot path, with zero cost to reply latency and zero context pollution during the live turn. See Self-Improving Agents.
The user shares preferences in chat; the agent recalls them in later sessions via the configured memory backend.
Breaking change: backend no longer accepts redis/postgres/valkey.MemoryConfig(backend="redis"), backend="postgres", and backend="valkey" now raise a ValueError instead of silently substituting a local file store. Earlier releases accepted these values but stored data locally — so any code that “worked” was already not reaching Redis/Postgres.Valid backends: file, sqlite, chroma, mem0, mongodb, dakera, in_memory.Two supported ways to use Redis / Postgres:
  1. Recommended — pass a live db() store:
    from praisonaiagents import db binds the callable factory directly. The namespaced from praisonaiagents.db import db form still works.
  2. Advanced — register a custom adapter:
See Redis persistence for the full db(state_url=...) guide.

Quick Start

1

Level 1 — Bool (simplest)

Turn on memory with a single flag — the agent remembers across turns using the default file backend.
memory=True and memory="file" are truly zero-dependency — the agent skips importing the heavier Memory module on this path, so Agent(memory=True) starts as fast as an agent with no memory. Heavier backends (sqlite, chroma, mem0, mongodb, dakera, or learn=True) load their dependencies lazily and raise a friendly ImportError if the praisonaiagents[memory] extra isn’t installed.If a memory provider’s backend package is installed but initialisation fails (for example a SaaS backend like mem0 needs credentials or network), the agent now falls back to FileMemory with a warning instead of raising. This mirrors the existing “missing dependencies → FileMemory” contract, so Agent(...) construction never hard-crashes on a misconfigured backend.
2

Level 2 — String (pick a backend)

Pass a backend name to choose where memories are stored.
3

Level 3 — Config class (full control)

Use MemoryConfig to scope memory per user and auto-extract facts.
4

Level 4 — Config with continuous learning

Add LearnConfig to build a long-term persona alongside session memory.

How It Works

Retrieved memory reaches the system prompt under normal logging (WARNING/INFO). You no longer need verbose=5 / DEBUG logging or an explicit include_in_output=True for Agent(memory=True) to take effect during a chat — see Memory Troubleshooting.
Turn on prefetch=True on MemoryConfig to have relevant long-term memories injected into the system prompt at the start of every turn — no explicit recall() call required.

Which Backend to Choose?


Configuration Options

Full list of options, types, and defaults — MemoryConfig
The most common options at a glance:
Turn on prefetch=True on MemoryConfig to have relevant long-term memories injected into the system prompt at the start of every turn — no explicit recall() call required. See Memory Prefetch for the full guide.

Combining backend and config

Pass a config= dict alongside backend= to hand provider-specific settings to the store — the outer backend= still decides which store is built.
An explicit provider or backend key inside config= wins; otherwise the outer backend= fills in.
The config dict you pass in is never mutated — a provider key, if injected, is written to an internal copy. Safe to share the same dict across multiple agents.

Common Patterns

Pattern 1 — User-scoped memory

Pattern 2 — History injection for conversation continuity

Default sessions are workspace-scoped — the same agent name in a different project is a different session. See Where sessions live for details and the PRAISONAI_GLOBAL_SESSIONS opt-out.

Pattern 3 — Recalled context at turn start

The agent sees a ## Recalled memories block in its system prompt before the first model call — no extra tool call needed.

Quick API — remember, recall, forget

Three verbs give you explicit control over long-term facts — store, look up, and delete. An agent with memory=True exposes its memory instance directly, so you can store and recall facts on demand.
Use Memory() standalone in a plain script — no config, no agent required.

Prompt-ready context — get_context

get_context(query=...) returns retrieved memory as a single prompt-ready string for a given query — the same string Agent.get_memory_context() injects into the system prompt.
An empty or whitespace-only query intentionally returns "" — this avoids a LIKE "%%" scan that would pull in unrelated (and possibly other users’) records.
Pass user_id="…" (or configure it on MemoryConfig) so user-scoped memories stay isolated when a single Memory instance is shared across users.

Parameters

remember() and recall() operate on long-term memory only, and forget(query=...) is scoped to long-term memory to match. forget() requires exactly one of memory_id or query — passing neither, both, or an empty query raises ValueError.
Cross-tier id collisions are normal. The SQLite adapter numbers short-term and long-term rows independently, so the Nth short-term row and the Nth long-term row share an id. forget(memory_id=id) now deletes from both tiers by design — previously it short-circuited on the first hit and could erase the wrong record while reporting success. If you need tier-scoped deletion, call agent.memory.delete_memory(memory_id, memory_type="long_term") (or "short_term").
agent.memory.get_all_memories() returns every stored short-term and long-term record (each with a public type field of "short_term" or "long_term"). When a memory adapter is configured, it now correctly delegates to the adapter — earlier releases returned [] for every provider.

Which memory API?

Interaction flow


Best Practices

As of PraisonAI PR #3614, Agent(memory=True) without a user_id generates a fresh per-instance identifier (agent-<uuid>) and logs a warning. Memory is isolated per Agent object by default — safe, but not what you want if you re-create the agent between requests and expect it to remember the last conversation.Pass user_id="alice" (or "tenant-42", "project-climate", etc.) to opt into a shared / persistent store that survives across processes.As of PraisonAI #4203, this isolation now covers every backend — sqlite, chroma, mongodb, mem0, and learn derive per-agent default store paths and collection names from the same agent-<uuid> id, so two agents in one process no longer silently share one short_term.db / long_term.db / memory_store. Explicit user_id, short_db, long_db, rag_db_path, or collection_name still win. See Per-agent isolation across backends.
Enable auto_memory=True to have the agent automatically identify and store important facts from each conversation — names, preferences, decisions — without extra code.
Set learn=True inside MemoryConfig to enable continuous learning alongside session memory. This gives agents both short-term context (memory) and long-term pattern recognition (learn).
Start with file, move to sqlite when you need durability, then mongodb (or chroma for vector search) when you deploy multiple agent instances that share memory. For Redis or Postgres, use memory=MemoryConfig(db=db(state_url="redis://...")) or db(database_url="postgresql://...") — see Redis persistence.
Agent(memory=True) auto-captures every conversation turn. remember() / recall() / forget() give you explicit control for fact storage — use them for structured knowledge you want to look up later. Both share the same long-term store when the agent’s memory instance is used.

Async safety

Task-callback memory writes (store_in_memory in Task.execute_callback) run on a worker thread on the async path. Parallel tasks batched into a single asyncio.gather(...) no longer stall the event loop on one slow embedding/DB write. The built-in in-memory adapter is thread-safe: concurrent async writes from multiple parallel tasks cannot produce duplicate ids or lose entries. No user-facing change: the async path automatically dispatches the write via asyncio.to_thread.
If you write a custom memory adapter that will be used from async task callbacks, make its mutating methods thread-safe — see Custom Memory Adapters. The full set of async guarantees lives on the Async Safety page.

Learn

Learn — continuous learning from conversations

Knowledge

Knowledge — add documents and URLs as agent knowledge

Memory Flush on Compaction

Preserve facts before compaction — save durable facts before older messages are dropped

Async Safety

Offloaded memory writes and the thread-safe in-memory adapter