> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Channels **Ajouté dans :** `@mastra/core@1.22.0` Channels connecte les agents aux plateformes de messagerie. Configurez-les via la propriété `channels` du constructeur `Agent`. L’objet transmis est un `ChannelConfig`. Consultez la [présentation de Channels](https://mastra.zisheng.pro/fr/docs/capabilities/channels/overview) pour les concepts et les instructions de configuration des plateformes. ## Exemple d’utilisation ```typescript import { Agent } from '@mastra/core/agent' import { createSlackAdapter } from '@chat-adapter/slack' import { createDiscordAdapter } from '@chat-adapter/discord' export const supportAgent = new Agent({ id: 'support-agent', name: 'Support Agent', instructions: 'You are a helpful support assistant.', model: 'openai/gpt-5.6-sol', channels: { adapters: { slack: createSlackAdapter(), discord: createDiscordAdapter(), }, }, }) ``` ## Paramètres La propriété `channels` accepte un objet `ChannelConfig` avec les champs suivants : **adapters** (`Record`): Adaptateurs de plateforme indexés par nom (par ex. slack, discord). Transmettez directement un Adapter pour les valeurs par défaut, ou un objet ChannelAdapterConfig pour personnaliser les options par adaptateur. **handlers** (`ChannelHandlers`): Remplace les gestionnaires de messages par défaut pour les DM, les mentions et les threads suivis. **inlineMedia** (`string[] | ((mimeType: string) => boolean)`): Contrôle les types de pièces jointes envoyés au modèle sous forme de parties de fichier. Les types qui ne correspondent pas sont décrits sous forme de résumés textuels. Accepte un tableau de motifs glob de type MIME ou une fonction prédicat. La valeur par défaut correspond aux formats pris en charge par les principaux modèles de vision. (Default: `['image/png', 'image/jpeg', 'image/webp', 'application/pdf']`) **inlineLinks** (`InlineLinkEntry[]`): Convertit les URL trouvées dans le texte des messages en parties de fichier afin que le modèle puisse traiter le contenu lié. Chaque entrée correspond à un domaine. Désactivé par défaut. **tools** (`boolean`): Indique si getTools() renvoie les outils propres au canal (add\_reaction, remove\_reaction). Définissez sur false pour les modèles qui ne prennent pas en charge l’appel de fonctions. Les outils de canal ne sont jamais ajoutés automatiquement à l’agent ; transmettez-les explicitement avec tools: { ...channels.getTools() }. (Default: `true`) **state** (`StateAdapter`): Adaptateur d’état pour les abonnements et la déduplication. Utilise par défaut MastraStateAdapter, soutenu par le stockage de l’instance Mastra. Channels exige que le stockage soit configuré. (Default: `MastraStateAdapter (depuis le stockage Mastra)`) **userName** (`string`): Nom d’affichage du bot dans les messages de la plateforme. Utilise par défaut le name de l’agent, ou 'Mastra' si aucun nom n’est défini. (Default: ``le `name` de l’agent``) **threadContext** (`{ maxMessages?: number; addSystemMessage?: boolean }`): Détermine comment l’agent récupère le contexte du thread actuel. maxMessages contrôle le nombre de messages récents de la plateforme récupérés lors de la première mention (définissez sur 0 pour désactiver ; s’applique uniquement aux threads non-DM). addSystemMessage: false ignore le message système intégré qui indique à l’agent de quel canal ou de quelle plateforme provient une requête. (Default: `{ maxMessages: 10, addSystemMessage: true }`) **chatOptions** (`Omit`): Options supplémentaires transmises directement au Chat SDK. Utilisez-les pour une configuration avancée, telle que dedupeTtlMs, fallbackStreamingPlaceholderText, lockScope et messageHistory. **resolveResourceId** (`(ctx: ResolveResourceIdContext) => string | Promise`): Détermine quel resourceId possède la mémoire au niveau de la ressource pour un thread de canal, indépendamment de l’expéditeur du message. S’exécute uniquement à la création d’un thread ; les threads réutilisés conservent leur propriétaire enregistré et n’appellent jamais le hook. Renvoyez ctx.defaultResourceId (${platform}:${message.author.userId}) pour conserver le comportement intégré. **resolveThreadId** (`(ctx: ResolveThreadIdContext) => string | Promise`): Détermine l’identifiant interne de thread Mastra d’un thread de canal. S’exécute après resolveResourceId, avec le propriétaire résolu dans le contexte, et uniquement à la création d’un thread ; les threads réutilisés conservent leur identifiant enregistré et n’appellent jamais le hook. L’identifiant renvoyé doit être unique dans le magasin de mémoire ; en cas de collision, un identifiant généré est utilisé. Renvoyez ctx.defaultThreadId (un UUID aléatoire) pour conserver le comportement intégré. **waitUntil** (`(promise: Promise) => void`): Fonction waitUntil de la plateforme. Requise sur Vercel pour que les exécutions d’agents en arrière-plan continuent après que le webhook a renvoyé 200. Sur Vercel, transmettez waitUntil depuis @vercel/functions. Cloudflare Workers et Netlify Functions sont détectés automatiquement depuis le contexte de la requête. AWS Lambda n’a pas besoin de waitUntil, car il attend naturellement que la boucle d’événements se vide. **resolveWaitUntil** (`(c: Context) => ((promise: Promise) => void) | undefined`): Résolveur pour les environnements d’exécution où waitUntil se trouve dans le contexte de requête Hono, mais n’est pas pris en charge par l’assistant intégré. Ordre de résolution : waitUntil seul → resolveWaitUntil(c) → valeur par défaut (Cloudflare Workers, Netlify). ## Options par adaptateur Enveloppez un adaptateur dans un objet `ChannelAdapterConfig` pour définir des options par adaptateur : ```typescript import { Agent } from '@mastra/core/agent' import { createDiscordAdapter } from '@chat-adapter/discord' import { createSlackAdapter } from '@chat-adapter/slack' const agent = new Agent({ id: 'example', name: 'Example', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { discord: { adapter: createDiscordAdapter(), toolDisplay: 'text', cors: { origin: ['https://customer-saas.example'], credentials: true, }, gateway: false, }, slack: createSlackAdapter(), // Plain adapter uses defaults }, }, }) ``` **adapter** (`Adapter`): Instance de l’adaptateur Chat SDK pour cette plateforme. **gateway** (`boolean`): Démarre un écouteur WebSocket Gateway persistant pour recevoir les DM, les @mentions et les réactions. Définissez sur false pour les déploiements serverless qui n’ont besoin que d’interactions basées sur des webhooks. (Default: `true`) **cards** (`boolean`): \*\*Obsolète\*\* — utilisez plutôt toolDisplay. Lorsque toolDisplay n’est pas défini, cards: true correspond à toolDisplay: "cards" et cards: false à toolDisplay: "text". Les IDE affichent ce champ barré ; le comportement à l’exécution est préservé. **cors** (`CorsOptions`): Configuration CORS pour cette route de webhook d’adaptateur. Utilisez-la pour les adaptateurs de canal exécutés dans un navigateur et nécessitant des identifiants inter-origines. **formatError** (`(error: Error) => PostableMessage`): Remplace la façon dont les erreurs sont rendues dans le chat. Renvoyez un message convivial plutôt que d’exposer l’erreur brute. (Default: `"❌ Erreur : "`) **formatToolCall** (`(args: { toolName: string; args: unknown; result: unknown; isError: boolean }) => PostableMessage | null`): \*\*Obsolète\*\* — utilisez plutôt toolDisplay (sous forme de fonction). Lorsqu’il est défini, s’exécute comme un ToolDisplayFn qui ne se déclenche que sur les événements result/error ; les événements running et approval ne produisent aucun rendu. Mutuellement exclusif avec toolDisplay au niveau du type. **streaming** (`boolean | { updateIntervalMs?: number }`): Diffuse les deltas de texte de l’agent vers le canal au fur et à mesure de leur génération, plutôt que de les mettre en mémoire tampon et de publier une fois par étape. Exige que l’adaptateur sous-jacent prenne en charge le streaming avec publication et modification. Slack utilise true par défaut ; les autres adaptateurs utilisent false. (Default: `false (true pour Slack)`) **textFormat** (`'markdown' | 'plain'`): Dialecte du texte de réponse final de l’agent. 'markdown' (valeur par défaut) publie les réponses en Markdown : les adaptateurs avec un rendu Markdown natif (Slack) l’affichent directement, les autres le convertissent au format de leur plateforme. 'plain' publie les réponses sous forme de texte brut littéral et rétablit le comportement antérieur à Markdown pour les agents invités à produire un dialecte de plateforme tel que Slack mrkdwn. S’applique uniquement au texte de réponse final ; les cartes d’outils, messages d’erreur et avis de déclenchement ne sont pas affectés. Le streaming natif est toujours en Markdown, quel que soit ce paramètre. (Default: `'markdown'`) **toolDisplay** (`'cards' | 'text' | 'timeline' | 'grouped' | 'hidden' | ToolDisplayFn`): Détermine le rendu des appels d’outils dans le canal. "cards" publie des cartes Block Kit riches par outil pour l’exécution et le résultat. "text" publie le même cycle de vie en texte brut (sans Block Kit). "timeline" et "grouped" diffusent l’état des outils sous forme de blocs task\_update en ligne (nécessite streaming: true ; Slack uniquement pour le moment — les autres adaptateurs peuvent afficher un espace réservé). "hidden" exécute les outils silencieusement. Transmettez une fonction pour afficher vous-même les événements d’outils ; renvoyez { kind: "post", message } pour une publication/modification distincte, { kind: "stream", chunk } pour envoyer un élément au widget de streaming, ou undefined pour ignorer le rendu de cet événement. Ajoutez openIfEmpty: false à un résultat de streaming lorsque son bloc ne doit s’appliquer qu’à une session de streaming active. Les invites d’approbation/de refus s’affichent toujours comme une carte distincte, quel que soit le mode. (Default: `'cards' ('grouped' pour Slack)`) **typingStatus** (`boolean | ((chunk: AgentChunkType, ctx: TypingStatusContext) => string | false | null | undefined | void)`): Contrôle l’indicateur de saisie de la plateforme. true utilise les valeurs par défaut intégrées (is typing… pour le texte, is calling {tool}… pour un appel d’outil, is waiting for approval… pour une approbation d’appel d’outil). false supprime entièrement l’indicateur de saisie — utile lorsqu’un widget de streaming en direct (par ex. toolDisplay: "grouped" dans Slack) indique déjà la progression. Transmettez une fonction pour définir un texte d’état personnalisé par bloc ; renvoyez une chaîne pour définir l’état, ou false/null/undefined pour le laisser inchangé. Composez avec defaultTypingStatus (exporté depuis @mastra/core/channels) pour revenir aux valeurs par défaut pour les blocs que vous ne gérez pas. (Default: `true`) ## Modes d’affichage des outils `toolDisplay` contrôle le rendu des appels d’outils dans le chat. La valeur par défaut, `'cards'`, publie une carte « Running… » par outil et la modifie avec le résultat, conformément au comportement des versions précédentes. `'text'` suit le même cycle de vie, mais sans Block Kit enrichi ; il est utile pour les plateformes qui n’affichent pas bien les cartes. `'timeline'` et `'grouped'` diffusent l’état des outils sous forme de blocs `task_update` en ligne à côté du texte de l’agent. Ces modes nécessitent `streaming: true` et reposent sur l’adaptateur de chat pour afficher les blocs. Slack prend les deux en charge nativement ; les autres adaptateurs peuvent afficher un espace réservé jusqu’à leur prise en charge. Si `streaming` est désactivé, le canal journalise un avertissement unique et revient à `'cards'`. `'hidden'` exécute les outils silencieusement. Seul l’état de saisie indique le travail en cours. Transmettez une fonction à `toolDisplay` pour un rendu entièrement personnalisé. La fonction reçoit un `ToolDisplayEvent` (`running` / `result` / `error` / `approval`) et un `ToolDisplayContext` (`{ mode, platform }`) ; renvoyez `{ kind: 'post', message }` pour une publication/modification distincte, `{ kind: 'stream', chunk }` pour envoyer un élément au widget de streaming actif, ou `undefined` pour ignorer le rendu de cet événement. Par défaut, un résultat de streaming ouvre une session de streaming si aucune n’est active. Définissez `openIfEmpty: false` lorsque le bloc s’applique uniquement à une session existante. Mastra ignore le bloc si aucune session n’est active. Les canaux statiques ignorent cette option et conservent leur comportement de repli existant en texte brut. ```typescript toolDisplay: event => { if (event.kind !== 'running') return undefined return { kind: 'stream', chunk: { type: 'task_update', id: event.toolCallId, title: event.displayName, status: 'in_progress', }, openIfEmpty: false, } } ``` Les invites d’approbation/de refus (`requireApproval`) s’affichent toujours comme une carte distincte, quel que soit le mode, car les entrées de tâche en ligne ne peuvent pas contenir de boutons interactifs. ```typescript import { Agent } from '@mastra/core/agent' import { createSlackAdapter } from '@chat-adapter/slack' const agent = new Agent({ id: 'streaming-agent', name: 'Streaming Agent', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { slack: { adapter: createSlackAdapter(), streaming: true, // already the Slack default toolDisplay: 'timeline', }, }, }, }) ``` ## État de saisie personnalisé Transmettez une fonction à `typingStatus` pour personnaliser le texte d’état. La fonction est appelée une fois par bloc de streaming ; renvoyez une chaîne pour définir l’état, ou `false` / `null` / `undefined` pour laisser l’état actuel inchangé. Les valeurs de retour sont dédupliquées afin que la plateforme ne reçoive un appel que lorsque l’état change. `defaultTypingStatus` est exporté depuis `@mastra/core/channels` afin que vous puissiez revenir aux valeurs par défaut intégrées pour les blocs que vous ne gérez pas. ```typescript import { Agent } from '@mastra/core/agent' import { defaultTypingStatus } from '@mastra/core/channels' import { createDiscordAdapter } from '@chat-adapter/discord' const agent = new Agent({ id: 'custom-typing-agent', name: 'Custom Typing Agent', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { discord: { adapter: createDiscordAdapter(), typingStatus: (chunk, ctx) => { if (chunk.type === 'tool-call' && chunk.payload.toolName === 'searchDocs') { return 'is searching docs…' } return defaultTypingStatus(chunk, ctx) }, }, }, }, }) ``` ## Gestionnaires Remplacez les gestionnaires d’événements intégrés. Chaque gestionnaire peut être : - **Omis** : utilise le gestionnaire Mastra par défaut (transmet le message à l’agent et publie la réponse). - **`false`** : désactive entièrement le gestionnaire. - **Une fonction** `(thread, message, defaultHandler) => Promise` : encapsule ou remplace le gestionnaire par défaut. ```typescript import { Agent } from '@mastra/core/agent' import { createSlackAdapter } from '@chat-adapter/slack' const agent = new Agent({ id: 'custom-handler-agent', name: 'Custom Handler Agent', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { slack: createSlackAdapter(), }, handlers: { onMention: async (thread, message, defaultHandler) => { console.log('Received mention:', message.text) await defaultHandler(thread, message) }, onDirectMessage: false, }, }, }) ``` **onDirectMessage** (`ChannelHandler | false`): Appelé lorsque le bot reçoit un message direct. **onMention** (`ChannelHandler | false`): Appelé lorsque le bot est @mentionné dans un canal ou un thread. **onSubscribedMessage** (`ChannelHandler | false`): Appelé pour les messages des threads auxquels l’agent est abonné. Signature de la fonction `ChannelHandler` : ```typescript type ChannelHandler = ( thread: Thread, message: Message, defaultHandler: (thread: Thread, message: Message) => Promise, ctx: ChannelHandlerContext, ) => Promise type ChannelHandlerContext = { mastra?: Mastra requestContext: RequestContext } ``` `ctx.mastra` est l’instance `mastra` résolue ; un gestionnaire peut donc accéder au stockage ou à d’autres primitives enregistrées sans qu’un accesseur externe lui soit transmis : ```typescript onDirectMessage: async (thread, message, defaultHandler, ctx) => { const store = await ctx.mastra?.getStorage()?.getStore('memory') await defaultHandler(thread, message) } ``` `ctx.requestContext` est le [`RequestContext`](https://mastra.zisheng.pro/fr/docs/server/request-context) de l’exécution que ce message est sur le point de démarrer, créé à neuf pour chaque message. Écrivez-y avant d’appeler `defaultHandler` ; la valeur parvient à l’exécution avec les entrées de canal ajoutées ensuite par Mastra : ```typescript onDirectMessage: async (thread, message, defaultHandler, ctx) => { ctx.requestContext.set('locale', 'en-GB') await defaultHandler(thread, message) } ``` De cette manière, tout ce que l’exécution lit dans son contexte de requête peut être déterminé par message, comme l’utilisateur auquel correspond un expéditeur de plateforme. ## Résolution de l’identifiant de ressource Par défaut, le `resourceId` de mémoire d’un thread de canal est `${platform}:${message.author.userId}`. L’expéditeur possède la mémoire, délimitée par plateforme. Pour les applications avec une identité partagée, telle que l’authentification unique (SSO), cela sépare la mémoire : le même utilisateur obtient `feishu:user_123` dans un DM Feishu, mais `user_123` sur le Web. Transmettez `resolveResourceId` pour décider de la propriété de la mémoire indépendamment de l’expéditeur. Il s’exécute uniquement lors de la création d’un thread. Les threads réutilisés conservent leur `resourceId` enregistré et n’appellent jamais le hook ; les conversations existantes ne dépendent donc pas de la disponibilité du résolveur. Renvoyez `ctx.defaultResourceId` pour revenir au comportement intégré. ```typescript import { Agent } from '@mastra/core/agent' import { createSlackAdapter } from '@chat-adapter/slack' const agent = new Agent({ id: 'sso-agent', name: 'SSO Agent', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { slack: createSlackAdapter(), }, resolveResourceId: async ({ thread, message }) => { // DM: share resource-level memory with the web app by using the bare SSO id if (thread.isDM) { return await resolveSsoUserId(message) } // Group chat: the conversation owns the memory; the sender stays the actor return thread.channelId }, }, }) ``` `ResolveResourceIdContext` transmis à la fonction : **platform** (`string`): Nom de la plateforme (par ex. slack, discord). **thread** (`Thread`): Thread de canal dans lequel le message est arrivé. Utilisez thread.isDM pour distinguer les DM des threads de groupe ou de canal. **message** (`Message`): Message entrant. message.author.userId est l’acteur ou l’expéditeur, pas nécessairement le propriétaire de la mémoire. **defaultResourceId** (`string`): Valeur par défaut intégrée (${platform}:${message.author.userId}). Renvoyez-la pour conserver le comportement actuel. ## Résolution de l’identifiant de thread Par défaut, un nouveau thread de canal reçoit un UUID aléatoire comme identifiant de thread Mastra interne. Transmettez `resolveThreadId` pour choisir vous-même l’identifiant : par exemple, donnez au thread le même identifiant que la session à laquelle il appartient, conformément à la façon dont votre application nomme les threads qu’elle crée elle-même. Le hook s’exécute après `resolveResourceId`, ainsi le propriétaire résolu est disponible dans le contexte. Comme `resolveResourceId`, il s’exécute uniquement à la création d’un thread : les threads réutilisés conservent leur identifiant enregistré et n’appellent jamais le hook. L’identifiant renvoyé doit être unique dans le magasin de mémoire. S’il appartient déjà à un thread existant, Mastra journalise un avertissement et utilise un identifiant généré afin que le thread existant ne soit jamais écrasé. Renvoyez `ctx.defaultThreadId` pour conserver le comportement intégré. ```typescript import { Agent } from '@mastra/core/agent' import { createSlackAdapter } from '@chat-adapter/slack' const agent = new Agent({ id: 'session-agent', name: 'Session Agent', instructions: '...', model: 'openai/gpt-5.6-sol', channels: { adapters: { slack: createSlackAdapter(), }, // Owner: a session id resolved from the sender's linked account resolveResourceId: async ctx => resolveSessionId(ctx), // Thread id: align with the session id so app URLs that address // threads by session id resolve channel-created threads too resolveThreadId: ({ resourceId, defaultThreadId }) => { return isSessionId(resourceId) ? resourceId : defaultThreadId }, }, }) ``` `ResolveThreadIdContext` transmis à la fonction : **platform** (`string`): Nom de la plateforme (par ex. slack, discord). **thread** (`Thread`): Thread de canal dans lequel le message est arrivé. Utilisez thread.isDM pour distinguer les DM des threads de groupe ou de canal. **message** (`Message`): Message entrant. **resourceId** (`string`): Le resourceId de mémoire résolu auquel appartiendra le nouveau thread (après resolveResourceId). **defaultThreadId** (`string`): Valeur par défaut intégrée (un UUID aléatoire). Renvoyez-la pour conserver le comportement actuel. ## Médias intégrés Contrôle les types de pièces jointes (images, vidéo, PDF, etc.) envoyés au modèle sous forme de parties de fichier. Les types qui ne correspondent pas sont décrits sous forme de résumés textuels, afin que l’agent connaisse le fichier sans faire échouer les modèles qui refusent les types non pris en charge. La valeur par défaut (`['image/png', 'image/jpeg', 'image/webp', 'application/pdf']`) correspond aux formats pris en charge par les principaux modèles de vision. Remplacez `inlineMedia` pour étendre la liste (par ex. `['image/*', 'audio/*']`) ou la remplacer entièrement par une fonction prédicat. Motifs glob pris en charge : | Motif | Correspondances | | ----------------- | -------------------------------------------------------- | | `image/*` | Tous les types d’image (`image/png`, `image/jpeg`, etc.) | | `video/*` | Tous les types de vidéo | | `*` ou `*/*` | Tous les types | | `application/pdf` | Correspondance exacte du type | Pour les plateformes avec des CDN privés (par ex. Slack), les pièces jointes sont récupérées avec des identifiants authentifiés depuis le Chat SDK. Pour les plateformes avec des CDN publics (par ex. Discord), l’URL est transmise directement au modèle. ## Liens intégrés Convertit les URL trouvées dans le texte des messages en parties de fichier afin que le modèle puisse traiter le contenu lié au lieu de voir le texte brut de l’URL. Chaque entrée peut être une chaîne (motif de domaine) ou un objet avec un type MIME forcé. Les **entrées de chaîne** correspondent à un domaine et effectuent une requête HEAD pour détecter le Content-Type. Le type résolu est vérifié par rapport à `inlineMedia` et seuls les types correspondants deviennent des parties de fichier. Les **entrées d’objet** correspondent à un domaine et forcent un type MIME donné, sans effectuer la requête HEAD ni la vérification `inlineMedia`. Cela est utile pour des sites tels que YouTube, où une requête HEAD renvoie `text/html`, mais le modèle traite l’URL comme un contenu vidéo. ```typescript type InlineLinkEntry = | string // Domain pattern (HEAD determines mime type) | { match: string; mimeType: string } // Domain + forced mime type (skips HEAD) ``` ## Ressources associées - [Présentation de Channels](https://mastra.zisheng.pro/fr/docs/capabilities/channels/overview) : concepts, démarrage rapide et configuration des plateformes - [Classe Agent](https://mastra.zisheng.pro/fr/reference/agents/agent) : paramètres et méthodes du constructeur - [Adaptateurs Chat SDK](https://chat-sdk.dev/adapters) : configuration des adaptateurs et des plateformes