> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Threads multi-utilisateurs Un même thread Mastra peut être partagé par plusieurs utilisateurs, chacun possédant son propre nom et son propre rôle fonctionnel. L’identité du locuteur est intégrée au corps du message afin que l’agent puisse distinguer les utilisateurs tout en lisant un seul thread partagé. ## Quand utiliser des threads multi-utilisateurs Utilisez des threads multi-utilisateurs lorsque plusieurs personnes collaborent sur le même sujet par l’intermédiaire d’un agent : - Documents collaboratifs réunissant des rédacteurs, des réviseurs et des approbateurs - Conversations de groupe dans lesquelles un même assistant sert plusieurs participants - Revues impliquant plusieurs parties prenantes, dans lesquelles les rôles disposent de niveaux d’autorité différents ## Partager un même `resourceId` entre tous les participants Un thread appartient à un seul `resourceId` ; tous les participants d’un thread partagé doivent donc transmettre la même valeur. Au lieu d’utiliser un identifiant utilisateur, comme le font par défaut les applications à utilisateur unique, fondez `resourceId` sur la conversation elle-même, par exemple `doc_${docId}` pour un document partagé ou `room_${roomId}` pour une conversation de groupe. Lorsque tout le monde pointe vers le même `resourceId`, tous les participants lisent et écrivent le même historique. ## Ajouter l’identité du locuteur à chaque message utilisateur Le modèle doit savoir qui parle à chaque tour. Puisque le corps du message est le seul endroit qui persiste dans l’historique puis revient dans le contexte, enveloppez chaque message utilisateur dans une petite balise `` contenant l’identifiant, le nom et le rôle du locuteur. La balise reste attachée au message ; lorsque les tours précédents sont rappelés, le modèle sait donc toujours qui a dit quoi. Construisez la balise avec une petite fonction utilitaire. L’exemple ci-dessous présente une façon de procéder : copiez-le dans votre projet et adaptez-le à la structure de vos données utilisateur : ```typescript export type Speaker = { id: string name: string role: string } function escapeAttr(value: string) { return value .replace(/&/g, '&') .replace(/"/g, '"') .replace(//g, '>') } export function asUserTurn(speaker: Speaker, text: string) { const id = escapeAttr(speaker.id) const name = escapeAttr(speaker.name) const role = escapeAttr(speaker.role) return { role: 'user' as const, content: ` ${text} `, } } ``` Apprenez à l’agent à lire la balise `` dans ses instructions. La propriété `memory` doit être configurée sur l’agent afin de pouvoir l’appeler avec un `thread` et une `resource` : ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, }, }) export const collabAgent = new Agent({ id: 'collab', name: 'CollabAgent', model: 'openai/gpt-5-mini', memory, instructions: ` You are a collaborative document assistant. Multiple users talk to you in the SAME thread. Every user message is wrapped in a tag carrying the user's identity: ...message text... Rules: 1. Address users by their author_name. 2. Respect functional_role: editors propose changes, reviewers approve. 3. When attributing past statements, read author_name from the surrounding tag. 4. Do not echo the tags back at users. `.trim(), }) ``` Appelez l’agent avec le message enveloppé. Tous les participants partagent le même `thread` et la même `resource` : ```typescript import { asUserTurn } from './identity' const docResourceId = 'doc_42' const docThreadId = 'doc_42' const alice = { id: 'u_alice', name: 'Alice', role: 'editor' } const bob = { id: 'u_bob', name: 'Bob', role: 'reviewer' } await collabAgent.generate([asUserTurn(alice, 'My favorite color is teal.')], { memory: { thread: docThreadId, resource: docResourceId }, }) await collabAgent.generate([asUserTurn(bob, 'I want QA sign-off before publish.')], { memory: { thread: docThreadId, resource: docResourceId }, }) ``` La balise `` persiste dans le corps du message. Lorsque l’historique est rappelé lors de tours ultérieurs, le modèle sait donc toujours qui a dit quoi. ## Combiner les couches de mémoire Le modèle d’étiquetage des utilisateurs se combine avec toutes les couches de mémoire. Choisissez la couche selon la durée pendant laquelle la conversation doit mémoriser les faits propres à chaque utilisateur : - **Conversations courtes**, limitées à une seule session ou à un thread assez petit pour tenir dans `lastMessages`, ou situations nécessitant un enregistrement mot pour mot de chaque intervention : utilisez [uniquement l’historique des messages](#message-history-alone). Les balises utilisateur de l’historique suffisent ; aucune couche de mémoire supplémentaire n’est nécessaire. - **Threads de longue durée**, c’est-à-dire des conversations qui dépassent `lastMessages` et dont les faits propres à chaque utilisateur doivent survivre à l’éviction de l’historique : utilisez la [mémoire observationnelle](#with-observational-memory-recommended). - **Besoin d’une liste structurée de participants, ou adaptateur de stockage incompatible avec OM**, qui nécessite LibSQL, PG ou MongoDB : utilisez la [mémoire de travail](#with-working-memory). Nous recommandons d’utiliser soit la mémoire observationnelle, soit la mémoire de travail, car elles répondent à des besoins qui se recoupent. Les exécuter ensemble augmente la latence et le coût en tokens sans apporter beaucoup d’avantages. ### Historique des messages uniquement Pour les conversations courtes, ou lorsque vous avez besoin d’un enregistrement mot pour mot de chaque intervention, les balises utilisateur de l’historique suffisent. `lastMessages` réinjecte les tours précédents dans le contexte en conservant leur attribution : ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, }, }) ``` Le modèle lit l’identité dans la balise `` du message actuel ainsi que dans les messages précédents balisés, réinjectés au moyen de `lastMessages`. ### Avec la mémoire observationnelle (recommandé) La [mémoire observationnelle](https://mastra.zisheng.pro/fr/docs/memory/observational-memory) (OM) extrait les faits propres à chaque utilisateur dans un journal en arrière-plan sans consommer le budget d’outils de l’agent. Le modèle Observer par défaut lit nativement les balises `` et produit des attributions telles que `Alice stated her favorite color is teal.` et `Bob asked for QA sign-off before publish.` Préférez OM à la mémoire de travail pour les threads multi-utilisateurs lorsque votre stockage le prend en charge. OM extrait automatiquement les faits, s’adapte à n’importe quel nombre de participants et ne nécessite aucune maintenance de modèle. Activez-la sans remplacement : ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, observationalMemory: true, }, }) ``` OM nécessite un adaptateur de stockage qui la prend en charge : `@mastra/libsql`, `@mastra/pg`, `@mastra/mongodb` ou `@mastra/oracledb`. > **Remarque:** Si vous remplacez le modèle Observer par un modèle moins performant et que les faits se réduisent à un terme générique `User`, utilisez [`observation.instruction`](https://mastra.zisheng.pro/fr/reference/memory/observational-memory) pour apprendre à l’Observer à lire la balise ``. ### Avec la mémoire de travail Utilisez la mémoire de travail lorsque OM n’est pas envisageable, par exemple si votre adaptateur de stockage ne prend pas OM en charge, ou lorsque vous avez besoin d’une liste de participants structurée et déterministe que l’agent peut lire et modifier à chaque tour. Le modèle de [mémoire de travail](https://mastra.zisheng.pro/fr/docs/memory/working-memory) par défaut suppose un utilisateur par thread (« Prénom », « Nom », etc.). Pour les threads multi-utilisateurs, fournissez un modèle comportant une liste de participants : ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, workingMemory: { enabled: true, scope: 'thread', template: `# Document Collaboration State ## Participants ## Open Questions ## Decisions `, }, }, }) ``` Définissez `scope: 'thread'` afin que la liste des participants appartienne au document et non à un utilisateur individuel. Ajoutez une instruction demandant à l’agent d’ajouter chaque nouveau participant à la liste lorsqu’un nouvel `author_id` apparaît dans une balise ``. Pour en savoir plus sur les modèles, consultez la page [Modèles personnalisés](https://mastra.zisheng.pro/fr/docs/memory/working-memory). ## Sécurité Définissez le `speaker` à partir du contexte de requête authentifié, jamais à partir du corps de la requête. Si un client peut choisir son propre `author_id`, un utilisateur peut usurper l’identité d’un autre. Utilisez le [contexte de requête](https://mastra.zisheng.pro/fr/docs/server/request-context) pour lire l’utilisateur vérifié depuis votre couche d’authentification et construire la balise `` sur le serveur avant d’appeler l’agent. ## Ressources associées - [Mémoire de travail](https://mastra.zisheng.pro/fr/docs/memory/working-memory) - [Mémoire observationnelle](https://mastra.zisheng.pro/fr/docs/memory/observational-memory) - [Partager la mémoire entre les agents](https://mastra.zisheng.pro/fr/docs/memory/overview) - [Référence de `Memory`](https://mastra.zisheng.pro/fr/reference/memory/memory-class)