Guides / Frameworks
Mastra
For agents built with Mastra (@mastra/core, version 1). @recall-memory/mastra gives an agent Recall memory through processors, Mastra's own place for memory: one RecallMemory adds what Recall knows about the user to each run and stores every turn, and three tools let the agent search memory, ask it a question and save a fact.
What you get
| Export | What it does |
|---|---|
RecallMemory | A processor. In inputProcessors it adds what Recall knows about the user, biased towards their message, as a system message. In outputProcessors it stores the user's message and the agent's reply in the session. Use the same instance in both. |
recallTools(options) | Tools for the agent's tools: searchMemory (facts and messages that match), askMemory (a question about the user, answered from memory) and rememberFact (save one fact). |
Both take optional recall (a client; by default one is made from RECALL_API_KEY), userId and sessionId. Without ids they use the run's: the resource is the user and the thread is the conversation.
Build it
Install the package and the SDK (npm install @recall-memory/mastra @recall-memory/sdk; @mastra/core you already have) and set RECALL_API_KEY. The user is a Recall peer keyed by your own stable user id, and each conversation is a session. Facts from your app's settings can go in directly.
import { Agent } from "@mastra/core/agent";
import {
MASTRA_RESOURCE_ID_KEY,
MASTRA_THREAD_ID_KEY,
RequestContext,
} from "@mastra/core/request-context";
import { RecallMemory, recallTools } from "@recall-memory/mastra";
import { Recall } from "@recall-memory/sdk";
const recall = new Recall({ workspaceId: "my-app" });
// Who the memory is about (your own stable user id) and the conversation it belongs to.
const userId = "user-8412";
const sessionId = "chat-20261013-a91f";
// A fact from your app's settings, stored as given and searchable at once.
await recall.peer(userId).conclusions.create("Is vegetarian.");
An agent with memory. Put one RecallMemory in both processor lists, and add the tools if the agent should use memory on its own. The agent is defined once; who it talks to comes with each run.
// `model` is any model Mastra accepts. One RecallMemory serves as input processor (it adds what
// Recall knows about the user to the run) and as output processor (it stores the turn).
const memory = new RecallMemory({ recall });
const agent = new Agent({
id: "assistant",
name: "Assistant",
instructions: "You are a helpful assistant.",
model,
tools: { ...recallTools({ recall }) },
inputProcessors: [memory],
outputProcessors: [memory],
});
Each run: who and which conversation. Set the run's resource and thread in the request context. In a Mastra server your auth middleware usually sets the resource from the signed-in user, so one user can never read another's memory. If the agent also has Mastra memory, memory: { resource, thread } on the call works too.
// The run's resource is the user and its thread the conversation. Your auth middleware usually
// sets the resource, so one user can never read another's memory.
const requestContext = new RequestContext();
requestContext.set(MASTRA_RESOURCE_ID_KEY, userId);
requestContext.set(MASTRA_THREAD_ID_KEY, sessionId);
const result = await agent.generate("Can you plan a dinner for four on Saturday?", {
requestContext,
});
If Recall cannot be reached, the run goes on without memory and onError is told. To take the ids from somewhere else, pass functions: new RecallMemory({ userId: ({ requestContext }) => requestContext?.get("userId") }).
Settings that matter
| Option | Use |
|---|---|
userId, sessionId | A fixed id, a function of the request context, or (the default) the run's resource and thread. Use your own stable user id, not an email address. |
assistantId | The assistant's peer (default assistant). It is created with observeMe: false: Recall reads its replies as context but learns nothing about it. |
context: false / store: false | A processor that only stores turns, or only reads memory. |
maxConclusions | Most facts in the memory block. Fewer means a shorter prompt. |
reasoningLevel (tools) | The reasoning level for askMemory. See Reasoning levels and models. |
Cost and speed
Reading memory at the start of a run is a context call: it is included in the price and takes under a second. Storing the turn is one request at the end. Recall learns from the user's messages in the background, and that is what you pay for. askMemory is a question, a model call of a few seconds. Prices are on the pricing page and worked examples in Cost and speed.
Privacy and forgetting
Everything the user writes to an agent with RecallMemory is stored and learned from. Tell users in your privacy notice and keep secrets such as passwords and card numbers out of messages. Take the user id from your authentication, never from the request body. To forget a user, delete their peer (recall.peer(userId).delete()) and their sessions; see Privacy, consent and forgetting.
Pitfalls
- The processor in one list only. In
inputProcessorsalone it reads but never stores; inoutputProcessorsalone it stores but the agent never sees the memory. - No resource on the run. Without a user id the processor does nothing and the tools fail with a clear error. Set the resource, or pass
userId. - Expecting a fact to show up at once. Recall learns from messages in the background, usually within about 20 seconds. Facts saved with
rememberFactare searchable at once.
Next: Vercel AI SDK · LangChain.js