cd /news/ai-agents/add-long-term-memory-to-a-mastra-age… · home › topics › ai-agents › article
[ARTICLE · art-156863] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Add long-term memory to a Mastra agent (input/output processors, per-user recall)

Mohammed, founder of MemorySync, published a guide showing how to add per-user long-term memory to Mastra agents using the memorysync-mastra package's input and output processors. The integration hooks into Mastra's processor pipeline to extract durable facts about each user and recall them across threads, with identity resolved per call via a custom resolver, static IDs, or Mastra's RequestContext. The author notes the code is adapted from documentation and was not run for the post.

by read5 min views6 publishedOct 24, 2026

Disclosure: I'm Mohammed, founder of MemorySync. I drafted this article with AI assistance and reviewed it for accuracy against the official MemorySync and Mastra docs. The code is adapted from the docs and I haven't run it.

Mastra agents already have memory. Give an agent a Memory from @mastra/memory and pass memory: { resource, thread } on each call: resource is a stable id for the user and thread isolates one conversation (Mastra memory docs). Mastra also has working memory and semantic recall, stored in whichever storage provider you configure.

If that's working for you, keep it. This post is for when you want durable facts about each user extracted and recalled by a hosted service, wired in through Mastra's own processor pipeline. It uses MemorySync's Mastra integration, memorysync-mastra. MemorySync is a hosted memory layer, and I'm building it. Mastra behaviour comes from its docs on memory and processors. Everything about MemorySync comes from its Mastra Memory guide. The code is adapted from those docs. I haven't run it for this post, so check it against your versions.

npm install memorysync-mastra

Per the guide it supports @mastra/core 1.42+ (Node 20+ for the package; current @mastra/core itself requires Node 22+). npm currently lists 1.1.0 with peer @mastra/core >=1.42.0 <2.0.0. Set MEMORYSYNC_API_KEY in the environment, or pass apiKey, and keep it server-side.

Mastra processors are hooks in the agent pipeline: inputProcessors run before messages reach the model, outputProcessors run after the model responds and before the result is returned (processors docs). MemorySync uses one of each:

import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { createMemorySyncProcessors } from "memorysync-mastra";

const { inputProcessor, outputProcessor } = createMemorySyncProcessors({
  userId: "customer-7",     // scopes memory to one end user
  sessionId: "thread-42",   // groups the stored facts by thread
});

const agent = new Agent({
  id: "assistant",
  name: "Assistant",
  instructions: "You are a helpful assistant.",
  model: openai("your-model"),
  inputProcessors: [inputProcessor],
  outputProcessors: [outputProcessor],
});

await agent.generate("I'm vegetarian and I fly aisle.");

// Later, same user, any thread
const { text } = await agent.generate("Book my trip: flight plus a dinner spot.");

Per the guide:

generate/ stream call (it uses processInput, not the per-step hook), so multi-step tool loops don't add the block twice. Your instructions stay first; the memory block is appended after them.onError (a console warning by default) and never thrown. Prefer less wiring? withMemorySync(config, { userId }) wraps your agent config and merges both processors in, keeping any processors you already have (MemorySync's run after yours).

A Mastra server agent serves many users, so identity is resolved per call, in this priority order:

import { RequestContext } from "@mastra/core/request-context";
import {
  createMemorySyncProcessors,
  MASTRA_RESOURCE_ID_KEY,
  MASTRA_THREAD_ID_KEY,
} from "memorysync-mastra";

// 1. Your own resolver wins over everything
createMemorySyncProcessors({
  resolveIdentity: (requestContext) => ({
    userId: currentSession.userId,
    sessionId: currentSession.threadId,
  }),
});

// 2. Static ids (scripts, workers)
createMemorySyncProcessors({ userId: "customer-7", sessionId: "thread-42" });

// 3. Mastra's RequestContext, set by your server middleware
const ctx = new RequestContext();
ctx.set(MASTRA_RESOURCE_ID_KEY, "customer-7");
ctx.set(MASTRA_THREAD_ID_KEY, "thread-42");
await agent.generate(messages, { requestContext: ctx });

// 4. Mastra's own memory ids on the call
await agent.generate("I moved to Lisbon.", {
  memory: { resource: "customer-7", thread: "thread-42" },
});

Option 4 is handy if you already use Mastra memory: the same resource id becomes the MemorySync user. If no source yields a user id, recall is skipped and the write is refused (reported through onError), never sent to a default scope. Take the id from your auth session, not from the request body.

const stream = await agent.stream("Plan a dinner for my team.", {
  memory: { resource: "customer-7", thread: "thread-42" },
});
for await (const chunk of stream.textStream) process.stdout.write(chunk);

The user's message is sent once, after the full stream. Per the guide, a stream that errors mid-flight (finishReason: "error") sends nothing, so the retry sends the message once.

createMemorySyncProcessors({ userId, mode: "query" });   // relevant to the latest message (default)
createMemorySyncProcessors({ userId, mode: "profile" }); // stable overview of the user
createMemorySyncProcessors({ userId, mode: "full" });    // both

createMemorySyncProcessors({ userId, persist: false });  // read-only
createMemorySyncProcessors({ userId, recall: false });   // write-only

createMemorySyncProcessors({
  userId,
  k: 12,
  template: "What you know about this user:\n{context}",
});
js
import { createMemorySyncTools } from "memorysync-mastra";

const agent = new Agent({
  id: "assistant",
  name: "Assistant",
  instructions: "Use the memory tools to remember durable facts.",
  model: openai("your-model"),
  tools: { ...createMemorySyncTools({ userId: "customer-7" }) },
});

// For agents you don't fully trust: search and list only
createMemorySyncTools({ userId: "customer-7", readOnly: true });

The five tools are add_memory, search_memory, list_memories, update_memory (tags and importance only) and delete_memory; they return readable error strings instead of throwing. For workflows there are getMemoryContext, searchMemories and saveTurn. saveTurn sends only the user's message and throws on failure. The guide says a turn sent by both the processors and saveTurn is recognised server-side and extracted once.

resource) must match across calls. The thread can differ.@mastra/core 1.x from 1.42, and current core needs Node 22+. Does a Mastra agent remember previous conversations?

Yes, if you give it a Memory from @mastra/memory and pass memory: { resource, thread } on each call. To recall earlier messages, call the agent with the same resource and thread values. lastMessages controls how many recent messages are included (Mastra memory docs).

Where does Mastra store memory?

In the storage provider you configure. Memory needs a storage provider to persist message history; the quickstart uses @mastra/libsql (Mastra memory docs).

What's the difference between resource and thread in Mastra memory?

resource is a stable id for the user or entity, and thread isolates one conversation. Each thread's owner can't be changed after creation, so don't reuse a thread id across owners. Working memory and semantic recall are resource-scoped by default, so they carry across that user's threads (Mastra memory docs).

Can I use Mastra's Memory and the MemorySync processors together?

Yes. MemorySync's guide recommends running both: Mastra's Memory for the conversation history, and the MemorySync processors for durable per-user facts across threads. The processors can also read the user and thread from the same memory: { resource, thread } option (MemorySync Mastra guide).

If you want to see the save, reload and recall loop before wiring up an agent, the MemorySync playground runs it in your browser: memorysync.io/try.

── more in #ai-agents 4 stories · sorted by recency
── more on @memorysync 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/add-long-term-memory…] indexed:0 read:5min 2026-10-24 · —