Aller au contenu principal

Processeurs de mémoire

Les processeurs de mémoire transforment et filtrent les messages lorsqu'ils traversent un agent dont la mémoire est activée. Ils gèrent les limites de la fenêtre de contexte, suppriment le contenu superflu et optimisent les informations envoyées au modèle de langage.

Lorsque la mémoire est activée sur un agent, Mastra ajoute des processeurs de mémoire à son pipeline de processeurs. Ces processeurs récupèrent l'historique des messages, la mémoire de travail et les messages sémantiquement pertinents, puis conservent les nouveaux messages après la réponse du modèle.

Les processeurs de mémoire sont des processeurs qui agissent spécifiquement sur les messages et l'état liés à la mémoire.

Processeurs de mémoire intégrés
Lien direct vers Processeurs de mémoire intégrés

Mastra ajoute automatiquement les processeurs suivants lorsque la mémoire est activée :

MessageHistory
Lien direct vers messagehistory

Récupère l'historique des messages et conserve les nouveaux messages.

Lorsque vous configurez :

memory: new Memory({
lastMessages: 10,
})

En interne, Mastra :

  1. Crée un processeur MessageHistory avec limit: 10.
  2. L'ajoute aux processeurs d'entrée de l'agent (exécution avant le LLM).
  3. L'ajoute aux processeurs de sortie de l'agent (exécution après le LLM).

Son rôle :

  • Entrée : récupère les 10 derniers messages dans le stockage et les ajoute au début de la conversation.
  • Sortie : conserve les nouveaux messages dans le stockage après la réponse du modèle.

Exemple :

import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'
import { openai } from '@ai-sdk/openai'

const agent = new Agent({
id: 'test-agent',
name: 'Test Agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'memory-store',
url: 'file:memory.db',
}),
lastMessages: 10, // MessageHistory processor automatically added
}),
})

SemanticRecall
Lien direct vers semanticrecall

Récupère les messages sémantiquement pertinents en fonction de l'entrée actuelle et crée des embeddings pour les nouveaux messages.

Lorsque vous configurez :

memory: new Memory({
semanticRecall: { enabled: true },
vector: myVectorStore,
embedder: myEmbedder,
})

En interne, Mastra :

  1. Crée un processeur SemanticRecall.
  2. L'ajoute aux processeurs d'entrée de l'agent (exécution avant le LLM).
  3. L'ajoute aux processeurs de sortie de l'agent (exécution après le LLM).
  4. Nécessite la configuration d'un stockage vectoriel et d'un modèle d'embedding.

Son rôle :

  • Entrée : effectue une recherche par similarité vectorielle afin de trouver les anciens messages pertinents et les ajoute au début de la conversation.
  • Sortie : crée des embeddings pour les nouveaux messages et les enregistre dans le stockage vectoriel en vue d'une récupération ultérieure.

Exemple :

import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'
import { PineconeVector } from '@mastra/pinecone'
import { OpenAIEmbedder } from '@mastra/openai'
import { openai } from '@ai-sdk/openai'

const agent = new Agent({
name: 'semantic-agent',
instructions: 'You are a helpful assistant with semantic memory',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'memory-store',
url: 'file:memory.db',
}),
vector: new PineconeVector({
id: 'memory-vector',
apiKey: process.env.PINECONE_API_KEY!,
}),
embedder: new OpenAIEmbedder({
model: 'text-embedding-3-small',
apiKey: process.env.OPENAI_API_KEY!,
}),
semanticRecall: { enabled: true }, // SemanticRecall processor automatically added
}),
})

WorkingMemory
Lien direct vers workingmemory

Gère l'état de la mémoire de travail d'une conversation à l'autre.

Lorsque vous configurez :

memory: new Memory({
workingMemory: { enabled: true },
})

En interne, Mastra :

  1. Crée un processeur WorkingMemory.
  2. L'ajoute aux processeurs d'entrée de l'agent (exécution avant le LLM).
  3. Nécessite la configuration d'un adaptateur de stockage.

Son rôle :

  • Entrée : récupère l'état de la mémoire de travail du thread actuel et l'ajoute au début de la conversation.
  • Sortie : aucun traitement de sortie.

Exemple :

import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'
import { openai } from '@ai-sdk/openai'

const agent = new Agent({
name: 'working-memory-agent',
instructions: 'You are an assistant with working memory',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({
id: 'memory-store',
url: 'file:memory.db',
}),
workingMemory: { enabled: true }, // WorkingMemory processor automatically added
}),
})

Contrôle manuel et déduplication
Lien direct vers Contrôle manuel et déduplication

Si vous ajoutez manuellement un processeur de mémoire à inputProcessors ou à outputProcessors, Mastra ne l'ajoutera pas automatiquement. Vous maîtrisez ainsi entièrement l'ordre des processeurs :

import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { MessageHistory } from '@mastra/core/processors'
import { TokenLimiter } from '@mastra/core/processors'
import { LibSQLStore } from '@mastra/libsql'
import { openai } from '@ai-sdk/openai'

// Custom MessageHistory with different configuration
const customMessageHistory = new MessageHistory({
storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }),
lastMessages: 20,
})

const agent = new Agent({
name: 'custom-memory-agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }),
lastMessages: 10, // This would normally add MessageHistory(10)
}),
inputProcessors: [
customMessageHistory, // Your custom one is used instead
new TokenLimiter({ limit: 4000 }), // Runs after your custom MessageHistory
],
})

Ordre d'exécution des processeurs
Lien direct vers Ordre d'exécution des processeurs

Il est important de comprendre l'ordre d'exécution lorsque vous associez des garde-fous à la mémoire :

