An assistant that remembers end users
Use userId, user visibility and user profiles so your app's assistant remembers each end user across conversations.
Problem: The assistant in your app meets each user from scratch in every conversation: it asks again for their preferences, earlier requests and context.
Solution: Represent each user with a userId. Write durable information about the user with that userId, protect personal information with visibility: "user", keep the general profile in the user profile, and recall with userId in every conversation.
This guide uses the Node SDK; the same fields exist in REST and Python.
Prerequisites
- An API key used from your server application (not the browser).
- The act for users permission on the key (console → API Keys). Without it, every call that includes
userIdreturns403. - For
userId, use a stable identifier from your own system that contains no personal data (e.g. an internal user number); don't use email addresses.
1. Client
import { AgentMemoryClient } from 'agentmemory'
const memory = new AgentMemoryClient({
apiKey: process.env.AGENT_MEMORY_API_KEY,
baseUrl: process.env.AGENT_MEMORY_URL,
workspaceId: process.env.AGENT_MEMORY_WS,
})2. Recall at the start of a conversation
async function recall(userId, conversationId, userMessage) {
const ctx = await memory.search(userMessage, { userId, runId: conversationId, tokenBudget: 1500 })
return {
receiptId: ctx.receiptId,
profile: ctx.userProfile?.content ?? '',
facts: ctx.workspaceEntries.map(e => `- ${e.content}`).join('\n'),
}
}When userId is given, results are narrowed to that user's memories, and user-visibility memories and the user profile are added to the context. Put this context in your model's system message.
3. Write what is durable
Don't write every message; write durable information: preferences, decisions, corrections.
await memory.add('Wants the weekly report as a PDF; does not want Excel', {
type: 'preference',
userId,
runId: conversationId,
sourceKind: 'user', // the user's own statement
visibility: 'user', // only calls reading on behalf of this user see it
idempotencyKey: `${conversationId}:pref:report-format`,
})If you'd rather store the raw conversation and let the system extract the information, write the lines to the Session layer as raw and run consolidation with instructions at the end of the conversation (REST). See Writing memory.
4. Keep the user profile up to date
Use the profile for short information that applies to every conversation:
curl -s -X PUT "$API/v1/memory/users/$WS/u-10293/profile" \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"content":"Language: Turkish. Report: PDF, Monday. Contact: in-app notification instead of email."}'Here $API is https://memory.empecta.com. The profile is free text; your application can write it in any format (e.g. line-by-line key–value pairs). To fill it automatically from preferences, enable the userProfile.autoEnrich setting.
5. When a preference changes
When the user says "I want Excel now":
- If the old memory's text is wrong, use
memory.update(id, newText, { ifMatch }). - If a new preference invalidates the old one, write the new memory and mark the old one with
supersedes(via MCP), or delete the old one.
6. Report the outcome (optional)
If the user is happy with the answer, report it together with the receipt:
await memory.outcome({ runId: conversationId, receiptId, userRating: 5 })7. Deleting user data
If the user asks for some of their information to be deleted, delete the relevant memory and confirm completion with erasure. There is no single call that deletes all of a user's memories; your application can keep the IDs of the user's memories (e.g. the id in write responses) and delete them one by one. See Data management.
Responsibilities: product and application
| Agent Memory provides | Your application provides |
|---|---|
User-bound memories, user visibility, profiles, context assembly, identity binding (a key without act for users can't act on behalf of users) | Authenticating the user and sending the correct userId, the model call, the chat UI, deciding what to write, user consent and privacy notices |
Because your key has the act for users permission, it can act on behalf of any userId; separation between users depends on your application sending the correct userId. Don't put the key on the client side (browser, mobile app).
Related pages
Project memory for a coding agent
Give a coding agent persistent project memory over MCP so it stops forgetting decisions, corrections and rules between sessions.
Sharing across multiple agents and applications
Combine workspaces, applications, visibility and facets so shared rules reach everyone while app-specific and private notes stay contained.