Agent Memory

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 userId returns 403.
  • 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 providesYour 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).

On this page