> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # 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 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 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 : ```sql UPDATE mastra_scorers SET "requestContext" = "runtimeContext" WHERE "runtimeContext" IS NOT NULL; ALTER TABLE mastra_scorers DROP COLUMN "runtimeContext"; ``` ### 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. #### Option 1 : utiliser la CLI (recommandé) Exécutez la commande de migration, qui déduplique automatiquement les spans et ajoute la contrainte : ```bash 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) Si vous préférez exécuter la migration manuellement : ```sql -- 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) Pour ClickHouse, LibSQL, MongoDB ou MSSQL, utilisez l'API programmatique : ```typescript 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) **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. ```sql 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 ### Composition du stockage dans `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é. ```typescript 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](https://mastra.zisheng.pro/fr/reference/storage/composite) pour plus de détails. ## Modifications ### `MastraStorage` renommé en `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 : ```diff - 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 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. ```diff 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` 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. ```diff memoryStore.listMessages({ threadId: 'thread-123', - offset: 0, - limit: 20, + page: 0, + perPage: 20, }); ``` ### De `getMessagesPaginated` à `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. ```diff + 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 : > > ```bash > npx @mastra/codemod@latest v1/storage-get-messages-paginated . > ``` ### Accès au stockage par domaine 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é. ```diff 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` 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. ```diff - 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. ```typescript // 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 : > > ```bash > npx @mastra/codemod@latest v1/storage-list-threads-by-resource-to-list-threads . > ``` ### De `getWorkflowRuns` à `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. ```diff - 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 : > > ```bash > npx @mastra/codemod@latest v1/storage-list-workflow-runs . > ``` ### De `getMessagesById` à `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. ```diff + 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 : > > ```bash > npx @mastra/codemod@latest v1/storage-list-messages-by-id . > ``` ### Signatures de stockage de `getMessages` et `saveMessages` 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. ```diff + 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 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. ```diff - 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 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. ```diff - 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 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. ```diff - 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 : > > ```bash > npx @mastra/codemod@latest v1/vector-pg-constructor . > ``` ### De PGVector `defineIndex` à `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. ```diff - await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' }); + await vectorDB.buildIndex({ + indexName: indexName, + metric: 'cosine', + indexConfig: { type: 'flat' }, + }); ``` ### `PostgresStore` : de `schema` à `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. ```diff 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 : > > ```bash > npx @mastra/codemod@latest v1/storage-postgres-schema-name . > ``` ### Adoption du modèle `listScoresBy*` pour les méthodes de stockage des scores 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. ```diff - const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' }); + const scores = await storage.listScoresByScorerId({ + scorerId: 'helpfulness-scorer', + }); + // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan ``` ## Suppressions ### 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`. ```diff - // 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` 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é. ```diff - 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 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. ```diff - import { createEvalsTests } from '@internal/test-utils/domains/evals'; - createEvalsTests({ storage }); + // Use storage APIs directly for testing ``` ### 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.