User memories are the layer above session storage. While session storage keeps a single conversation coherent, user memories let the agent remember things about a specific person across every conversation they have. “Prefers concise answers.” “This user is on the enterprise tier.” “Their renewal is in November.” The data lives in the same Postgres schema as session storage, scoped byDocumentation Index
Fetch the complete documentation index at: https://docs.xpander.ai/llms.txt
Use this file to discover all available pages before exploring further.
user_id instead of session_id. Each user’s memories are completely isolated. One user’s preferences never leak into another’s conversations, even when they interact with the same agent. The two layers turn on independently, so you can have user memories without session storage (or vice versa).
User memories are wired in automatically only for Agno. The DB connection and helpers on this page raise
NotImplementedError on LangChain, OpenAI Agents SDK, and AWS Strands. See the framework pages for the manual integration story.Configuration
The settings below live onagent.agno_settings and are toggled in the agent’s Memory tab in Agent Studio. Both modes require session storage to be on, since user memories are stored alongside sessions.
Configure memory in Agent Studio
UI walkthrough for toggling user memory and switching between agentic and manual modes.
| Setting | What it controls | Default |
|---|---|---|
user_memories | Turn user-memory storage on. The agent reads memories during reasoning. | False |
agentic_memory | When on, the agent decides what to write. When off, your code writes through the SDK. | False |
Manual vs agentic mode
There are two flavors, and they’re mutually exclusive:- Manual mode (
user_memories = True): the agent has access to a memory store, but it doesn’t decide on its own when to write to it. Your code calls the memory APIs to add, update, and remove facts. - Agentic mode (
agentic_memory = True): the agent decides when to write memories. As conversations happen, it surfaces facts worth remembering and stores them automatically.
Identifying the user
The agent identifies a user via theUser object on the task input. When you create a task, pass the user details:
emailis the only required field onUser.id,first_name,last_name,additional_attributes, andtimezoneare optional.- The framework scopes the memory lookup by these fields together, so anything stored against that user surfaces the next time they show up.
- Inside
@on_task, the same object lives ontask.input.user: read it back when you need the active user.
Add, inspect, and edit memories
On Agno-backed agents memories are loaded into context automatically wheneveruser_memories or agentic_memory is on. You don’t have to do anything for the agent to see them. Reach for the DB when you want to add memories yourself (manual mode), audit what’s been stored, correct something the agent kept by mistake, or seed facts from another system.
agent.aget_db() returns the same AsyncPostgresDb connection the framework reads and writes through, so admin tools, migration scripts, and your handler all share one source of truth.
Add a memory
db.upsert_user_memory inserts a new memory or updates an existing one by memory_id. In manual mode this is how your app writes memories; in agentic mode use it to seed or override what the agent stored on its own.
UserMemory.memorycarries the content (notcontent).user_id,topics,input, andfeedbackare the other useful fields.memory_idis auto-generated on insert. Pass an existingmemory_idto update that record in place.- The upsert is keyed by
memory_id, so the same call shape adds or edits depending on whether the ID exists.
@on_boot hook or run them in the handler when get_user_memories returns empty.
Inspect memories
db.get_user_memories(user_id=...) lists every memory keyed to one user. Each UserMemory exposes memory_id, memory, topics, created_at, and updated_at.
Edit or delete
To edit, upsert with an existingmemory_id:
SDK reference
| Method | Returns | What it’s for |
|---|---|---|
agent.aget_db(async_db=True) | AsyncPostgresDb | The Postgres handle scoped to this agent’s schema. Sync form: agent.get_db(). |
db.get_user_memories(user_id) | list[UserMemory] | List every memory keyed to one user. |
db.upsert_user_memory(UserMemory(...)) | UserMemory | Insert or update a memory by memory_id. |
db.delete_user_memory(memory_id) | None | Remove one record by ID. |
db.delete_user_memories(memory_ids, user_id) | None | Bulk delete. |
Token cost considerations
User memories cost LLM calls. In agentic mode the agent decides when to extract memories from a conversation (one extra LLM call per session, sometimes more). On every turn, the relevant memories are loaded into context, which costs tokens. For high-volume agents, the math matters: if your agent handles 100,000 conversations a month and each one triggers a memory-extraction call, that’s 100,000 extra LLM calls. For most production cases the trade is worth it, but verify against your usage patterns.Troubleshooting
User memories don't appear in the agent's responses
User memories don't appear in the agent's responses
First check that you’re passing
user_details (or task.input.user) on every invocation. Without an identifier, memories have nowhere to scope. Then confirm user_memories or agentic_memory is on via xpander_agent.agno_settings. If the user is brand new and the agent is in agentic mode, give it a few exchanges to find something worth remembering.Agentic mode isn't writing any memories
Agentic mode isn't writing any memories
The agent only writes when it decides a fact is worth remembering. Brief, transactional conversations may produce nothing. Verify
agentic_memory=True (not user_memories=True; they’re mutually exclusive) and that the conversation has at least a few exchanges with substantive content.A memory the agent stored is wrong or sensitive
A memory the agent stored is wrong or sensitive
Look it up with
db.get_user_memories(user_id=...), find the offending row, and call db.delete_user_memory(memory_id=...). For systematic prevention, switch from agentic to manual mode so the agent can no longer write on its own.Memories I added through `db.upsert_user_memory` aren't showing up
Memories I added through `db.upsert_user_memory` aren't showing up
Confirm the
UserMemory.user_id matches the User.email (or User.id if you’re using IDs consistently) that the agent will see at runtime. Mismatched scoping is the most common cause. Then verify the agent is loaded fresh after the write; cached Agent instances from before the insert won’t reflect it until the next Agents().aget(...).Token usage is climbing as a user accumulates memories
Token usage is climbing as a user accumulates memories
Memories all load into context. Prune aggressively: iterate
get_user_memories, drop stale rows with delete_user_memory or delete_user_memories, and consider moving long-form context to a knowledge base where it’s retrieved on demand instead of always-on.What to read next
Agent memories
Org-wide knowledge, the layer above user memories.
Session storage
Single-conversation memory, the layer below.
Agno framework
The full args-dict reference for what
aget_args wires up.Output Response Filtering
Trim chatty connector responses before they reach the LLM.

