Aller au contenu principal

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ées
Lien 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 scorers
Lien direct vers Renommage d'une colonne de la table des scorers

La colonne runtimeContext de mastra_scorers a été renommée en requestContext.

Qui doit effectuer cette migration ?

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.

Que se passe-t-il sans cette migration ?

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 double
Lien 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.

Qui doit effectuer cette migration ?

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.

Que se passe-t-il sans cette migration ?

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.

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.

Recommandé

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;

Ajouts
Lien direct vers Ajouts

Composition du stockage dans MastraCompositeStore
Lien 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.

Modifications
Lien direct vers Modifications

MastraStorage renommé en MastraCompositeStore
Lien 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 }),
},
}),
});
remarque

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 stockage
Lien 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/perPage
Lien 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 à listMessages
Lien 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,
+ });
Codemod

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 ressources
  • workflows - Instantanés de workflows
  • scores - Scores d'évaluation
  • observability - Traces et spans
  • agents - 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 à listThreads
Lien 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.

important

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,
})
Codemod

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 à listWorkflowRuns
Lien 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,
});
Codemod

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 à listMessagesById
Lien 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'],
});
Codemod

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 saveMessages
Lien 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 vectorielles
Lien 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 vectorielles
Lien 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 PGVector
Lien 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,
+ });
Codemod

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 à buildIndex
Lien 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 à schemaName
Lien 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,
});
Codemod

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 scores
Lien 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

Suppressions
Lien direct vers Suppressions

Fonctions de stockage sans pagination
Lien 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 getTracesPaginated
Lien 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 évaluations
Lien 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 MSSQL
Lien 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.