Stockage
Les API de stockage ont été standardisées afin d'utiliser des conventions cohérentes de pagination et de nommage dans toutes les méthodes.
Migration de la base de donnéesLien direct vers Migration de la base de données
Exécutez ces migrations SQL dans le cadre de votre processus de migration habituel (par exemple, Prisma Migrate, Drizzle Kit ou le processus de validation de votre administrateur de base de données).
Renommage d'une colonne de la table des scorersLien direct vers Renommage d'une colonne de la table des scorers
La colonne runtimeContext de mastra_scorers a été renommée en requestContext.
Uniquement si vous utilisez @mastra/pg ou @mastra/libsql avec les évaluations ou le scoring et que la colonne runtimeContext contient déjà des données.
Les données de contexte de requête des enregistrements de score existants ne seront plus accessibles.
Après avoir déployé la v1 (qui ajoute la nouvelle colonne requestContext lors de l'initialisation), copiez les données et supprimez l'ancienne colonne :
UPDATE mastra_scorers SET "requestContext" = "runtimeContext" WHERE "runtimeContext" IS NOT NULL;
ALTER TABLE mastra_scorers DROP COLUMN "runtimeContext";
Migration des spans en doubleLien direct vers Migration des spans en double
Si vous effectuez une mise à niveau depuis une ancienne version de Mastra, il se peut que des entrées (traceId, spanId) soient présentes en double dans votre table mastra_spans. La v1 ajoute une contrainte d'unicité sur ces colonnes afin de garantir l'intégrité des données, mais cette contrainte ne peut pas être ajoutée tant que des doublons existent.
Uniquement si vous possédez des données de spans provenant de versions de Mastra antérieures à la v1 et rencontrez des erreurs de violation de clé dupliquée ou d'échec de création de contrainte.
L'initialisation du stockage peut échouer lors de l'ajout de la contrainte d'unicité, ou des erreurs telles que « duplicate key value violates unique constraint » peuvent apparaître.
Option 1 : utiliser la CLI (recommandé)Lien direct vers Option 1 : utiliser la CLI (recommandé)
Exécutez la commande de migration, qui déduplique automatiquement les spans et ajoute la contrainte :
npx mastra migrate
La CLI regroupe votre projet et se connecte au stockage configuré avant d'exécuter la migration. Lors de la suppression des doublons, elle conserve l'enregistrement le plus complet (selon endTime et les attributs).
Option 2 : SQL manuel (PostgreSQL)Lien direct vers Option 2 : SQL manuel (PostgreSQL)
Si vous préférez exécuter la migration manuellement :
-- Remove duplicates, keeping the most complete record
DELETE FROM mastra_spans a USING mastra_spans b
WHERE a.ctid < b.ctid
AND a."traceId" = b."traceId"
AND a."spanId" = b."spanId";
-- Add the unique constraint
ALTER TABLE mastra_spans ADD CONSTRAINT mastra_spans_trace_span_unique UNIQUE ("traceId", "spanId");
Option 3 : migration manuelle (autres bases de données)Lien direct vers Option 3 : migration manuelle (autres bases de données)
Pour ClickHouse, LibSQL, MongoDB ou MSSQL, utilisez l'API programmatique :
const storage = mastra.getStorage()
const observabilityStore = await storage.getStore('observability')
// Check if migration is needed
const status = await observabilityStore?.checkSpansMigrationStatus()
console.log(status)
// Run the migration
const result = await observabilityStore?.migrateSpans()
console.log(result)
Colonnes JSON (TEXT → JSONB)Lien direct vers Colonnes JSON (TEXT → JSONB)
PostgreSQL uniquement. La colonne metadata de mastra_threads et la colonne snapshot de mastra_workflow_snapshot sont passées du type TEXT au type JSONB.
La migration vers JSONB permet d'utiliser les opérateurs JSON natifs de PostgreSQL et l'indexation GIN afin d'améliorer les performances des requêtes sur les champs JSON.
ALTER TABLE mastra_threads
ALTER COLUMN metadata TYPE jsonb
USING metadata::jsonb;
ALTER TABLE mastra_workflow_snapshot
ALTER COLUMN snapshot TYPE jsonb
USING snapshot::jsonb;
AjoutsLien direct vers Ajouts
Composition du stockage dans MastraCompositeStoreLien direct vers storage-composition-in-mastracompositestore
MastraCompositeStore peut désormais composer des domaines de stockage provenant de différents adaptateurs. Utilisez-le lorsque vous avez besoin de bases de données distinctes selon les usages, par exemple PostgreSQL pour la mémoire et les workflows, et une base de données spécialisée pour l'observabilité.
import { MastraCompositeStore } from '@mastra/core/storage'
import { MemoryPG, WorkflowsPG, ScoresPG } from '@mastra/pg'
import { MemoryLibSQL } from '@mastra/libsql'
import { Mastra } from '@mastra/core'
// Compose domains from different stores
const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite',
domains: {
memory: new MemoryLibSQL({ url: 'file:./local.db' }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
},
}),
})
Consultez la référence sur la composition du stockage pour plus de détails.
ModificationsLien direct vers Modifications
MastraStorage renommé en MastraCompositeStoreLien direct vers mastrastorage-renamed-to-mastracompositestore
La classe MastraStorage a été renommée en MastraCompositeStore afin de mieux refléter son rôle d'implémentation de stockage composite, qui achemine différents domaines vers différents stockages sous-jacents. Cela évite toute confusion avec le concept général de « stockage Mastra » (la propriété storage de l'instance Mastra).
L'ancien nom MastraStorage reste disponible en tant qu'alias obsolète pour assurer la rétrocompatibilité, mais il sera supprimé dans une prochaine version.
Pour effectuer la migration, mettez à jour vos imports et l'instanciation :
- import { MastraStorage } from "@mastra/core/storage";
+ import { MastraCompositeStore } from "@mastra/core/storage";
import { MemoryLibSQL } from "@mastra/libsql";
import { WorkflowsPG } from "@mastra/pg";
export const mastra = new Mastra({
- storage: new MastraStorage({
+ storage: new MastraCompositeStore({
id: "composite",
domains: {
memory: new MemoryLibSQL({ url: "file:./memory.db" }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
},
}),
});
Si vous utilisez directement une seule implémentation de stockage (comme PostgresStore ou LibSQLStore), conservez la configuration existante. Ce changement concerne uniquement le code qui utilise explicitement MastraStorage pour le stockage composite.
Propriété id obligatoire pour les instances de stockageLien direct vers required-id-property-for-storage-instances
Les instances de stockage nécessitent désormais une propriété id. Cet identifiant unique sert à suivre et à gérer les instances de stockage dans Mastra. La valeur de id doit être une chaîne descriptive et unique pour chaque instance de stockage de votre application.
Pour effectuer la migration, ajoutez un champ id au constructeur de votre stockage.
const storage = new PostgresStore({
+ id: 'main-postgres-store',
connectionString: process.env.POSTGRES_CONNECTION_STRING,
schemaName: 'public',
});
const upstashStore = new UpstashStore({
+ id: 'upstash-cache-store',
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
Passage de la pagination offset/limit à page/perPageLien direct vers pagination-from-offsetlimit-to-pageperpage
Toutes les API de pagination utilisent désormais page et perPage au lieu de offset et limit, conformément à la pagination web fondée sur les pages.
Pour effectuer la migration, remplacez tous les paramètres de pagination offset/limit par page/perPage. Notez que l'indexation de page commence à 0.
memoryStore.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});
De getMessagesPaginated à listMessagesLien direct vers getmessagespaginated-to-listmessages
La méthode getMessagesPaginated() a été remplacée par listMessages(). La nouvelle méthode accepte perPage: false pour récupérer tous les enregistrements sans pagination. Ce changement respecte la convention de nommage list* et offre davantage de souplesse pour récupérer l'ensemble des enregistrements.
Pour effectuer la migration, renommez la méthode et mettez à jour les paramètres de pagination. Vous pouvez désormais utiliser perPage: false pour récupérer tous les enregistrements.
+ const memoryStore = await storage.getStore('memory');
+
// Paginated
- const result = await storage.getMessagesPaginated({
+ const result = await memoryStore?.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});
// Fetch all records (no pagination limit)
+ const allMessages = await memoryStore?.listMessages({
+ threadId: 'thread-123',
+ page: 0,
+ perPage: false,
+ });
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/storage-get-messages-paginated .
Accès au stockage par domaine via getStore()Lien direct vers domain-specific-storage-access-via-getstore
Les opérations de stockage sont désormais accessibles par l'intermédiaire de stockages propres à chaque domaine, plutôt que directement sur l'instance de stockage.
Les domaines comprennent :
memory- Threads, messages et ressourcesworkflows- Instantanés de workflowsscores- Scores d'évaluationobservability- Traces et spansagents- Données d'agents stockées
Pour effectuer la migration, appelez getStore() avec le nom du domaine, puis appelez les méthodes sur le stockage renvoyé.
const storage = mastra.getStorage();
// Memory operations (threads, messages, resources)
- const thread = await storage.getThread({ threadId: '123' });
- await storage.saveThread({ thread });
+ const memoryStore = await storage.getStore('memory');
+ const thread = await memoryStore?.getThreadById({ threadId: '123' });
+ await memoryStore?.saveThread({ thread });
// Workflow operations (snapshots)
- const snapshot = await storage.loadWorkflowSnapshot({ runId, workflowName });
- await storage.persistWorkflowSnapshot({ runId, workflowName, snapshot });
+ const workflowStore = await storage.getStore('workflows');
+ const snapshot = await workflowStore?.loadWorkflowSnapshot({ runId, workflowName });
+ await workflowStore?.persistWorkflowSnapshot({ runId, workflowName, snapshot });
// Observability operations (traces, spans)
- const traces = await storage.listTraces({ page: 0, perPage: 20 });
+ const observabilityStore = await storage.getStore('observability');
+ const traces = await observabilityStore?.listTraces({ page: 0, perPage: 20 });
// Score operations (evaluations)
- const scores = await storage.listScoresByScorerId({ scorerId: 'helpfulness' });
+ const scoresStore = await storage.getStore('scores');
+ const scores = await scoresStore?.listScoresByScorerId({ scorerId: 'helpfulness' });
De getThreadsByResourceId à listThreadsLien direct vers getthreadsbyresourceid-to-listthreads
La méthode getThreadsByResourceId() a été remplacée par listThreads(). La nouvelle méthode prend en charge la pagination et le filtrage par resourceId, par metadata ou par les deux.
L'ancienne méthode getThreadsByResourceId() renvoyait tous les threads correspondants sans pagination. La nouvelle méthode listThreads() nécessite des paramètres de pagination. Pour conserver l'ancien comportement et récupérer tous les threads, utilisez perPage: false.
Pour effectuer la migration, utilisez le stockage de mémoire et la nouvelle méthode listThreads() avec la pagination et un objet de filtre facultatif.
- const threads = await storage.getThreadsByResourceId({
- resourceId: 'res-123',
- });
+ const memoryStore = await storage.getStore('memory');
+
+ // Paginated (recommended for large datasets)
+ const result = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ page: 0,
+ perPage: 20,
+ });
+ const threads = result?.threads;
+
+ // Or fetch all threads like before (use perPage: false)
+ const allResult = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ perPage: false,
+ });
+ const allThreads = allResult?.threads;
La nouvelle méthode permet également :
- de répertorier tous les threads (sans indiquer de filtre) ;
- de filtrer uniquement par métadonnées ;
- de combiner les filtres resourceId et metadata.
// List all threads
await memoryStore?.listThreads({ page: 0, perPage: 20 })
// Filter by metadata only
await memoryStore?.listThreads({
filter: { metadata: { status: 'active' } },
page: 0,
perPage: 20,
})
// Combined filter
await memoryStore?.listThreads({
filter: {
resourceId: 'user-123',
metadata: { category: 'support' },
},
page: 0,
perPage: 20,
})
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/storage-list-threads-by-resource-to-list-threads .
De getWorkflowRuns à listWorkflowRunsLien direct vers getworkflowruns-to-listworkflowruns
La méthode getWorkflowRuns() a été renommée en listWorkflowRuns(). Ce changement respecte la convention selon laquelle les méthodes list* renvoient des collections.
Pour effectuer la migration, utilisez le stockage des workflows, renommez l'appel de méthode et mettez à jour les paramètres de pagination.
- const runs = await storage.getWorkflowRuns({
+ const workflowStore = await storage.getStore('workflows');
+ const runs = await workflowStore?.listWorkflowRuns({
fromDate,
toDate,
+ page: 0,
+ perPage: 20,
});
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/storage-list-workflow-runs .
De getMessagesById à listMessagesByIdLien direct vers getmessagesbyid-to-listmessagesbyid
La méthode getMessagesById() a été renommée en listMessagesById(). Ce changement respecte la convention selon laquelle les méthodes list* renvoient des collections.
Pour effectuer la migration, utilisez le stockage de mémoire et renommez l'appel de méthode.
+ const memoryStore = await storage.getStore('memory');
- const result = await storage.getMessagesById({
+ const result = await memoryStore?.listMessagesById({
messageIds: ['msg-1', 'msg-2'],
});
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/storage-list-messages-by-id .
Signatures de stockage de getMessages et saveMessagesLien direct vers storage-getmessages-and-savemessages-signatures
Les signatures et les types de retour des méthodes getMessages() et saveMessages() ont changé. Les surcharges de format ont été supprimées et les méthodes fonctionnent désormais toujours avec MastraDBMessage. Ce changement simplifie l'API en supprimant les variations de format.
Pour effectuer la migration, utilisez le stockage de mémoire, supprimez les paramètres de format et adaptez le code au type de retour désormais uniforme.
+ const memoryStore = await storage.getStore('memory');
+
// Always returns { messages: MastraDBMessage[] }
- const v1Messages = await storage.getMessages({ threadId, format: 'v1' });
- const v2Messages = await storage.getMessages({ threadId, format: 'v2' });
+ const result = await memoryStore?.getMessages({ threadId });
+ const messages = result?.messages; // MastraDBMessage[]
// SaveMessages always uses MastraDBMessage
- await storage.saveMessages({ messages: v1Messages, format: 'v1' });
- await storage.saveMessages({ messages: v2Messages, format: 'v2' });
+ const saveResult = await memoryStore?.saveMessages({ messages: mastraDBMessages });
+ const saved = saveResult?.messages; // MastraDBMessage[]
Passage des arguments positionnels aux arguments nommés dans l'API des bases vectoriellesLien direct vers Passage des arguments positionnels aux arguments nommés dans l'API des bases vectorielles
Toutes les méthodes des bases vectorielles utilisent désormais un objet d'arguments plutôt que des arguments positionnels. Le rôle de chaque valeur est ainsi visible au point d'appel, et les signatures de méthode peuvent évoluer sans dépendre de l'ordre des arguments.
Pour effectuer la migration, mettez à jour tous les appels de méthodes des bases vectorielles afin qu'ils utilisent un objet d'arguments.
- await vectorDB.createIndex(indexName, 3, 'cosine');
+ await vectorDB.createIndex({
+ indexName: indexName,
+ dimension: 3,
+ metric: 'cosine',
+ });
- await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]);
+ await vectorDB.upsert({
+ indexName: indexName,
+ vectors: [[1, 2, 3]],
+ metadata: [{ test: 'data' }],
+ });
- await vectorDB.query(indexName, [1, 2, 3], 5);
+ await vectorDB.query({
+ indexName: indexName,
+ queryVector: [1, 2, 3],
+ topK: 5,
+ });
Renommage des méthodes des bases vectoriellesLien direct vers Renommage des méthodes des bases vectorielles
Les méthodes updateIndexById et deleteIndexById ont été renommées respectivement en updateVector et deleteVector. Les nouveaux noms indiquent que ces méthodes agissent sur des vecteurs.
Pour effectuer la migration, renommez les méthodes et transmettez un objet d'arguments.
- await vectorDB.updateIndexById(indexName, id, update);
- await vectorDB.deleteIndexById(indexName, id);
+ await vectorDB.updateVector({ indexName, id, update });
+ await vectorDB.deleteVector({ indexName, id });
Passage d'une chaîne de connexion à un objet pour le constructeur PGVectorLien direct vers Passage d'une chaîne de connexion à un objet pour le constructeur PGVector
Le constructeur PGVector attend désormais des paramètres sous forme d'objet plutôt qu'une chaîne de connexion. Ce changement rend l'API plus cohérente entre tous les adaptateurs de stockage.
Pour effectuer la migration, transmettez la chaîne de connexion comme propriété d'un objet.
- const pgVector = new PgVector(process.env.POSTGRES_CONNECTION_STRING!);
+ const pgVector = new PgVector({
+ connectionString: process.env.POSTGRES_CONNECTION_STRING,
+ });
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/vector-pg-constructor .
De PGVector defineIndex à buildIndexLien direct vers pgvector-defineindex-to-buildindex
La méthode defineIndex() a été supprimée au profit de buildIndex(), dont le nom indique que la méthode construit un index.
Pour effectuer la migration, renommez la méthode et transmettez un objet d'arguments.
- await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' });
+ await vectorDB.buildIndex({
+ indexName: indexName,
+ metric: 'cosine',
+ indexConfig: { type: 'flat' },
+ });
PostgresStore : de schema à schemaNameLien direct vers postgresstore-schema-to-schemaname
Le paramètre schema a été renommé en schemaName dans le constructeur PostgresStore. Le nouveau nom indique que la valeur correspond au nom du schéma de la base de données.
Pour effectuer la migration, renommez le paramètre.
const pgStore = new PostgresStore({
connectionString: process.env.POSTGRES_CONNECTION_STRING,
- schema: customSchema,
+ schemaName: customSchema,
});
Vous pouvez utiliser la CLI codemod de Mastra pour mettre à jour votre code automatiquement :
npx @mastra/codemod@latest v1/storage-postgres-schema-name .
Adoption du modèle listScoresBy* pour les méthodes de stockage des scoresLien direct vers score-storage-methods-to-listscoresby-pattern
Les API de stockage des scores ont été renommées selon le modèle listScoresBy*. Ce changement assure leur cohérence avec les conventions générales de nommage de l'API.
Pour effectuer la migration, remplacez les noms de méthode getScores par listScoresByScorerId et les variantes associées.
- const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' });
+ const scores = await storage.listScoresByScorerId({
+ scorerId: 'helpfulness-scorer',
+ });
+ // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan
SuppressionsLien direct vers Suppressions
Fonctions de stockage sans paginationLien direct vers Fonctions de stockage sans pagination
Les fonctions de stockage sans pagination ont été supprimées au profit de versions paginées. Toutes les opérations de liste utilisent désormais la pagination, même s'il reste possible de récupérer tous les enregistrements avec perPage: false. Ce changement garantit la cohérence de l'API et évite le chargement accidentel de jeux de données volumineux.
Pour effectuer la migration, utilisez les méthodes paginées par l'intermédiaire des stockages propres aux domaines. Pour récupérer tous les enregistrements, utilisez perPage: false.
- // Non-paginated direct access
- const messages = await storage.getMessages({ threadId });
+ // Use paginated methods via domain stores
+ const memoryStore = await storage.getStore('memory');
+ const result = await memoryStore?.listMessages({ threadId, page: 0, perPage: 20 });
+ // Or fetch all
+ const allMessages = await memoryStore?.listMessages({
+ threadId,
+ page: 0,
+ perPage: false,
+ });
getTraces et getTracesPaginatedLien direct vers gettraces-and-gettracespaginated
Les méthodes getTraces() et getTracesPaginated() ont été supprimées du stockage. Utilisez le package d'observabilité pour accéder aux traces plutôt que le stockage principal.
Pour effectuer la migration, utilisez à la place les méthodes de stockage de l'observabilité.
- const traces = await storage.getTraces({ traceId: 'trace-123' });
- const paginated = await storage.getTracesPaginated({ page: 0, perPage: 20 });
+ // Use observability API for traces
+ import { initObservability } from '@mastra/observability';
+ const observability = initObservability({ config: { ... } });
+ // Access traces through observability API
Utilitaires de test des évaluationsLien direct vers Utilitaires de test des évaluations
Les utilitaires de test du domaine des évaluations ont été supprimés de @internal/test-utils. Ce changement découle de la suppression de l'ancienne fonctionnalité d'évaluation.
Pour effectuer la migration, utilisez directement les API de stockage dans vos tests plutôt que les utilitaires de test spécialisés pour les évaluations.
- import { createEvalsTests } from '@internal/test-utils/domains/evals';
- createEvalsTests({ storage });
+ // Use storage APIs directly for testing
TABLE_EVALS du stockage MSSQLLien direct vers TABLE_EVALS du stockage MSSQL
La table TABLE_EVALS a été supprimée des implémentations de stockage MSSQL. Ce changement découle de la suppression de l'ancienne fonctionnalité d'évaluation.
Si vous utilisiez le stockage MSSQL avec les évaluations, migrez vers un autre adaptateur de stockage ou supprimez la fonctionnalité d'évaluation.