Observational Memory
Ajouté dans : @mastra/memory@1.1.0
Observational Memory (OM) est le système de mémoire agentique à contexte long de Mastra. Un Observer surveille les conversations et crée des observations. Un Reflector restructure ces observations en combinant les éléments associés et en condensant les tendances générales. Ensemble, ils maintiennent un journal d’observations qui remplace progressivement l’historique brut des messages.
Exemple d’utilisationLien direct vers Exemple d’utilisation
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: true,
},
}),
})
ConfigurationLien direct vers Configuration
L’option observationalMemory accepte true, un objet de configuration ou false. La valeur true active OM avec google/gemini-2.5-flash comme modèle par défaut. Lorsque vous transmettez un objet de configuration, définissez model au premier niveau ou dans observation.model et/ou reflection.model ; si tous les champs de modèle sont omis, OM utilise google/gemini-2.5-flash comme solution de repli.
L’entrée de l’Observer prend en charge le multimodal. OM conserve des espaces réservés textuels tels que [Image #1: screenshot.png] dans la transcription créée pour l’Observer et envoie également les parties d’image sous-jacentes lorsque cela est possible. Ce comportement s’applique à l’observation d’un seul thread comme à l’observation par lots de plusieurs threads. Les fichiers qui ne sont pas des images apparaissent uniquement sous forme d’espaces réservés.
OM applique les seuils au moyen d’une estimation locale rapide des tokens. Le texte utilise tokenx, tandis que les entrées de type image utilisent des heuristiques adaptées au Provider et des solutions de repli déterministes lorsque les métadonnées sont incomplètes.
enabled?:
true. Seul enabled: false la désactive explicitement.model?:
observation.model ou reflection.model ; une erreur est levée si les deux sont définis. Lorsque cette option et observation.model/reflection.model sont toutes omises, OM utilise google/gemini-2.5-flash comme solution de repli. Utilisez "default" pour employer explicitement le modèle par défaut (google/gemini-2.5-flash).scope?:
'thread' conserve les observations par thread. 'resource' (expérimental) partage les observations entre tous les threads d’une ressource, ce qui permet une mémoire interconversationnelle.activateAfterIdle?:
observation.messageTokens. Accepte une valeur numérique en millisecondes telle que 300_000, des chaînes de durée comme "5m" ou "1hr", "auto" pour une durée de vie du cache de prompts adaptée au Provider, ou false pour désactiver l’activation après inactivité héritée par les observations. Les réflexions n’héritent pas de ce paramètre. Utilisez reflection.activateAfterIdle pour activer ce comportement pour les réflexions.activateOnProviderChange?:
reflection.activateOnProviderChange pour activer ce comportement pour les réflexions.temporalMarkers?:
retrieval?:
recall est enregistré afin que l’Agent puisse les parcourir. true active par défaut la navigation entre les threads. { vector: true } active également la recherche sémantique au moyen du stockage vectoriel et de l’Embedder de Memory. { scope: 'thread' } limite le Tool de rappel au thread actuel. La portée par défaut est 'resource'. { instructions: '...' } ajoute des consignes de rappel propres à l’application après les instructions de récupération intégrées de Mastra.hooks?:
observe()/reflect(), l’observation synchrone pilotée par les tours et la mise en mémoire tampon asynchrone sans attente. Les callbacks reçoivent le contexte d’appel threadId/resourceId/trigger ('manual' | 'turn-sync' | 'async-buffer'), et les hooks de fin (onObservationEnd/onReflectionEnd) reçoivent en plus l’usage de tokens et les providerMetadata de l’appel au modèle OM, où des Providers tels que l’AI Gateway indiquent le coût de chaque appel. Les applications peuvent ainsi comptabiliser les dépenses du modèle OM sans encapsuler les modèles Observer/Reflector dans un middleware. Les cycles asynchrones mis en mémoire tampon qui échouent ne lèvent jamais d’erreur ; ils la signalent dans le champ error du hook de fin. Les erreurs levées par ces hooks sont interceptées et journalisées ; elles ne font jamais échouer le cycle.observation?:
model?:
model de premier niveau est également fourni. Si ni cette option ni le model de premier niveau ne sont définis, utilise reflection.model comme solution de repli.instruction?:
threadTitle?:
true, l’Observer suggère des titres de thread courts et met à jour le titre lorsque le sujet de la conversation change de manière significative. Cette fonctionnalité doit être activée explicitement et est désactivée par défaut.extract?:
manageWorkingMemory?:
WorkingMemoryExtractor, définit par défaut workingMemory.agentManaged sur false et workingMemory.useStateSignals sur true. Consultez la section Mises à jour de la mémoire de travail.observeAttachments?:
true (valeur par défaut) transmet toutes les pièces jointes. false les retire toutes tout en conservant les espaces réservés visibles. 'auto' utilise le registre des fonctionnalités des Providers : les pièces jointes sont transmises lorsque le modèle Observer prend en charge les entrées multimodales, retirées dans le cas contraire, et transmises si aucune donnée de fonctionnalité n’est disponible. Un tableau constitue une liste d’autorisation mimeType insensible à la casse prenant en charge les correspondances exactes ('application/pdf'), les sous-types génériques ('image/*') et '*' seul pour tout autoriser. Cette option est utile lorsque le modèle Observer accepte uniquement du texte, par exemple certains endpoints DeepSeek, tandis que l’Agent principal utilise un modèle multimodal. Les pièces jointes issues des résultats de Tool sont filtrées selon la même règle.messageTokens?:
tokenx. Les parties d’image sont incluses au moyen d’heuristiques adaptées au modèle lorsque cela est possible, avec des solutions de repli déterministes si leurs métadonnées sont incomplètes. Les parties file de type image sont comptées de la même manière lorsque les téléversements sont normalisés comme fichiers.maxTokensPerBatch?:
modelSettings?:
maxOutputTokens: 100_000 ne s’applique qu’avec la sélection de modèle par défaut (aucun modèle défini, "default" ou un sélecteur ModelByInputTokens). Les modèles personnalisés ne reçoivent aucune valeur par défaut pour maxOutputTokens.temperature?:
maxOutputTokens?:
100000 ne s’applique qu’avec la sélection de modèle par défaut ; les modèles personnalisés ne reçoivent aucune valeur par défaut.providerOptions?:
bufferTokens?:
0 et 1 sont des fractions de messageTokens : 0.25 met en mémoire tampon tous les 25 % du seuil (7,5 k tokens avec la valeur par défaut de 30 k). Les valeurs supérieures ou égales à 1 sont des nombres absolus de tokens : 5000 effectue une mise en mémoire tampon tous les 5 k tokens. Les observations sont stockées jusqu’à atteindre le seuil messageTokens, puis s’activent instantanément sans appel LLM bloquant. La valeur résolue doit être inférieure à messageTokens. Définissez false pour désactiver toute mise en mémoire tampon asynchrone (observation et réflexion).bufferOnIdle?:
bufferTokens, qui contrôle la mise en mémoire tampon asynchrone pendant les étapes. Définissez true pour mettre en mémoire tampon les tours inactifs courts sans attendre le tour suivant ni le seuil messageTokens.bufferActivation?:
0 et 1 représentent la fraction de messageTokens à supprimer : 0.8 retire environ 80 % de l’historique et en conserve environ 20 % (6 k tokens avec la valeur par défaut de 30 k). Les valeurs supérieures ou égales à 1000 indiquent le nombre de tokens à conserver : 4000 conserve environ 4 k tokens après l’activation. Le sens s’inverse : un ratio plus élevé supprime davantage d’historique, tandis qu’un nombre de tokens plus élevé en conserve davantage.activateAfterIdle?:
"auto" pour une durée de vie du cache de prompts adaptée au Provider, ou false. Si cette option n’est pas définie, les observations utilisent la valeur activateAfterIdle de premier niveau. Définissez false pour désactiver ce paramètre de premier niveau pour les observations. S’applique actuellement uniquement à la classe ObservationalMemory autonome ; new Memory(...) applique seulement la valeur activateAfterIdle de premier niveau.activateOnProviderChange?:
activateOnProviderChange de premier niveau. S’applique actuellement uniquement à la classe ObservationalMemory autonome ; new Memory(...) applique seulement la valeur activateOnProviderChange de premier niveau.blockAfter?:
1 à moins de 100 sont des multiplicateurs de messageTokens : 1.2 force une observation bloquante à 120 % du seuil (36 k tokens avec la valeur par défaut de 30 k). Les valeurs supérieures ou égales à 100 sont des nombres absolus de tokens et doivent dépasser messageTokens. Entre messageTokens et blockAfter, seules la mise en mémoire tampon asynchrone et l’activation s’exécutent ; l’activation conserve toujours un contexte minimal (la plus petite valeur entre 1 000 tokens et le plancher de rétention). Ne s’applique que lorsque bufferTokens est défini. Utilise par défaut 1.2 lorsque la mise en mémoire tampon asynchrone est activée.previousObserverTokens?:
0 pour omettre entièrement les observations précédentes, ou false pour désactiver explicitement la troncature.reflection?:
model?:
model de premier niveau est également fourni. Si ni cette option ni le model de premier niveau ne sont définis, utilise observation.model comme solution de repli.instruction?:
extract?:
observationTokens?:
modelSettings?:
maxOutputTokens: 100_000 ne s’applique qu’avec la sélection de modèle par défaut (aucun modèle défini, "default" ou un sélecteur ModelByInputTokens). Les modèles personnalisés ne reçoivent aucune valeur par défaut pour maxOutputTokens.temperature?:
maxOutputTokens?:
100000 ne s’applique qu’avec la sélection de modèle par défaut ; les modèles personnalisés ne reçoivent aucune valeur par défaut.providerOptions?:
bufferActivation?:
observationTokens : 0.5 lance la réflexion lorsque les observations atteignent 50 % du seuil (20 k tokens avec la valeur par défaut de 40 k). Lorsque le seuil complet est atteint, la réflexion mise en mémoire tampon remplace les observations qu’elle couvre tout en conservant les nouvelles observations ajoutées après cette plage.activateAfterIdle?:
"auto" pour une durée de vie du cache de prompts adaptée au Provider, ou false. Les réflexions n’héritent pas de la valeur activateAfterIdle de premier niveau ; définissez explicitement cette option pour activer ce comportement. S’applique actuellement uniquement à la classe ObservationalMemory autonome ; ce paramètre est sans effet avec new Memory(...).activateOnProviderChange?:
activateOnProviderChange de premier niveau ; définissez explicitement cette option pour activer ce comportement. S’applique actuellement uniquement à la classe ObservationalMemory autonome ; ce paramètre est sans effet avec new Memory(...).blockAfter?:
1 à moins de 100 sont des multiplicateurs de observationTokens : 1.2 force une réflexion bloquante à 120 % du seuil (48 k tokens avec la valeur par défaut de 40 k). Les valeurs supérieures ou égales à 100 sont des nombres absolus de tokens et doivent dépasser observationTokens. Entre observationTokens et blockAfter, seules la mise en mémoire tampon asynchrone et l’activation s’exécutent. Ne s’applique que lorsque bufferActivation est défini. Utilise par défaut 1.2 lorsque la réflexion asynchrone est activée.Cache des métadonnées d’estimation des tokensLien direct vers Cache des métadonnées d’estimation des tokens
OM persiste les estimations de tokens des charges utiles afin que les comptages répétés puissent réutiliser les estimations précédentes.
- Cache au niveau des parties :
part.providerMetadata.mastra. - Cache de repli pour le contenu textuel : métadonnées au niveau du message lorsqu’aucune partie n’existe.
- Les entrées de cache sont ignorées et recalculées si la version du cache ou la source du tokenizer ne correspond pas.
- Le surcoût propre à chaque message et à chaque conversation est toujours recalculé à l’exécution et n’est pas mis en cache.
- Les parties
data-*etreasoningsont ignorées et ne reçoivent aucune entrée de cache.
API ExtractorLien direct vers API Extractor
Extractor définit une valeur qu’OM doit extraire pendant l’observation ou la réflexion. Les valeurs OM intégrées telles que current-task, suggested-response et thread-title utilisent le même pipeline d’extraction que les valeurs personnalisées.
import { Memory, Extractor } from '@mastra/memory'
import { z } from 'zod'
const memory = new Memory({
options: {
observationalMemory: {
model: 'openai/gpt-5-mini',
observation: {
extract: [
new Extractor({
name: 'User profile',
instructions: 'Extract stable user profile facts that should be remembered.',
schema: z.object({
name: z.string().optional(),
timezone: z.string().optional(),
}),
}),
],
},
},
},
})
name:
slug:
name ; il ne s’agit pas d’une option du constructeur. Identifiant stable généré pour les valeurs persistées et les tags XML. Les slugs utilisent des lettres minuscules, des chiffres et des traits d’union. Les extracteurs personnalisés ne peuvent pas utiliser les slugs intégrés ni les tags XML réservés.instructions:
schema?:
includePreviousExtraction?:
false pour les valeurs qui doivent provenir uniquement de l’exécution OM actuelle.metadataKeyPath?:
false pour ignorer entièrement la persistance des métadonnées OM.onExtracted?:
Comportement de l’extractionLien direct vers Comportement de l’extraction
- Les valeurs extraites sont stockées dans les métadonnées OM du thread sous
om.extracted. - Les valeurs des extracteurs intégrés sont également reproduites dans les champs de métadonnées de compatibilité
currentTask,suggestedResponseetthreadTitle. thread-titlemet à jour le titre du thread uniquement lorsqueobservation.threadTitleest activé.observation.extracts’exécute pendant l’observation.reflection.extracts’exécute pendant la réflexion.- Les extracteurs avec schéma ajoutent une requête de sortie structurée ultérieure.
- Les extracteurs sans schéma sont des extracteurs de chaîne en ligne émis directement dans la sortie de l’Observer ou du Reflector.
- Les fonctions d’extraction dynamiques reçoivent le contexte d’exécution, notamment
source,threadId,resourceId,mainAgent,memoryetrequestContextlorsqu’ils sont disponibles. WorkingMemoryExtractorutilise le pipeline d’extraction normal pour mettre à jour la mémoire de travail au moyen de l’instanceMemoryactive. Il utilise l’extraction structurée lorsque la mémoire de travail possède un schéma JSON et ignore la persistance des métadonnées OM, afin de ne pas dupliquer sa charge utile sous les métadonnées extraites OM.observationalMemory.observation.manageWorkingMemoryajouteWorkingMemoryExtractor, définit par défautworkingMemory.agentManagedsurfalseetworkingMemory.useStateSignalssurtruelorsque la mémoire de travail est activée.- Les échecs d’extraction sont signalés dans les données des marqueurs OM et ne suppriment pas les autres valeurs extraites avec succès.
ExemplesLien direct vers Exemples
Mises à jour de la mémoire de travailLien direct vers Mises à jour de la mémoire de travail
Utilisez observationalMemory.observation.manageWorkingMemory lorsqu’OM doit mettre à jour la mémoire de travail.
import { Memory } from '@mastra/memory'
const memory = new Memory({
options: {
workingMemory: {
enabled: true,
},
observationalMemory: {
enabled: true,
observation: {
manageWorkingMemory: true,
},
},
},
})
Définissez workingMemory.agentManaged: true si l’Agent principal doit continuer à recevoir le Tool de mémoire de travail et l’injection d’instructions.
Portée ressource avec seuils personnalisés (expérimental)Lien direct vers Portée ressource avec seuils personnalisés (expérimental)
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
scope: 'resource',
observation: {
messageTokens: 20_000,
},
reflection: {
observationTokens: 60_000,
},
},
},
}),
})
Budget de tokens partagéLien direct vers Budget de tokens partagé
Lorsque shareTokenBudget est activé, le budget total est observation.messageTokens + reflection.observationTokens (100 k dans cet exemple). Si les observations utilisent seulement 30 k tokens, les messages peuvent occuper jusqu’à 70 k tokens. Si les messages sont courts, les observations disposent de plus d’espace avant de déclencher la réflexion.
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: {
shareTokenBudget: true,
observation: {
messageTokens: 20_000,
bufferTokens: false, // required when using shareTokenBudget (temporary limitation)
},
reflection: {
observationTokens: 80_000,
},
},
},
}),
})
Modèle personnaliséLien direct vers Modèle personnalisé
En transmettant un model dans la configuration, vous pouvez utiliser n’importe quel modèle du routeur de modèles Mastra.
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
observationalMemory: {
model: 'openai/gpt-5-mini',
},
},
}),
})
Modèles différents pour chaque AgentLien direct vers Modèles différents pour chaque Agent
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
observationalMemory: {
observation: {
model: 'google/gemini-2.5-flash',
},
reflection: {
model: 'openai/gpt-5-mini',
},
},
},
}),
})
Instructions personnaliséesLien direct vers Instructions personnalisées
Personnalisez les éléments sur lesquels l’Observer et le Reflector se concentrent en fournissant des instructions personnalisées :
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'health-assistant',
name: 'health-assistant',
instructions: 'You are a health and wellness assistant.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
// Focus observations on health-related preferences and goals
instruction:
'Prioritize capturing user health goals, dietary restrictions, exercise preferences, and medical considerations. Avoid capturing general chit-chat.',
},
reflection: {
// Guide reflection to consolidate health patterns
instruction:
'When consolidating, group related health information together. Preserve specific metrics, dates, and medical details.',
},
},
},
}),
})
Mise en mémoire tampon asynchroneLien direct vers Mise en mémoire tampon asynchrone
La mise en mémoire tampon asynchrone est activée par défaut. Elle précalcule les observations en arrière-plan à mesure que la conversation s’allonge : lorsque le seuil messageTokens est atteint, les observations mises en mémoire tampon s’activent instantanément sans appel LLM bloquant.
Le cycle de vie suit le schéma mettre en mémoire tampon → activer → supprimer les messages → répéter. Les appels en arrière-plan de l’Observer s’exécutent aux intervalles bufferTokens et produisent chacun un chunk d’observations. Au seuil, les chunks s’activent : les observations passent dans le journal et les messages bruts sont retirés du contexte. Le seuil blockAfter force une solution de repli synchrone si la mise en mémoire tampon ne suit plus.
Paramètres par défaut :
observation.bufferTokens: 0.2: mise en mémoire tampon tous les 20 % demessageTokens(par exemple, tous les ~6 k tokens avec un seuil de 30 k)observation.bufferActivation: 0.8: lors de l’activation, supprime suffisamment de messages pour ne conserver que 20 % du seuil- Les observations mises en mémoire tampon incluent des indications de continuation (
suggestedResponse,currentTask) qui survivent à l’activation afin de préserver la continuité de la conversation reflection.bufferActivation: 0.5: démarre la réflexion en arrière-plan à 50 % du seuil d’observation
Pour personnaliser ces paramètres :
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
messageTokens: 30_000,
// Buffer every 5k tokens (runs in background)
bufferTokens: 5_000,
// Activate to retain 30% of threshold
bufferActivation: 0.7,
// Force synchronous observation at 1.5x threshold
blockAfter: 1.5,
},
reflection: {
observationTokens: 60_000,
// Start background reflection at 50% of threshold
bufferActivation: 0.5,
// Force synchronous reflection at 1.2x threshold
blockAfter: 1.2,
},
},
},
}),
})
Pour désactiver entièrement la mise en mémoire tampon asynchrone :
observationalMemory: {
model: "google/gemini-2.5-flash",
observation: {
bufferTokens: false,
},
}
Définir bufferTokens: false désactive la mise en mémoire tampon asynchrone de l’observation et de la réflexion. Les observations et réflexions s’exécutent de manière synchrone lorsque leurs seuils sont atteints.
La mise en mémoire tampon asynchrone n’est pas prise en charge avec scope: 'resource' et est automatiquement désactivée dans la portée ressource.
Parties de données du streamingLien direct vers Parties de données du streaming
Observational Memory émet des parties de données typées pendant l’exécution de l’Agent, que les clients peuvent utiliser pour fournir un retour en temps réel dans l’interface utilisateur. Elles sont diffusées avec la réponse de l’Agent.
Lecture des résultats des extracteursLien direct vers Lecture des résultats des extracteurs
Les deux événements de fin transportent la sortie des extracteurs dans leur charge utile data. Les champs des extracteurs sont les suivants :
interface DataOmObservationEndPart {
type: 'data-om-observation-end'
data: {
/** Whether the completed work was an observation or reflection */
operationType: 'observation' | 'reflection'
/** Values extracted during this OM operation, keyed by extractor slug */
extractedValues?: Record<string, unknown>
/** Extractor failures from this OM operation. Successful extractor values are still included */
extractionFailures?: Array<{ slug: string; error: string }>
// ...other fields documented in the tables below
}
}
Les deux champs d’extracteur sont facultatifs. Un événement de fin peut inclure des valeurs, des échecs, les deux ou aucun. data-om-observation-end signale une fin synchrone. data-om-buffering-end signale la fin d’un travail en arrière-plan dont le contenu mis en mémoire tampon attend encore son activation, bien que les métadonnées d’extraction soient déjà persistées. DataOmBufferingEndPart contient les mêmes champs d’extracteur, et les deux types sont exportés depuis @mastra/memory/processors. Consultez Lire les valeurs extraites depuis un flux pour découvrir un exemple de consommation.
data-om-statusLien direct vers data-om-status
Émis une fois par étape de la boucle de l’Agent, avant la génération du modèle. Fournit un instantané de l’état actuel de la mémoire, notamment l’utilisation des tokens dans les deux fenêtres de contexte et l’état du contenu mis en mémoire tampon de manière asynchrone.
interface DataOmStatusPart {
type: 'data-om-status'
data: {
windows: {
active: {
/** Unobserved message tokens and the threshold that triggers observation */
messages: { tokens: number; threshold: number }
/** Observation tokens and the threshold that triggers reflection */
observations: { tokens: number; threshold: number }
}
buffered: {
observations: {
/** Number of buffered chunks staged for activation */
chunks: number
/** Total message tokens across all buffered chunks */
messageTokens: number
/** Projected message tokens that would be removed if activation happened now (based on bufferActivation ratio and chunk boundaries) */
projectedMessageRemoval: number
/** Observation tokens that will be added on activation */
observationTokens: number
/** idle: no buffering in progress. running: background observer is working. complete: chunks are ready for activation. */
status: 'idle' | 'running' | 'complete'
}
reflection: {
/** Observation tokens that were fed into the reflector (pre-compression size) */
inputObservationTokens: number
/** Observation tokens the reflection will produce on activation (post-compression size) */
observationTokens: number
/** idle: no reflection buffered. running: background reflector is working. complete: reflection is ready for activation. */
status: 'idle' | 'running' | 'complete'
}
}
}
recordId: string
threadId: string
stepNumber: number
/** Increments each time the Reflector creates a new generation */
generationCount: number
}
}
buffered.reflection.inputObservationTokens correspond à la taille des observations envoyées au Reflector. buffered.reflection.observationTokens correspond au résultat compressé : la taille du contenu qui remplacera ces observations lors de l’activation de la réflexion. Un client peut utiliser ces deux valeurs pour afficher un taux de compression.
Les clients peuvent calculer des pourcentages et des estimations après activation à partir des valeurs brutes :
// Message window usage %
const msgPercent = status.windows.active.messages.tokens / status.windows.active.messages.threshold
// Observation window usage %
const obsPercent =
status.windows.active.observations.tokens / status.windows.active.observations.threshold
// Projected message tokens after buffered observations activate
// Uses projectedMessageRemoval which accounts for bufferActivation ratio and chunk boundaries
const postActivation =
status.windows.active.messages.tokens -
status.windows.buffered.observations.projectedMessageRemoval
// Reflection compression ratio (when buffered reflection exists)
const { inputObservationTokens, observationTokens } = status.windows.buffered.reflection
if (inputObservationTokens > 0) {
const compressionRatio = observationTokens / inputObservationTokens
}
data-om-observation-startLien direct vers data-om-observation-start
Émis lorsque l’Agent Observer ou Reflector commence le traitement.
cycleId:
operationType:
startedAt:
tokensToObserve:
recordId:
threadId:
threadIds:
config:
messageTokens, observationTokens et scope au moment de l’observation.data-om-observation-endLien direct vers data-om-observation-end
Émis lorsque l’observation ou la réflexion se termine avec succès.
cycleId:
start associé.operationType:
completedAt:
durationMs:
tokensObserved:
observationTokens:
observations?:
currentTask?:
suggestedResponse?:
extractedValues?:
extractionFailures?:
recordId:
threadId:
data-om-observation-failedLien direct vers data-om-observation-failed
Émis lorsque l’observation ou la réflexion échoue. Le système revient au traitement synchrone.
cycleId:
start associé.operationType:
failedAt:
durationMs:
tokensAttempted:
error:
observations?:
recordId:
threadId:
data-om-buffering-startLien direct vers data-om-buffering-start
Émis lorsque la mise en mémoire tampon asynchrone démarre en arrière-plan. Elle précalcule les observations ou réflexions avant que le seuil principal ne soit atteint.
cycleId:
operationType:
startedAt:
tokensToBuffer:
recordId:
threadId:
threadIds:
config:
data-om-buffering-endLien direct vers data-om-buffering-end
Émis lorsque la mise en mémoire tampon asynchrone se termine. Le contenu est stocké, mais pas encore activé dans le contexte principal.
cycleId:
buffering-start associé.operationType:
completedAt:
durationMs:
tokensBuffered:
bufferedTokens:
observations?:
extractedValues?:
extractionFailures?:
recordId:
threadId:
data-om-buffering-failedLien direct vers data-om-buffering-failed
Émis lorsque la mise en mémoire tampon asynchrone échoue. Le système revient au traitement synchrone lorsque le seuil est atteint.
cycleId:
buffering-start associé.operationType:
failedAt:
durationMs:
tokensAttempted:
error:
observations?:
recordId:
threadId:
data-om-activationLien direct vers data-om-activation
Émis lorsque les observations ou réflexions mises en mémoire tampon sont activées (déplacées dans la fenêtre de contexte active). Cette opération est instantanée : elle n’implique aucun appel LLM.
cycleId:
operationType:
activatedAt:
chunksActivated:
tokensActivated:
observationTokens:
messagesActivated:
generationCount:
observations?:
triggeredBy?:
activateAfterIdle ou un changement de modèle/Provider.lastActivityAt?:
ttlExpiredMs?:
activateAfterIdle au moment du déclenchement de l’activation.previousModel?:
openai/gpt-4o.currentModel?:
recordId:
threadId:
config:
data-om-thread-updateLien direct vers data-om-thread-update
Émis lorsque l’Observer met à jour le titre du thread. Uniquement émis lorsque observation.threadTitle est activé.
cycleId:
threadId:
oldTitle?:
newTitle:
timestamp:
Utilisation autonomeLien direct vers Utilisation autonome
La plupart des utilisateurs doivent employer la classe Memory présentée ci-dessus. L’utilisation directe d’ObservationalMemory est surtout utile pour les benchmarks, l’expérimentation ou lorsque vous devez contrôler l’ordre des processeurs avec d’autres processeurs, tels que les garde-fous.
La classe ObservationalMemory constitue le moteur. Pour l’associer à un Agent, encapsulez-la dans un ObservationalMemoryProcessor, qui nécessite une instance Memory pour charger et persister les messages. Notez que stores.memory est typé comme facultatif sur les adaptateurs de stockage ; une assertion non nulle (ou une vérification à l’exécution) est donc nécessaire :
import { ObservationalMemory, ObservationalMemoryProcessor } from '@mastra/memory/processors'
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { LibSQLStore } from '@mastra/libsql'
const storage = new LibSQLStore({
id: 'my-storage',
url: 'file:./memory.db',
})
const memory = new Memory({ storage })
const om = new ObservationalMemory({
storage: storage.stores.memory!,
memory,
model: 'google/gemini-2.5-flash',
scope: 'resource',
observation: {
messageTokens: 20_000,
},
reflection: {
observationTokens: 60_000,
},
})
const omProcessor = new ObservationalMemoryProcessor(om, memory)
export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
inputProcessors: [omProcessor],
outputProcessors: [omProcessor],
})
Configuration autonomeLien direct vers Configuration autonome
La classe ObservationalMemory autonome accepte les mêmes options que l’objet de configuration observationalMemory ci-dessus, auxquelles s’ajoutent les suivantes :
storage:
MastraStorage.stores.memory).onDebugEvent?:
obscureThreadIds?:
Tool de rappelLien direct vers Tool de rappel
Lorsque retrieval est défini sur une valeur vraie, un Tool recall est enregistré afin que l’Agent puisse parcourir les messages bruts à l’origine des plages de groupes d’observations. Par défaut (portée 'resource'), le Tool permet de répertorier les threads (mode: "threads"), de parcourir d’autres threads (threadId) et d’effectuer une recherche interthreads. Avec retrieval: { vector: true }, la recherche sémantique est disponible (mode: "search"). Définissez scope: 'thread' pour limiter le Tool au thread actuel. Le Tool est automatiquement ajouté à la liste des Tools de l’Agent.
Mastra injecte également dans le contexte de l’Agent des instructions d’utilisation adaptées à la portée. Pour la portée ressource avec vector: true, elles couvrent le routage entre search, threads et messages, y compris le repli vers la découverte des threads lorsque les résultats de recherche ne conviennent pas. Sans vector: true, les instructions couvrent uniquement la navigation dans threads et messages, afin de ne pas orienter l’Agent vers un mode de recherche non configuré. Les instructions de portée ressource sont injectées avant même l’existence d’un groupe d’observations ; l’Agent peut donc parcourir d’autres threads dès le premier message. Utilisez retrieval: { instructions: '...' } pour ajouter des consignes propres à l’application après les instructions intégrées.
ParamètresLien direct vers Paramètres
mode?:
"messages" (valeur par défaut) parcourt l’historique des messages. "threads" répertorie tous les threads de l’utilisateur actuel. "search" recherche des messages par similarité sémantique dans tous les threads (nécessite un stockage vectoriel et un Embedder).query?:
mode: "search". Recherche dans tous les threads de l’utilisateur actuel les messages sémantiquement similaires à ce texte.cursor?:
_range: \startId:endId\_, utilisez startId ou endId). Si une chaîne de plage est transmise directement, le Tool renvoie une indication expliquant comment extraire l’ID correct. Lorsque cursor et threadId sont tous deux omis pour mode: "messages", le Tool parcourt le thread actuel depuis la position définie par anchor.threadId?:
"current" pour le thread actif. Utilisez d’abord mode: "threads" pour découvrir les ID de thread. Lorsque cette option est fournie sans cursor, la lecture commence au début du thread.anchor?:
mode: "messages" sans cursor, parcourt le thread depuis le début (plus ancien en premier) ou la fin (plus récent en premier).page?:
0 est traité comme 1.limit?:
detail?:
'low' affiche le texte tronqué et les noms des Tools avec des index de position ([p0], [p1]). 'high' affiche le contenu complet, notamment les arguments et résultats des Tools, limité à une partie par appel avec des indications de continuation.partType?:
mode: "messages".toolName?:
mode: "messages".partIndex?:
[p1] ; effectuez un nouvel appel avec partIndex: 1 pour consulter le contenu complet sans charger toutes les parties.before?:
mode: "threads". Filtre les threads créés avant cette date. Accepte le format ISO 8601, par exemple "2026-03-15" ou "2026-03-10T00:00:00Z".after?:
mode: "threads". Filtre les threads créés après cette date. Accepte le format ISO 8601, par exemple "2026-03-01" ou "2026-03-10T00:00:00Z".Valeur renvoyée (mode messages)Lien direct vers Valeur renvoyée (mode messages)
messages:
detail.count:
cursor:
page:
limit:
detail:
hasNextPage:
hasPrevPage:
truncated?:
true lorsque la sortie a été limitée par le budget de tokens. L’Agent peut paginer ou utiliser partIndex pour accéder au contenu restant.tokenOffset?:
truncated vaut true.Valeur renvoyée (mode threads)Lien direct vers Valeur renvoyée (mode threads)
threads:
← current.count:
page:
hasMore:
Valeur renvoyée (mode recherche)Lien direct vers Valeur renvoyée (mode recherche)
results:
count:
ModelByInputTokensLien direct vers ModelByInputTokens
ModelByInputTokens sélectionne un modèle en fonction du nombre de tokens d’entrée. Il choisit le modèle associé au plus petit seuil couvrant la taille réelle de l’entrée.
ConstructeurLien direct vers Constructeur
new ModelByInputTokens(config)
Où config est un objet dont les clés upTo associent des seuils de tokens (nombres) à des modèles cibles.
ExempleLien direct vers Exemple
import { ModelByInputTokens } from '@mastra/memory'
const selector = new ModelByInputTokens({
upTo: {
10_000: 'google/gemini-2.5-flash', // Fast for small inputs
40_000: 'openai/gpt-5-mini', // Stronger for medium inputs
1_000_000: 'openai/gpt-5.6-sol', // Most capable for large inputs
},
})
ComportementLien direct vers Comportement
- Les seuils sont triés en interne ; leur ordre dans l’objet de configuration est donc sans importance.
inputTokens ≤ smallest threshold→ utilise le modèle de ce seuilinputTokens > largest threshold→resolve()lève une erreur. Si cela se produit pendant une exécution OM de l’Observer ou du Reflector, OM abandonne par l’intermédiaire de TripWire ; les appelants reçoivent donc un résultattextvide ou untripwirediffusé en continu plutôt qu’une réponse normale de l’assistant.- OM calcule le nombre de tokens d’entrée de l’appel à l’Observer ou au Reflector et résout directement le niveau de modèle correspondant