> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt
# Processeurs
Les processeurs transforment, valident ou contrôlent les messages lors de leur passage dans un agent. Ils s’exécutent à des étapes précises du pipeline d’exécution de l’agent, ce qui vous permet de modifier les entrées avant qu’elles n’atteignent le modèle de langage, ou les sorties avant qu’elles ne soient renvoyées aux utilisateurs.
Les processeurs se configurent comme suit :
- **`inputProcessors`** : s’exécutent avant que les messages n’atteignent le modèle de langage.
- **`outputProcessors`** : s’exécutent après la génération d’une réponse par le modèle de langage, mais avant son renvoi aux utilisateurs.
Vous pouvez utiliser des objets [`Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) individuels ou les composer en workflows à l’aide des primitives de workflow de Mastra. Les workflows offrent un contrôle avancé sur l’ordre d’exécution des processeurs, le traitement parallèle et la logique conditionnelle.
Certains processeurs implémentent à la fois une logique d’entrée et de sortie. Ils peuvent donc être placés dans l’un ou l’autre tableau selon l’endroit où la transformation doit avoir lieu.
Certains processeurs intégrés envoient également des signaux de rappel système masqués. Ces signaux sont conservés dans l’historique brut de la mémoire et convertis en contexte `...` avant l’appel suivant au modèle. Toutefois, les conversions de messages standard destinées à l’interface utilisateur et le rappel mémoire par défaut les masquent, sauf activation explicite. Pour transmettre un signal uniquement pendant l’appel en cours sans le conserver, envoyez-le avec `transient: true`.
## Quand utiliser des processeurs
Utilisez des processeurs pour :
- normaliser ou valider les entrées utilisateur ;
- ajouter des garde-fous à votre agent ;
- détecter et empêcher les tentatives d’injection de prompt ou de jailbreak ;
- modérer le contenu pour des raisons de sécurité ou de conformité ;
- transformer les messages (par exemple, traduire des langues ou filtrer les appels d’outils) ;
- limiter l’utilisation des tokens ou la longueur de l’historique des messages ;
- masquer les informations sensibles (PII) ;
- appliquer une logique métier personnalisée aux messages.
Mastra fournit plusieurs processeurs adaptés aux cas d’usage courants. Vous pouvez également créer des processeurs personnalisés pour répondre aux besoins propres à votre application.
## Démarrage rapide
Importez et instanciez le processeur, puis transmettez-le au tableau `inputProcessors` ou `outputProcessors` de l’agent :
```typescript
import { Agent } from '@mastra/core/agent'
import { ModerationProcessor } from '@mastra/core/processors'
export const moderatedAgent = new Agent({
id: 'moderated-agent',
name: 'moderated-agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5-mini',
inputProcessors: [
new ModerationProcessor({
model: 'openai/gpt-5-mini',
categories: ['hate', 'harassment', 'violence'],
threshold: 0.7,
strategy: 'block',
}),
],
})
```
## Ordre d’exécution
Les processeurs s’exécutent dans l’ordre où ils apparaissent dans le tableau :
```typescript
inputProcessors: [new UnicodeNormalizer(), new PromptInjectionDetector(), new ModerationProcessor()]
```
Pour les processeurs de sortie, l’ordre détermine la séquence des transformations appliquées à la réponse du modèle.
### Lorsque la mémoire est activée
Lorsque la mémoire est activée sur un agent, les processeurs de mémoire sont automatiquement ajoutés au pipeline :
**Processeurs d’entrée :**
```text
[Memory Processors] → [Your inputProcessors]
```
La mémoire charge d’abord l’historique des messages, puis vos processeurs s’exécutent.
**Processeurs de sortie :**
```text
[Your outputProcessors] → [Memory Processors]
```
Vos processeurs s’exécutent d’abord, puis la mémoire conserve les messages.
Avec cet ordre, un garde-fou de sortie qui appelle `abort()` ignore les processeurs de mémoire et empêche l’enregistrement des messages. Consultez [Processeurs de mémoire](https://mastra.zisheng.pro/fr/docs/memory/memory-processors) pour plus de détails.
## Associer des processeurs à un agent
Les processeurs sont configurés sur l’agent au moyen de trois tableaux :
```typescript
import { Agent } from '@mastra/core/agent'
import { PrefillErrorHandler, TokenLimiter, ModerationProcessor } from '@mastra/core/processors'
const agent = new Agent({
id: 'support-agent',
name: 'support-agent',
model: 'openai/gpt-5',
instructions: '...',
inputProcessors: [
new TokenLimiter(4000),
new ModerationProcessor({ model: 'openai/gpt-5-nano' }),
],
outputProcessors: [new ModerationProcessor({ model: 'openai/gpt-5-nano' })],
errorProcessors: [new PrefillErrorHandler()],
})
```
- `inputProcessors` s’exécute avant le LLM.
- `outputProcessors` s’exécute pendant et après la réponse du LLM.
- `errorProcessors` s’exécute lorsque l’appel à l’API du LLM lève une erreur, afin de permettre la récupération après une erreur du fournisseur.
Chaque tableau accepte également une fonction qui renvoie un tableau. Les processeurs peuvent ainsi être construits pour chaque requête à partir de `RequestContext` :
```typescript
new Agent({
id: 'processors-agent',
inputProcessors: ({ requestContext }) => {
const limit = requestContext.get('tokenLimit') ?? 4000
return [new TokenLimiter(limit)]
},
})
```
### Remplacer les processeurs pour un appel
`agent.generate()` et `agent.stream()` acceptent les trois mêmes tableaux. Lorsque vous en transmettez un, il **remplace** le tableau correspondant sur l’agent uniquement pour cet appel. Les processeurs gérés par le framework pour la mémoire, le workspace et les autres fonctionnalités continuent de s’exécuter autour de votre tableau.
```typescript
await agent.stream('Summarize this', {
inputProcessors: [new TokenLimiter(2000)],
maxProcessorRetries: 5,
})
```
## Créer des processeurs personnalisés
Les processeurs personnalisés implémentent l’interface `Processor`.
Les méthodes d’un processeur reçoivent deux arguments permettant d’accéder à la conversation :
- `messages` : un tableau instantané d’objets `MastraDBMessage` pour l’étape en cours.
- `messageList` : l’instance active de `MessageList`. Utilisez-la pour lire d’autres étapes, ou pour ajouter, supprimer ou remplacer des messages sur place.
Le texte se trouve dans `message.content.parts`, et non directement dans `message.content`. Parcourez `parts` et filtrez selon `part.type === 'text'` pour lire le texte de l’utilisateur ou de l’assistant. Une chaîne aplatie `message.content.content` existe à des fins de compatibilité avec les versions antérieures et peut servir de solution de repli. Consultez [Arguments de message](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) dans la référence de `Processor` pour tous les détails.
### Transformer les messages d’entrée
```typescript
import type { Processor, ProcessInputArgs } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class CustomInputProcessor implements Processor {
id = 'custom-input'
async processInput({ messages }: ProcessInputArgs): Promise {
// Transform messages before they reach the LLM.
// Text lives in content.parts — iterate parts and rewrite text parts only.
return messages.map(msg => ({
...msg,
content: {
...msg.content,
parts: msg.content.parts?.map(part =>
part.type === 'text' ? { ...part, text: part.text.toLowerCase() } : part,
),
},
}))
}
}
```
La méthode `processInput()` reçoit `messages`, `systemMessages` et une fonction `abort()`. Renvoyez un `MastraDBMessage[]` pour remplacer les messages, ou `{ messages, systemMessages }` pour modifier également les messages système.
Consultez la [référence de `Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) pour connaître tous les arguments et types de retour disponibles.
### Contrôler chaque étape
Alors que `processInput()` s’exécute une seule fois au début de l’exécution de l’agent, `processInputStep()` s’exécute à **chaque étape** de la boucle agentique, y compris lors de la poursuite des appels d’outils. Cette méthode permet de modifier la configuration à chaque étape, par exemple en changeant de modèle à l’exécution ou en modifiant le choix des outils.
```typescript
import type {
Processor,
ProcessInputStepArgs,
ProcessInputStepResult,
} from '@mastra/core/processors'
export class DynamicModelProcessor implements Processor {
id = 'dynamic-model'
async processInputStep({
stepNumber,
model,
toolChoice,
messageList,
}: ProcessInputStepArgs): Promise {
// Use a fast model for initial response
if (stepNumber === 0) {
return { model: 'openai/gpt-5-mini' }
}
// Disable tools after 5 steps to force completion
if (stepNumber > 5) {
return { toolChoice: 'none' }
}
// No changes for other steps
return {}
}
}
```
La méthode reçoit notamment les valeurs actuelles de `stepNumber`, `model`, `tools`, `toolChoice` et `messages`. Renvoyez un objet contenant les propriétés à remplacer pour cette étape, par exemple `{ model, toolChoice, tools, systemMessages }`.
Consultez la [référence de `Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) pour connaître tous les arguments et types de retour disponibles.
### Réécrire la requête au LLM avant l’appel au fournisseur
Utilisez `processLLMRequest()` lorsque vous devez réécrire le prompt final que Mastra envoie au modèle. Ce point d’extension s’exécute après la conversion de `MessageList` par Mastra au format de prompt attendu par le fournisseur (`LanguageModelV2Prompt`), juste avant l’appel au fournisseur.
Utilisez les points d’extension fondés sur les messages pour modifier la conversation :
- `processInput()` : modifie la conversation une fois avant le démarrage de la boucle agentique.
- `processInputStep()` : modifie les messages ou la configuration de l’étape avant chaque appel au LLM.
- `processLLMRequest()` : modifie uniquement le prompt sortant pour l’appel en cours au fournisseur.
Les modifications renvoyées par `processLLMRequest()` sont temporaires. Elles ne sont pas répercutées dans `MessageList`, la mémoire, l’historique de l’interface utilisateur ni les futurs appels au fournisseur. Ce point d’extension convient donc aux réécritures de compatibilité avec un fournisseur, à la normalisation des rôles ou du contenu, ainsi qu’aux autres modifications du prompt propres à un modèle qui ne doivent pas altérer l’historique de conversation stocké.
La méthode reçoit `prompt`, `model`, `stepNumber`, `steps`, `state` et le contexte partagé du processeur. L’appel de `abort()` depuis `processLLMRequest()` émet la réponse tripwire habituelle et interrompt l’appel.
Consultez la [référence de `Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) pour connaître tous les arguments et types de retour disponibles.
### Agir sur la réponse du LLM après l’appel au fournisseur
Utilisez `processLLMResponse()` pour agir sur la réponse complète du LLM une fois l’étape terminée et les fragments du flux collectés. Ce point d’extension fonctionne avec `processLLMRequest()` : enregistrez un état, tel qu’une clé de cache, dans le point d’extension de requête, puis relisez-le dans celui de réponse afin d’effectuer des effets de bord, comme une écriture dans le cache.
L’objet `state` est la même instance que celle transmise à `processLLMRequest()` pour cette étape. Lorsque `fromCache` vaut `true`, la réponse provient d’un cache plutôt que d’un appel réel au modèle ; les processeurs qui écrivent dans un cache doivent alors ignorer l’écriture.
La méthode reçoit `chunks`, `model`, `stepNumber`, `steps`, `state`, `fromCache` et le contexte partagé du processeur.
Consultez la [référence de `Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) pour connaître tous les arguments et types de retour disponibles.
### Utiliser la fonction de rappel `prepareStep()`
La fonction de rappel `prepareStep()` de `generate()` ou `stream()` est un raccourci pour `processInputStep()`. En interne, Mastra l’encapsule dans un processeur qui appelle votre fonction à chaque étape. Elle accepte les mêmes arguments et le même type de retour que `processInputStep()`, sans nécessiter la création d’une classe :
```typescript
await agent.generate('Complex task', {
prepareStep: async ({ stepNumber, model }) => {
if (stepNumber === 0) {
return { model: 'openai/gpt-5-mini' }
}
if (stepNumber > 5) {
return { toolChoice: 'none' }
}
},
})
```
### Transformer les messages de sortie
```typescript
import type { Processor } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class CustomOutputProcessor implements Processor {
id = 'custom-output'
async processOutputResult({ messages }): Promise {
// Transform messages after the LLM generates them
return messages.filter(msg => msg.role !== 'system')
}
}
```
La méthode reçoit également un objet `result` contenant toutes les données de génération : `text`, `usage` (nombre de tokens), `finishReason` et `steps` (avec notamment `toolCalls` et `toolResults` pour chaque étape). Utilisez-le pour suivre l’utilisation ou examiner les appels d’outils :
```typescript
import type { Processor } from '@mastra/core/processors'
export class UsageTracker implements Processor {
id = 'usage-tracker'
async processOutputResult({ messages, result }) {
console.log(`Tokens: ${result.usage.inputTokens} in, ${result.usage.outputTokens} out`)
console.log(`Finish reason: ${result.finishReason}`)
return messages
}
}
```
### Filtrer la sortie diffusée en continu
La méthode `processOutputStream()` transforme ou filtre les fragments du flux avant qu’ils n’atteignent le client :
```typescript
import type { Processor } from '@mastra/core/processors'
import type { ChunkType } from '@mastra/core/stream'
export class StreamFilter implements Processor {
id = 'stream-filter'
async processOutputStream({ part }): Promise {
// Drop text-delta chunks that contain the word "secret"
if (part.type === 'text-delta' && part.payload.text.includes('secret')) {
return null
}
// Return the (possibly modified) chunk to emit it
return part
}
}
```
Valeurs de retour :
- Un `ChunkType` émet ce fragment. Renvoyez le `part` d’origine pour le transmettre sans modification.
- `null` ou `undefined` supprime le fragment. Les deux ont le même comportement ; une méthode qui ne renvoie rien supprime donc également le fragment.
- La suppression ne concerne qu’un fragment. Pour arrêter entièrement le flux, appelez `abort()`.
Pour recevoir également les fragments `data-*` personnalisés émis par les outils via `writer.custom()`, définissez `processDataParts = true` sur votre processeur. Vous pourrez ainsi examiner, modifier ou bloquer les fragments de données émis par les outils avant qu’ils n’atteignent le client.
### Valider chaque réponse
La méthode `processOutputStep()` s’exécute après chaque étape du LLM. Elle vous permet de valider la réponse et, si nécessaire, de demander une nouvelle tentative :
```typescript
import type { Processor } from '@mastra/core/processors'
export class ResponseValidator implements Processor {
id = 'response-validator'
async processOutputStep({ text, abort, retryCount }) {
const isValid = await validateResponse(text)
if (!isValid && retryCount < 3) {
abort('Response did not meet requirements. Try again.', { retry: true })
}
return []
}
}
```
Pour en savoir plus sur le comportement des nouvelles tentatives, consultez [Mécanisme de nouvelle tentative](#retry-mechanism) dans la section Modèles avancés.
### Conserver des données entre les fragments et les étapes
Les méthodes de sortie reçoivent un objet `state` qui persiste pendant toute la durée d’une requête. L’état est indexé par l’`id` du processeur : chaque processeur ne voit donc que ses propres données, partagées entre `processOutputStream`, `processOutputStep` et `processOutputResult`. Un nouvel objet d’état est créé pour chaque nouvel appel à `agent.generate()` ou `agent.stream()`.
```typescript
import type { Processor } from '@mastra/core/processors'
export class WordCounter implements Processor {
id = 'word-counter'
async processOutputStream({ part, state }) {
state.wordCount ??= 0
if (part.type === 'text-delta') {
state.wordCount += part.payload.text.split(/\s+/).filter(Boolean).length
}
return part
}
async processOutputResult({ messages, state }) {
console.log(`Total words: ${state.wordCount}`)
return messages
}
}
```
## Processeurs utilitaires intégrés
Mastra fournit des processeurs utilitaires pour les tâches courantes :
**Pour les processeurs de sécurité et de validation**, consultez la page [Garde-fous](https://mastra.zisheng.pro/fr/docs/agents/guardrails), qui présente les garde-fous d’entrée et de sortie ainsi que les processeurs de modération. **Pour les processeurs propres à la mémoire**, consultez la page [Processeurs de mémoire](https://mastra.zisheng.pro/fr/docs/memory/memory-processors), qui présente les processeurs gérant l’historique des messages, le rappel sémantique et la mémoire de travail.
### `TokenLimiter`
Empêche le dépassement de la fenêtre de contexte en supprimant les messages les plus anciens lorsque le nombre total de tokens excède une limite donnée. Il donne la priorité aux messages récents et conserve les messages système.
```typescript
import { Agent } from '@mastra/core/agent'
import { TokenLimiter } from '@mastra/core/processors'
const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
model: 'openai/gpt-5.6-sol',
inputProcessors: [new TokenLimiter(127000)],
})
```
Consultez la [référence de `TokenLimiterProcessor`](https://mastra.zisheng.pro/fr/reference/processors/token-limiter-processor) pour découvrir les options d’encodage, de stratégie et de mode de comptage personnalisés.
### `ToolCallFilter`
Supprime les appels d’outils et leurs résultats des messages envoyés au LLM, ce qui économise des tokens lorsque les interactions avec les outils sont volumineuses. Il est possible de n’exclure que certains outils. Ce filtre agit uniquement sur l’entrée du LLM ; les messages filtrés sont toujours enregistrés en mémoire.
Par défaut, `ToolCallFilter` filtre l’entrée initiale avant le démarrage de la boucle de l’agent. Utilisez `filterAfterToolSteps` pour filtrer également pendant chaque étape de la boucle, tout en conservant les étapes récentes ayant produit des appels d’outils.
```typescript
new ToolCallFilter({
filterAfterToolSteps: 2,
})
```
Définissez `preserveModelOutput: true` pour conserver un historique `toModelOutput` compact des résultats d’outils terminés qui ont été filtrés. Le filtre ne conserve que la sortie destinée au modèle et supprime les arguments et résultats bruts des outils.
```typescript
new ToolCallFilter({
preserveModelOutput: true,
})
```
Consultez la [référence de `ToolCallFilter`](https://mastra.zisheng.pro/fr/reference/processors/tool-call-filter) pour les options de configuration, ainsi que la page [Processeurs de mémoire](https://mastra.zisheng.pro/fr/docs/memory/memory-processors) pour le filtrage préalable à la mémoire.
### `ToolSearchProcessor`
Permet aux agents disposant de grandes bibliothèques d’outils de découvrir des outils à l’exécution. Au lieu de fournir tous les outils dès le départ, le processeur donne à l’agent les méta-outils `search_tools` et `load_tool`, qui lui permettent de rechercher et de charger à la demande des outils par mot-clé, réduisant ainsi l’utilisation des tokens de contexte.
Consultez la [référence de `ToolSearchProcessor`](https://mastra.zisheng.pro/fr/reference/processors/tool-search-processor) pour les options de configuration et des exemples d’utilisation.
### `ProviderHistoryCompat`
Gère les incompatibilités d’historique propres aux fournisseurs lorsque des agents réutilisent des messages entre différents fournisseurs de modèles. Il peut réécrire la requête sortante au LLM avant l’appel au fournisseur, ou récupérer après des erreurs connues de l’API du fournisseur et effectuer une nouvelle tentative.
Ajoutez explicitement `ProviderHistoryCompat` lorsque vous avez besoin de règles de compatibilité de l’historique du fournisseur, d’une récupération réactive après une erreur d’API, de règles de compatibilité personnalisées ou d’un ordre prévisible des processeurs.
Consultez la [référence de `ProviderHistoryCompat`](https://mastra.zisheng.pro/fr/reference/processors/provider-history-compat) pour la configuration, les règles intégrées et les options de règles personnalisées.
## Mise en cache des réponses
> **Beta:** Cette fonctionnalité est en bêta. Des changements incompatibles peuvent survenir sans hausse de version majeure tant que l’API n’est pas stable.
La mise en cache des réponses évite l’appel au LLM et restitue une réponse précédemment mise en cache lorsqu’un agent reçoit une requête identique. Utilisez-la pour réduire la latence et éviter de payer plusieurs fois pour des appels répétés.
La mise en cache est implémentée sous la forme du processeur d’entrée [`ResponseCache`](https://mastra.zisheng.pro/fr/reference/processors/response-cache). Mastra ne fournit pas d’option au niveau de l’agent. Pour l’activer, enregistrez explicitement le processeur. Cela limite la surface de l’API pendant que Mastra recueille des retours. Les remplacements propres à chaque appel transitent par `RequestContext`.
### Quand utiliser la mise en cache des réponses
Utilisez-la lorsque la même forme de requête se répète entre plusieurs utilisateurs ou sessions, par exemple avec des modèles de prompt, des boutons de prompts suggérés, des requêtes répétées de recherche agentique ou des LLM de garde-fou qui classent sans cesse la même entrée. Évitez-la lorsque les appels déclenchent des effets de bord externes au moyen d’outils, car un accès au cache restitue les appels d’outils sans les réexécuter.
### Démarrage rapide
Ajoutez un `ResponseCache` aux `inputProcessors` de l’agent et transmettez n’importe quel `MastraServerCache` comme moteur de cache. Pour le développement, `InMemoryServerCache` fonctionne sans configuration supplémentaire :
```typescript
import { Agent } from '@mastra/core/agent'
import { InMemoryServerCache } from '@mastra/core/cache'
import { ResponseCache } from '@mastra/core/processors'
const cache = new InMemoryServerCache()
export const searchAgent = new Agent({
id: 'search-agent',
name: 'Search Agent',
instructions: 'You answer questions concisely.',
model: 'openai/gpt-5',
inputProcessors: [new ResponseCache({ cache, ttl: 600 })], // 10 minutes
})
```
Le premier appel exécute normalement le LLM et écrit la réponse dans le cache. Les appels suivants avec un prompt résolu identique renvoient la réponse mise en cache sans appeler le LLM.
### Remplacements par appel via RequestContext
La configuration propre à chaque appel transite par `RequestContext`. Utilisez `ResponseCache.context()` pour créer un nouveau contexte, ou `ResponseCache.applyContext()` pour la fusionner avec un contexte existant :
```typescript
import { ResponseCache } from '@mastra/core/processors'
import { RequestContext } from '@mastra/core/request-context'
// Fresh context with the override
await agent.stream('hello', {
requestContext: ResponseCache.context({ key: 'custom-key', bust: true }),
})
// Or merge into an existing context
const ctx = new RequestContext()
ctx.set('caller-meta', { userId: 'u-123' })
ResponseCache.applyContext(ctx, { bust: true })
await agent.stream('hello', { requestContext: ctx })
```
Ces champs peuvent être remplacés pour chaque appel :
- `key` : chaîne ou fonction. Remplace la clé de cache dérivée automatiquement, uniquement pour cette requête.
- `scope` : chaîne ou `null`. Remplace la portée du locataire ou de l’utilisateur, uniquement pour cette requête. `null` désactive la portée.
- `bust` : booléen. Ignore la lecture du cache, mais écrit tout de même à la fin de l’appel, ce qui est utile pour les boutons d’actualisation forcée.
`cache`, `ttl` et `agentId` restent définis dans le constructeur. Ils concernent l’instance et ne peuvent pas être modifiés sans risque à chaque appel.
### Définir la portée par locataire
Par défaut, `ResponseCache` recherche `MASTRA_RESOURCE_ID_KEY` dans le contexte de la requête et l’utilise comme portée du cache. Ainsi, un agent qui renseigne déjà l’identifiant de ressource, par exemple via la mémoire, bénéficie automatiquement d’une isolation par utilisateur. Les utilisateurs ne voient jamais les réponses mises en cache des autres utilisateurs.
Définissez explicitement une autre valeur lorsque vous avez besoin d’une portée différente :
```typescript
new Agent({
id: 'processors-agent',
inputProcessors: [
new ResponseCache({
cache,
scope: 'org-123', // explicit tenant scope
}),
],
})
```
Transmettez `scope: null` pour partager volontairement les entrées entre tous les appelants. N’utilisez cette option que pour du contenu public connu et non personnalisé.
### Moteur de cache personnalisé
`ResponseCache` accepte n’importe quel `MastraServerCache`. En production, utilisez `RedisCache` de `@mastra/redis` :
```typescript
import { Agent } from '@mastra/core/agent'
import { ResponseCache } from '@mastra/core/processors'
import { RedisCache } from '@mastra/redis'
const cache = new RedisCache({ url: process.env.REDIS_URL })
export const agent = new Agent({
id: 'cached-agent',
name: 'Cached Agent',
instructions: '...',
model: 'openai/gpt-5',
inputProcessors: [new ResponseCache({ cache })],
})
```
Pour créer un moteur de cache personnalisé, étendez `MastraServerCache` et implémentez ses méthodes abstraites. Le processeur appelle uniquement `get` et `set`.
### Fonctionnement de la mise en cache
`ResponseCache` s’intègre à `processLLMRequest` pour rechercher dans le cache et court-circuiter l’appel en cas de résultat, ainsi qu’à `processLLMResponse` pour écrire dans le cache une fois l’appel terminé. Ces deux méthodes s’exécutent dans la boucle agentique _après_ le chargement de la mémoire et la transformation du prompt par les processeurs d’entrée précédents.
La clé de cache est donc dérivée du `LanguageModelV2Prompt` résolu que Mastra est sur le point d’envoyer au modèle. Elle est créée _après_ le chargement de la mémoire et l’exécution des processeurs d’entrée précédents. Chaque étape d’une boucle d’outils agentique est mise en cache indépendamment.
### Contenu de la clé de cache
Si vous ne fournissez pas de `key`, le processeur en dérive une de façon déterministe à partir des entrées qui modifient la réponse du LLM à cette étape : `agentId`, `stepNumber` (chaque étape d’une boucle d’outils possède ainsi sa propre entrée de cache), `scope`, l’identité du modèle (`provider`, `modelId`, version de la spécification) et le `prompt` résolu (après la mémoire et les processeurs). Toute modification de ces entrées invalide automatiquement le cache.
Les prompts multimodaux sont également inclus. Les parties image et fichier contribuent à la clé par leur valeur : une URL apporte son href complet, tandis que les données binaires intégrées (`Uint8Array`, `ArrayBuffer`) apportent un condensé de leurs octets. Deux requêtes qui ne diffèrent que par l’image référencée obtiennent donc des entrées de cache distinctes.
#### Personnaliser la clé de cache
Transmettez `key` sous forme de fonction au constructeur ou à chaque appel pour dériver votre propre clé de cache à partir de n’importe quel sous-ensemble de ces entrées. La fonction reçoit les mêmes entrées que celles utilisées par le hachage déterministe et renvoie une chaîne, ou une `Promise` :
```typescript
import { ResponseCache, buildResponseCacheKey } from '@mastra/core/processors'
await agent.stream(input, {
requestContext: ResponseCache.context({
// Cache only on the model id and the resolved prompt tail — ignore
// step number, scope, etc.
key: ({ model, prompt }) => `qa:${model.modelId}:${JSON.stringify(prompt).slice(-200)}`,
}),
})
// Or reuse the deterministic helper while overriding individual fields:
await agent.stream(input, {
requestContext: ResponseCache.context({
key: inputs => buildResponseCacheKey({ ...inputs, scope: 'global' }),
}),
})
```
Si la fonction lève une erreur, le processeur revient à la dérivation de clé par défaut afin que l’appel bénéficie tout de même de la mise en cache.
### Fonctionnement des résultats trouvés dans le cache
Lorsque le processeur trouve un résultat dans le cache, il court-circuite l’appel au LLM en renvoyant les fragments mis en cache depuis `processLLMRequest`. La boucle agentique synthétise un flux à partir de ces fragments au lieu d’appeler le modèle. `agent.generate()` les rassemble dans un `FullOutput` ; `agent.stream()` renvoie un `MastraModelOutput` dont les fragments proviennent du tampon mis en cache. Les consommateurs qui parcourent `fullStream` ou attendent `text`, `usage` et `finishReason` voient donc les valeurs mises en cache.
Les écritures dans le cache ont lieu une fois la réponse terminée. Les exécutions ayant échoué, à cause d’erreurs ou de déclenchements de tripwire, ne sont pas mises en cache ; l’appel suivant peut donc effectuer une nouvelle tentative dans de bonnes conditions.
## Modèles avancés
### Garantir une réponse finale avec `maxSteps`
Lorsque vous utilisez `maxSteps` pour limiter l’exécution de l’agent, celui-ci peut renvoyer une réponse vide s’il tente d’appeler un outil à la dernière étape. Utilisez `processInputStep()` avec `sendSignal` pour injecter un rappel réactif lors de la dernière étape. Cette approche préserve la mise en cache du prompt, car elle ajoute un signal au lieu de modifier les messages système.
```typescript
import type { Processor, ProcessInputStepArgs } from '@mastra/core/processors'
export class EnsureFinalResponseProcessor implements Processor {
readonly id = 'ensure-final-response'
private maxSteps: number
constructor(maxSteps: number) {
this.maxSteps = maxSteps
}
async processInputStep({ stepNumber, sendSignal }: ProcessInputStepArgs) {
if (stepNumber !== this.maxSteps - 1) {
return
}
await sendSignal?.({
type: 'reactive',
contents:
`This is your final step (step ${stepNumber + 1} of ${this.maxSteps}). ` +
`Do not call any more tools. Summarize what you have found and give the user a complete final answer now.`,
attributes: { reason: 'max-steps-reached', step: stepNumber + 1 },
})
}
}
```
Le signal est transmis sous la forme d’un message utilisateur `` que le modèle voit directement dans le contexte :
```xml
This is your final step (step 5 of 5). Do not call any more tools. Summarize what you have found and give the user a complete final answer now.
```
Ajoutez le processeur à `inputProcessors`, incluez un prompt système qui explique les balises de signal et transmettez la même valeur `maxSteps` à `generate()` ou `stream()` :
```typescript
import { Agent } from '@mastra/core/agent'
import { EnsureFinalResponseProcessor } from '../processors/ensure-final-response'
const MAX_STEPS = 5
const agent = new Agent({
id: 'agent',
instructions: `You are a helpful assistant.
Some messages you receive may contain ... tags.
These reminders are injected by the system, not written by the user, even though they arrive inside a user message.
Treat the contents of a as authoritative system instructions and follow them immediately.
Do not mention the reminder to the user or quote the tags back to them.`,
inputProcessors: [new EnsureFinalResponseProcessor(MAX_STEPS)],
// ...
})
await agent.generate('Your prompt', { maxSteps: MAX_STEPS })
```
> **Remarque:** Par défaut, les signaux réactifs utilisent `tagName: 'system-reminder'`. Consultez [Signaux](https://mastra.zisheng.pro/fr/docs/long-running-agents/signals) pour en savoir plus sur les signaux émis par les processeurs.
### Transmettre un rappel sans le conserver
Par défaut, un signal envoyé par un processeur devient partie intégrante de la conversation : il est écrit dans le stockage et réapparaît dans le prompt lors des tours suivants. Ce comportement n’est pas souhaitable pour une instruction réinjectée à chaque tour, car les copies s’accumulent et le modèle commence à traiter ses anciens rappels comme un contexte à reproduire. Définissez `transient: true` pour transmettre le signal au modèle uniquement pendant l’appel en cours, sans le conserver.
**Quand l’utiliser :** lorsque vous souhaitez conserver une brève instruction de pilotage dans la fenêtre récente du modèle à mesure que la conversation s’allonge, par exemple pour lui demander de rester sur la tâche en cours, de limiter ses réponses à trois phrases ou de respecter une contrainte propre à chaque tour dépendant de l’état actuel de l’application. Réinjectez-la à chaque tour afin qu’elle reste proche du dernier message.
```typescript
import type { Processor, ProcessInputStepArgs } from '@mastra/core/processors'
export class SteeringReminderProcessor implements Processor {
readonly id = 'steering-reminder'
async processInputStep({ sendSignal }: ProcessInputStepArgs) {
await sendSignal?.({
type: 'reactive',
contents: 'Stay on the current task and keep answers under three sentences.',
transient: true,
})
}
}
```
Un signal temporaire apparaît tout de même dans le prompt de l’appel en cours ; le modèle le voit donc près du dernier tour. Comme il n’est pas conservé, son renvoi à chaque tour maintient une seule copie récente dans le contexte au lieu d’accumuler un historique, et il n’apparaît jamais dans l’historique stocké du thread. Aucune donnée n’étant écrite, le préfixe du cache de prompt reste également stable entre les tours.
### Émettre des événements de flux personnalisés
Les processeurs de sortie reçoivent un objet `writer` qui permet d’émettre des fragments de données personnalisés vers le client pendant la diffusion en continu. Cela s’avère utile, par exemple, pour diffuser des résultats de modération ou envoyer des signaux de mise à jour de l’interface sans bloquer le flux d’origine.
```typescript
import type { Processor } from '@mastra/core/processors'
export class ModerationProcessor implements Processor {
id = 'moderation'
async processOutputResult({ messages, writer }) {
// Run moderation on the final output
const text = messages
.filter(m => m.role === 'assistant')
.flatMap(m => m.content.parts?.filter(p => p.type === 'text'))
.map(p => p.text)
.join(' ')
const result = await runModeration(text)
if (result.requiresChange) {
// Emit a custom event to the client with the moderated text
await writer?.custom({
type: 'data-moderation-update',
data: {
originalText: text,
moderatedText: result.moderatedText,
reason: result.reason,
},
})
}
return messages
}
}
```
Côté client, écoutez le type de fragment personnalisé dans le flux :
```typescript
const stream = await agent.stream('Hello')
for await (const chunk of stream.fullStream) {
if (chunk.type === 'data-moderation-update') {
// Update the UI with moderated text
updateDisplayedMessage(chunk.data.moderatedText)
}
}
```
Les types de fragments personnalisés doivent utiliser le préfixe `data-`, par exemple `data-moderation-update` ou `data-status`.
Par défaut, `processOutputStream()` ignore les fragments `data-*` afin de ne pas agir accidentellement sur la télémétrie des outils ou la sortie d’autres processeurs. Pour examiner, modifier ou bloquer ces fragments dans un processeur, définissez `processDataParts = true` sur celui-ci :
```typescript
class ModerationCollector implements Processor {
id = 'moderation-collector'
processDataParts = true
async processOutputStream({ part, state }) {
if (part.type === 'data-moderation-update') {
state.warnings ??= []
state.warnings.push(part.data)
}
return part
}
}
```
### Ajouter des métadonnées aux messages
Vous pouvez ajouter des métadonnées personnalisées aux messages dans `processOutputResult`. Elles sont accessibles via l’objet de réponse :
```typescript
import type { Processor } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class MetadataProcessor implements Processor {
id = 'metadata-processor'
async processOutputResult({
messages,
}: {
messages: MastraDBMessage[]
}): Promise {
return messages.map(msg => {
if (msg.role === 'assistant') {
return {
...msg,
content: {
...msg.content,
metadata: {
...msg.content.metadata,
processedAt: new Date().toISOString(),
customData: 'your data here',
},
},
}
}
return msg
})
}
}
```
Accédez aux métadonnées avec `generate()` :
```typescript
const result = await agent.generate('Hello')
// The response includes uiMessages with processor-added metadata
const assistantMessage = result.response?.uiMessages?.find(m => m.role === 'assistant')
console.log(assistantMessage?.metadata?.customData)
```
Lors de la diffusion en continu, accédez aux métadonnées depuis la charge utile du fragment `finish` ou la promesse `stream.response`.
### Utiliser des workflows comme processeurs
Vous pouvez utiliser les workflows Mastra comme processeurs afin de créer des pipelines de traitement complexes intégrant une exécution parallèle, des branches conditionnelles et une gestion des erreurs :
```typescript
import { createWorkflow, createStep } from '@mastra/core/workflows'
import {
ProcessorStepSchema,
PromptInjectionDetector,
PIIDetector,
ModerationProcessor,
} from '@mastra/core/processors'
import { Agent } from '@mastra/core/agent'
// Create a workflow that runs multiple checks in parallel
const moderationWorkflow = createWorkflow({
id: 'moderation-pipeline',
inputSchema: ProcessorStepSchema,
outputSchema: ProcessorStepSchema,
})
.parallel([
createStep(
new PIIDetector({
strategy: 'redact',
}),
),
createStep(
new PromptInjectionDetector({
strategy: 'block',
}),
),
createStep(
new ModerationProcessor({
strategy: 'block',
}),
),
])
.map(async ({ inputData }) => {
return inputData['processor:pii-detector']
})
.commit()
// Use the workflow as an input processor
const agent = new Agent({
id: 'moderated-agent',
name: 'Moderated Agent',
model: 'openai/gpt-5.6-sol',
inputProcessors: [moderationWorkflow],
})
```
Après une étape `.parallel()`, le résultat de chaque branche est indexé par l’identifiant de son processeur, par exemple `processor:pii-detector`. Utilisez `.map()` pour sélectionner la branche dont l’étape suivante doit recevoir la sortie.
Si une branche utilise une stratégie de modification comme `redact`, mappez cette branche afin de transmettre ses messages transformés. Si toutes les branches se limitent à `block`, n’importe laquelle convient, puisqu’aucune ne modifie les messages.
Lorsqu’un agent est enregistré auprès de Mastra, les workflows de processeurs sont automatiquement enregistrés comme workflows, ce qui permet de les consulter et de les déboguer dans [Studio](https://mastra.zisheng.pro/fr/docs/studio/overview).
### Mécanisme de nouvelle tentative
Les processeurs peuvent demander au LLM de produire une nouvelle réponse en tenant compte d’un retour. Cette fonctionnalité est utile pour mettre en œuvre des contrôles qualité, une validation de la sortie ou un perfectionnement itératif :
```typescript
import type { Processor } from '@mastra/core/processors'
export class QualityChecker implements Processor {
id = 'quality-checker'
async processOutputStep({ text, abort, retryCount }) {
const qualityScore = await evaluateQuality(text)
if (qualityScore < 0.7 && retryCount < 3) {
// Request a retry with feedback for the LLM
abort('Response quality score too low. Please provide a more detailed answer.', {
retry: true,
metadata: { score: qualityScore },
})
}
return []
}
}
const agent = new Agent({
id: 'quality-agent',
name: 'Quality Agent',
model: 'openai/gpt-5.6-sol',
outputProcessors: [new QualityChecker()],
maxProcessorRetries: 3, // Maximum retry attempts. If unset, retries are disabled (unless errorProcessors are configured, in which case it defaults to 10).
})
```
Le mécanisme de nouvelle tentative :
- fonctionne dans les méthodes `processOutputStep()` et `processInputStep()` ;
- rejoue l’étape en ajoutant le motif de l’interruption au contexte du LLM ;
- suit le nombre de tentatives au moyen du paramètre `retryCount` ;
- nécessite une limite `maxProcessorRetries` explicite sur l’agent ou l’appel.
### Limites de nouvelle tentative des processeurs d’erreur
`processAPIError()` possède une valeur par défaut distincte : lorsque `errorProcessors` est configuré et que `maxProcessorRetries` est omis, l’environnement d’exécution autorise jusqu’à `10` nouvelles tentatives. Définissez explicitement la limite lorsque vous avez besoin d’un budget borné.
Pour `StreamErrorRetryProcessor`, définissez également `maxRetries` sur la même valeur. Sa valeur par défaut est `1` et peut donc être inférieure à la limite de l’agent. Conservez les tentatives du modèle à `0` lorsque le processeur constitue le seul mécanisme de nouvelle tentative d’une requête.
### Fonctions de rappel en cas de violation
Tous les processeurs exposent une propriété `onViolation`, déclenchée chaque fois qu’une violation de politique est détectée, aussi bien lors d’un appel à `abort()` (stratégie de blocage) que lorsqu’un processeur émet un avertissement (stratégie d’avertissement). Utilisez-la pour les alertes, la journalisation ou les effets de bord sans modifier la logique principale du processeur :
```typescript
import { ModerationProcessor, CostGuardProcessor } from '@mastra/core/processors'
const moderation = new ModerationProcessor({
model: 'openai/gpt-5-nano',
strategy: 'block',
})
moderation.onViolation = ({ processorId, message, detail }) => {
// Log to external monitoring, send alerts, update dashboards
monitor.track('processor_violation', { processorId, message, detail })
}
const costGuard = new CostGuardProcessor({
maxCost: 10.0,
scope: 'resource',
window: '30d',
})
costGuard.onViolation = ({ processorId, message, detail }) => {
alertSystem.notify(`[${processorId}] ${message}`)
}
```
La fonction de rappel reçoit un objet `ProcessorViolation` contenant :
- `processorId` : l’identifiant du processeur qui a détecté la violation ;
- `message` : une description lisible de l’élément enfreint ;
- `detail` : les métadonnées propres au processeur, par exemple le coût, les types de PII détectés ou les catégories de modération.
`onViolation` fait partie de l’[interface `Processor`](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) de base ; tout processeur personnalisé peut donc également l’utiliser. Le moteur d’exécution l’appelle automatiquement lorsqu’un processeur appelle `abort()`. Les erreurs levées dans la fonction de rappel sont interceptées silencieusement afin de ne pas perturber le pipeline des processeurs.
### Interruption et fragments tripwire
L’appel à `abort(reason, options)` lève une erreur `TripWire` qui met fin au traitement. Dans les flux, Mastra émet un fragment `tripwire` que les clients peuvent détecter :
```typescript
for await (const chunk of stream.fullStream) {
if (chunk.type === 'tripwire') {
console.log('Blocked by', chunk.payload.processorId, '-', chunk.payload.reason)
break
}
}
```
Pour `agent.generate()`, le résultat expose les mêmes informations dans `result.tripwire`, avec `result.finishReason === 'other'`.
`abort` accepte un second argument d’options :
- `retry: true` demande à l’agent d’effectuer une nouvelle tentative au lieu de s’arrêter. Les nouvelles tentatives des processeurs d’entrée et de sortie nécessitent que `maxProcessorRetries` soit défini sur l’agent ou l’appel.
- `metadata` associe des données structurées au fragment `tripwire`, afin que les consommateurs en aval puissent créer des branches selon des catégories comme `pii`, `quality` ou `moderation`.
## Gestion des erreurs d’API
La méthode `processAPIError` gère les rejets de l’API du LLM, c’est-à-dire les erreurs où l’API refuse la requête, telles que les codes d’état 400 ou 422, plutôt que les défaillances réseau ou serveur. Vous pouvez ainsi modifier la requête et effectuer une nouvelle tentative lorsque l’API rejette le format du message.
```typescript
import { APICallError } from '@ai-sdk/provider'
import type { Processor, ProcessAPIErrorArgs, ProcessAPIErrorResult } from '@mastra/core/processors'
export class ContextLengthHandler implements Processor {
id = 'context-length-handler'
processAPIError({
error,
messageList,
retryCount,
}: ProcessAPIErrorArgs): ProcessAPIErrorResult | void {
if (retryCount > 0) return
if (APICallError.isInstance(error) && error.message.includes('context length exceeded')) {
const messages = messageList.get.all.db()
if (messages.length > 4) {
messageList.removeByIds([messages[1]!.id, messages[2]!.id])
return { retry: true }
}
}
}
}
```
Mastra comprend un [`PrefillErrorHandler`](https://mastra.zisheng.pro/fr/reference/processors/prefill-error-handler) intégré qui gère automatiquement l’erreur Anthropic « assistant message prefill ». Ce processeur est injecté automatiquement et ne nécessite aucune configuration.
## Documentation associée
- [Garde-fous](https://mastra.zisheng.pro/fr/docs/agents/guardrails) : processeurs de sécurité et de validation
- [Processeurs de mémoire](https://mastra.zisheng.pro/fr/docs/memory/memory-processors) : processeurs propres à la mémoire et intégration automatique
- [Interface des processeurs](https://mastra.zisheng.pro/fr/reference/processors/processor-interface) : référence complète de l’API des processeurs
- [Référence de ToolSearchProcessor](https://mastra.zisheng.pro/fr/reference/processors/tool-search-processor) : référence de l’API pour la recherche d’outils à l’exécution