The first design question for agent memory is its scope: what does one memory hold? Threadless AI answers it one way. A memory is one conversation. Its id is the only scope there is.
Why one conversation
- Recall stays relevant. Facts recalled into a conversation come from that conversation. A user's support ticket about billing does not surface in their chat about a product launch.
- Isolation is simple and complete. Every read and write names its memory id; a request without one is refused, never widened. Recall searches within one memory and never across your other memories, let alone another customer's. See Security.
- A conversation can run for months. There is no length at which you need a new memory, so there is no pressure to merge conversations to keep context.
Mapping it to your ids
Create a memory when a conversation starts, and store its id next to your own conversation id. You can also keep your ids in the memory's metadata, up to 16 string pairs.
const { id } = await memory.memories.create({
metadata: { conversation: 'c_123', user: 'u_9', tenant: 'acme' },
});
await db.conversations.update('c_123', { memoryId: id });Use that one id for every call in the conversation, tool loops included.
Multi-tenant apps
Memories belong to the project of the API key that created them, and a key reaches only its own project's memories; any other id answers 404. Two common layouts:
- One project for your app, a memory per end-user conversation, with tenant and user ids in metadata. Simplest.
- A project per tenant, each with its own keys, when tenants need separate usage reporting or key management.
Edits and branches
A memory only grows: messages are appended, never rewritten.
- The user edits an earlier message and regenerates: start a new memory and send it the conversation as it now stands, up to the edit, in its first
decorate. - Two continuations from one point: each branch is its own memory, seeded the same way.
What about facts about the user?
Some apps want what was learned about a person carried into every new conversation: their name, their company, their preferences. Threadless AI does not share facts across memories, by design. Two ways to handle it:
- Put durable user facts in your instructions. Your system or developer message is stored and always leads the request; update it when the facts change.
- Keep a profile in your own database and write it into the first message of each new conversation.
If cross-conversation memory of a user is the core of your product, a per-user memory store fits that need more directly.
Deleting
memory.memories.delete(id) removes everything the memory holds and checks it is gone before it returns. For a user who asks to be forgotten, delete each memory whose metadata names them.
Questions people ask
Should agent memory be per user or per conversation?
In Threadless AI, per conversation: a memory's id is its only scope, and recall never crosses memories. If carrying facts about a person into every new conversation is the core of your product, a per-user memory store fits that need more directly.
When do I need a new memory?
When a new conversation starts, when the user edits an earlier message, or when a conversation branches. A long conversation never needs one: it can run for months, and token use stays bounded however long it runs.
Can two conversations share a memory?
They should not. Facts from one would be recalled into the other. Give each conversation its own memory and keep shared facts about the user in your instructions.
How do I find all of a user's memories?
Put your user id in each memory's metadata when you create it (up to 16 string pairs), and keep the memory id beside your own conversation id in your database.
Can one API key read another project's memories?
No. A key reaches only its own project's memories; any other id answers 404 not_found.