Processeurs d'entrée
Lien direct vers Processeurs d'entrée

[Memory Processors] → [Your inputProcessors]
  1. Les processeurs de mémoire s'exécutent EN PREMIER : WorkingMemory, MessageHistory, SemanticRecall.
  2. Vos processeurs d'entrée s'exécutent ENSUITE : garde-fous, filtres et validateurs.

La mémoire charge donc l'historique des messages avant que vos processeurs puissent valider ou filtrer l'entrée.

Processeurs de sortie
Lien direct vers Processeurs de sortie

[Your outputProcessors] → [Memory Processors]
  1. Vos processeurs de sortie s'exécutent EN PREMIER : garde-fous, filtres et validateurs.
  2. Les processeurs de mémoire s'exécutent ENSUITE : SemanticRecall (embeddings), MessageHistory (persistance).

Cet ordre est conçu pour être sûr par défaut : si votre garde-fou de sortie appelle abort(), les processeurs de mémoire ne s'exécutent jamais et aucun message n'est enregistré.

Garde-fous et mémoire
Lien direct vers Garde-fous et mémoire

L'ordre d'exécution par défaut garantit un comportement sûr des garde-fous :

Les garde-fous de sortie s'exécutent avant que les processeurs de mémoire n'enregistrent les messages. Si un garde-fou interrompt l'exécution :

  • Le tripwire est déclenché.
  • Les processeurs de mémoire sont ignorés.
  • Aucun message n'est conservé dans le stockage.
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { openai } from '@ai-sdk/openai'

// Output guardrail that blocks inappropriate content
const contentBlocker = {
id: 'content-blocker',
processOutputResult: async ({ messages, abort }) => {
const hasInappropriateContent = messages.some(msg => containsBadContent(msg))
if (hasInappropriateContent) {
abort('Content blocked by guardrail')
}
return messages
},
}

const agent = new Agent({
id: 'safe-agent',
name: 'safe-agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({ lastMessages: 10 }),
// Your guardrail runs BEFORE memory saves
outputProcessors: [contentBlocker],
})

// If the guardrail aborts, nothing is saved to memory
const result = await agent.generate('Hello')
if (result.tripwire) {
console.log('Blocked:', result.tripwire.reason)
// Memory is empty - no messages were persisted
}

Garde-fous d'entrée
Lien direct vers Garde-fous d'entrée

Les garde-fous d'entrée s'exécutent après que les processeurs de mémoire ont chargé l'historique. Si un garde-fou interrompt l'exécution :

  • Le tripwire est déclenché.
  • Le LLM n'est jamais appelé.
  • Les processeurs de sortie, y compris la persistance en mémoire, sont ignorés.
  • Aucun message n'est conservé dans le stockage.
// Input guardrail that validates user input
const inputValidator = {
id: 'input-validator',
processInput: async ({ messages, abort }) => {
const lastUserMessage = messages.findLast(m => m.role === 'user')
if (isInvalidInput(lastUserMessage)) {
abort('Invalid input detected')
}
return messages
},
}

const agent = new Agent({
id: 'validated-agent',
name: 'validated-agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({ lastMessages: 10 }),
// Your guardrail runs AFTER memory loads history
inputProcessors: [inputValidator],
})

Récapitulatif
Lien direct vers Récapitulatif

Type de garde-fouMoment de l'exécutionEn cas d'interruption
EntréeAprès le chargement de l'historique par la mémoireLe LLM n'est pas appelé et rien n'est enregistré
SortieAvant l'enregistrement par la mémoireRien n'est enregistré dans le stockage

Les deux scénarios sont sûrs : les garde-fous empêchent la conservation en mémoire de contenu inapproprié.

Gérer les pièces jointes volumineuses
Lien direct vers Gérer les pièces jointes volumineuses

Certains fournisseurs de stockage imposent des limites à la taille des enregistrements, que les pièces jointes encodées en base64 peuvent dépasser :

FournisseurTaille maximale d'un enregistrement
DynamoDB400 KB
Convex1 MiB
Cloudflare D11 MiB

PostgreSQL, MongoDB et libSQL ont des limites plus élevées et ne sont généralement pas concernés.

Utilisez un processeur d'entrée pour téléverser les pièces jointes vers un stockage externe, puis remplacez-les par des références URL avant la conservation des messages.

src/mastra/processors/attachment-uploader.ts
import type { Processor } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'

export class AttachmentUploader implements Processor {
id = 'attachment-uploader'

async processInput({ messages }: { messages: MastraDBMessage[] }) {
return Promise.all(messages.map(message => this.processMessage(message)))
}

async processMessage(message: MastraDBMessage) {
const attachments = message.content.experimental_attachments
if (!attachments?.length) return message

const uploaded = await Promise.all(
attachments.map(async attachment => {
if (!attachment.url?.startsWith('data:')) return attachment

const url = await this.upload(attachment.url, attachment.contentType)
return { ...attachment, url }
}),
)

return { ...message, content: { ...message.content, experimental_attachments: uploaded } }
}

async upload(dataUri: string, contentType?: string): Promise<string> {
const base64 = dataUri.split(',')[1]
const buffer = Buffer.from(base64, 'base64')

throw new Error('Implement upload() with your storage provider')
}
}

Utilisez le processeur avec votre agent :

src/mastra/agents/support-agent.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { AttachmentUploader } from '../processors/attachment-uploader'

export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support agent',
instructions: 'Answer customer support questions.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({ lastMessages: 10 }),
inputProcessors: [new AttachmentUploader()],
})

Lorsque vous créez des processeurs personnalisés, évitez de modifier directement le tableau d'entrée messages ou les objets qu'il contient.