> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # AgentController > **Beta:** La fonctionnalité [`AgentController`](https://mastra.zisheng.pro/fr/reference/agent-controller/agent-controller-class) est en version bêta. Elle peut subir des changements incompatibles dans les versions mineures jusqu’à sa sortie de la phase bêta. `AgentController` est un environnement d’exécution partagé pour les applications d’agents interactives. Il coordonne les modes, les modèles, le stockage, les Workspace, l’approbation des outils, les sous-agents et les canaux. Chaque utilisateur ou tâche active travaille dans une [`Session`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) isolée. [Mastra Code](https://code.mastra.ai) est l’implémentation phare d’AgentController. Cet agent de programmation en ligne de commande prend en charge plusieurs modèles, les conversations persistantes et les flux de travail qui séparent planification et exécution. Consultez [Créer un agent de programmation](https://mastra.zisheng.pro/fr/guides/guide/coding-agent) pour suivre un guide détaillé. ## Quand utiliser AgentController Utilisez AgentController lorsque votre application nécessite : - Plusieurs modes d’agent partageant un même fil de discussion (par exemple, planification → implémentation → révision) - Une couche de contrôle entre votre interface utilisateur et la boucle de l’agent (changement de modèle, persistance de l’état et gestion des fils de discussion) - Des processus d’approbation des outils et des politiques d’autorisation pour intégrer une validation humaine - L’orchestration de sous-agents afin de déléguer des sous-tâches ciblées avec un ensemble d’outils restreint - Des fils de discussion persistants et certains paramètres associés conservés après les redémarrages, avec un état actif isolé pour chaque Session Vous pourriez assembler vous-même tous ces éléments à partir de la [classe Agent](https://mastra.zisheng.pro/fr/docs/agents/overview), qui expose l’intégralité de la boucle de l’agent, ses outils et sa mémoire. AgentController fournit des choix par défaut structurants pour une session continue dans laquelle l’agent agit comme un collaborateur plutôt que comme un point de terminaison à usage unique. Utilisez directement la classe Agent si vous souhaitez un contrôle total ou un appel de type requête-réponse. Choisissez AgentController si vous souhaitez bénéficier du modèle de session collaborative sans avoir à construire l’environnement d’exécution correspondant. ## Démarrage rapide Créez l’[`Agent`](https://mastra.zisheng.pro/fr/reference/agents/agent) sous-jacent, le stockage et le [`Workspace`](https://mastra.zisheng.pro/fr/reference/workspace/workspace-class). Appelez [`controller.init()`](https://mastra.zisheng.pro/fr/reference/agent-controller/agent-controller-class) une seule fois, puis utilisez [`controller.createSession()`](https://mastra.zisheng.pro/fr/reference/agent-controller/agent-controller-class) pour créer une Session. Abonnez-vous avec [`session.subscribe()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session), puis envoyez une tâche avec [`session.sendMessage()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript import { Agent } from '@mastra/core/agent' import { AgentController } from '@mastra/core/agent-controller' import { LocalFilesystem, Workspace } from '@mastra/core/workspace' import { LibSQLStore } from '@mastra/libsql' const agent = new Agent({ id: 'assistant', name: 'Assistant', instructions: 'Help the user plan and complete tasks.', model: 'openai/gpt-5.6-sol', }) const controller = new AgentController({ id: 'assistant-controller', agent, storage: new LibSQLStore({ id: 'agent-controller-storage', url: 'file:./mastra.db', }), workspace: new Workspace({ id: 'assistant-workspace', filesystem: new LocalFilesystem({ basePath: './workspace' }), }), modes: [ { id: 'plan', name: 'Plan', metadata: { default: true }, instructions: 'Reason about the task before making changes.', }, { id: 'build', name: 'Build', instructions: 'Implement the approved plan.', }, ], }) await controller.init() const session = await controller.createSession({ resourceId: 'user-123', }) const unsubscribe = session.subscribe(event => { if (event.type === 'message_update') { console.log(event.message) } }) await session.sendMessage({ content: 'Plan a small TypeScript CLI.' }) unsubscribe() ``` Réutilisez le même contrôleur pour plusieurs Sessions. Ne stockez pas de Session courante dans le contrôleur et ne transmettez pas les tâches par des méthodes de messagerie au niveau du contrôleur. ## Comprendre le modèle d’exécution Le contrôleur, la Session et le fil de discussion ont des cycles de vie différents : - **Contrôleur** : un environnement partagé pour la configuration et les services d’exécution. Initialisez-le une seule fois, puis réutilisez-le. - **Session** : un environnement d’exécution actif et isolé pour un utilisateur, une tâche ou un périmètre de travail concurrent. Elle possède le mode, le modèle et l’état actifs, le bus d’événements, l’état d’exécution, les autorisations accordées et l’association au fil de discussion courant. - **Fil de discussion** : une conversation stockée qui contient des messages et des paramètres associés. Si vous configurez le stockage, les fils de discussion peuvent subsister après la recréation du contrôleur et du processus. Une Session représente un état actif. Le contenu arbitraire de [`session.state`](https://mastra.zisheng.pro/fr/reference/agent-controller/session), les autorisations accordées, les approbations en attente et les exécutions actives ne subsistent pas automatiquement après la recréation du processus. Le stockage peut conserver les messages du fil de discussion et certains de ses paramètres, notamment le mode et le modèle choisi pour chaque mode. ## Sessions et fils de discussion `createSession()` récupère ou crée une Session à partir de `resourceId` et, éventuellement, de `scope` : ```typescript const webSession = await controller.createSession({ resourceId: 'user-123', scope: 'web', }) const sameWebSession = await controller.createSession({ resourceId: 'user-123', scope: 'web', }) const workerSession = await controller.createSession({ resourceId: 'user-123', scope: 'background-worker', }) console.log(webSession === sameWebSession) // true console.log(webSession === workerSession) // false ``` Les Sessions dont les portées diffèrent possèdent des bus d’événements, des boucles d’exécution, des états, des sélections de mode et de modèle ainsi que des associations au fil de discussion courant distincts. Leurs fils de discussion stockés restent toutefois rattachés au même `resourceId`. Transmettez `threadId` lorsque l’environnement doit associer la Session à un fil de discussion précis. Le contrôleur bascule vers le fil de discussion existant ou, s’il n’existe pas, le crée avec cet ID. Ce comportement s’applique également lorsque `createSession()` renvoie une Session mise en cache : ```typescript const session = await controller.createSession({ resourceId: 'user-123', scope: 'web', threadId: 'support-ticket-42', }) ``` Utilisez [`session.thread.create()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) et [`session.thread.switch()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) pour faire passer une Session active d’une conversation à une autre. ## Changer de mode et de modèle Les modes modifient les instructions et les outils utilisés par l’agent sous-jacent partagé sans remplacer la Session ni le fil de discussion. Configurez dans le contrôleur les outils propres à chaque mode et leur visibilité : ```typescript const modes = [ { id: 'plan', name: 'Plan', metadata: { default: true }, instructions: 'Investigate the task and propose a plan.', additionalTools: { searchDocs }, availableTools: ['searchDocs', 'submit_plan'], transitionsTo: 'build', }, { id: 'build', name: 'Build', instructions: 'Implement the approved plan.', }, ] ``` `tools` et `additionalTools` sont deux options mutuellement exclusives pour ajouter des outils propres à un mode. Lorsque le contrôleur possède un agent sous-jacent partagé, chacune de ces options ajoute les outils concernés à ceux de l’agent. Utilisez `availableTools` pour limiter les noms d’outils finalement exposés dans un mode. Les refus définis par les autorisations restent prioritaires sur cette liste d’autorisation. Changez le mode de la Session active avec [`session.mode.switch()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session). Consultez le mode actif avec [`session.mode.get()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) ou [`session.mode.resolve()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript await session.mode.switch({ modeId: 'build' }) console.log(session.mode.get()) // "build" console.log(session.mode.resolve().instructions) ``` Changez de modèle indépendamment avec [`session.model.switch()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session), puis consultez la sélection active avec [`session.model.get()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session). Les sélections propres au fil de discussion sont stockées par mode et restaurées lorsque la Session revient à ce mode : ```typescript await session.model.switch({ modelId: 'anthropic/claude-sonnet-4-6', scope: 'thread', }) console.log(session.model.get()) ``` Utilisez `scope: 'global'` pour une sélection conservée en mémoire qui ne doit pas être inscrite dans les paramètres du fil de discussion. ## Gérer les fils de discussion et l’état Répertoriez les conversations stockées avec [`session.thread.list()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript const thread = await session.thread.create({ title: 'Release planning' }) const threads = await session.thread.list() await session.thread.switch({ threadId: thread.id }) console.log(threads.length) ``` Utilisez `session.state` pour l’état actif structuré associé à la Session. Consultez-le avec [`session.state.get()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) et mettez-le à jour avec [`session.state.set()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session). Définissez `stateSchema` et `initialState` dans le contrôleur si vous avez besoin d’une validation et de valeurs par défaut : ```typescript console.log(session.state.get()) await session.state.set({ activeProject: 'docs-site' }) ``` `session.state.get()` renvoie un instantané. `set()` valide la mise à jour et la fusionne dans l’état de la Session. Considérez cet état comme des données actives de la Session, sauf si votre environnement les conserve et les restaure explicitement. ## Approuver les outils et reprendre les suspensions Les politiques d’autorisation déterminent si un outil est autorisé, refusé ou soumis à l’interface utilisateur pour approbation. Associez les outils personnalisés à des catégories avec `toolCategoryResolver` dans le contrôleur : ```typescript const controller = new AgentController({ toolCategoryResolver: toolName => { if (toolName === 'delete_project') return 'execute' return null }, }) ``` Configurez les politiques par catégorie avec [`session.permissions.setForCategory()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) et celles propres aux outils avec [`session.permissions.setForTool()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript await session.permissions.setForCategory({ category: 'execute', policy: 'ask', }) await session.permissions.setForTool({ toolName: 'delete_project', policy: 'deny', }) ``` Lorsqu’une politique aboutit à `ask`, abonnez-vous à l’événement d’approbation et renvoyez la décision de l’utilisateur avec [`session.respondToToolApproval()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript session.subscribe(event => { if (event.type === 'tool_approval_required') { session.respondToToolApproval({ toolCallId: event.toolCallId, decision: 'approve', }) } }) ``` La décision `always_allow_category` autorise la catégorie d’outils pour toute la durée restante de la Session active. Les autorisations accordées dans une Session ne sont pas des autorisations persistantes au niveau du processus. Les outils interactifs tels que [`ask_user`](https://mastra.zisheng.pro/fr/reference/tools/ask-user-tool) et [`submit_plan`](https://mastra.zisheng.pro/fr/reference/tools/submit-plan-tool) utilisent plutôt des suspensions d’outil qui peuvent être reprises. Reprenez leur exécution avec [`session.respondToToolSuspension()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript session.subscribe(event => { if (event.type === 'tool_suspended' && event.toolName === 'ask_user') { void session.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: 'Use SQLite.', }) } }) ``` Pour `submit_plan`, reprenez l’exécution avec `{ action: 'approved' }` ou `{ action: 'rejected', feedback }`. Avant la poursuite de l’exécution, un plan approuvé peut déclencher le passage au mode configuré par `transitionsTo`. ## Déléguer à des sous-agents Configurez les types de sous-agents disponibles dans le contrôleur. L’outil intégré `subagent` peut ensuite s’appuyer sur ces définitions pour déléguer des tâches ciblées : ```typescript const controller = new AgentController({ tools: { searchDocs, }, subagents: [ { id: 'code-reviewer', name: 'Code reviewer', description: 'Review a change for correctness and regressions.', instructions: 'Inspect the change and report actionable findings.', allowedControllerTools: ['searchDocs'], allowedWorkspaceTools: ['view', 'find_files'], defaultModelId: 'openai/gpt-5-mini', }, ], }) ``` Un sous-agent standard démarre avec les instructions configurées et l’ensemble d’outils restreint qui lui est attribué. Définissez `forked: true` lorsque l’enfant doit cloner le fil de discussion parent et s’exécuter avec les instructions et les outils de l’agent parent. Les sous-agents dérivés conservent le préfixe de l’invite parente, ignorent les instructions, les outils, les listes d’autorisation et le modèle par défaut de leur définition, et nécessitent que la mémoire soit configurée dans le contrôleur. Utilisez [`session.subagents.model.set()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) pour stocker un modèle de sous-agent par défaut ou un modèle propre à un type d’agent. Consultez la sélection avec [`session.subagents.model.get()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript await session.subagents.model.set({ modelId: 'openai/gpt-5-mini', }) await session.subagents.model.set({ agentType: 'code-reviewer', modelId: 'anthropic/claude-sonnet-4-6', }) const reviewerModel = session.subagents.model.get({ agentType: 'code-reviewer', }) ``` Ces sélections sont enregistrées dans les paramètres du fil de discussion. La sélection propre à un type d’agent est prioritaire sur le modèle de sous-agent par défaut de la Session. ## Connecter des canaux de discussion Transmettez les adaptateurs de canaux au contrôleur, puis enregistrez celui-ci dans une instance de [`Mastra`](https://mastra.zisheng.pro/fr/reference/core/mastra-class) : ```typescript import { Mastra } from '@mastra/core' import { AgentController } from '@mastra/core/agent-controller' import { createSlackAdapter } from '@chat-adapter/slack' const controller = new AgentController({ id: 'support-controller', agent, storage, workspace, modes, channels: { adapters: { slack: createSlackAdapter(), }, resolveResourceId: ({ thread, message, defaultResourceId }) => { if (thread.isDM) return message.author.userId return defaultResourceId }, onSessionStart: async ({ session, thread }) => { const plan = await billing.planFor(thread.resourceId) await session.model.switch({ modelId: plan.modelId }) }, }, }) export const mastra = new Mastra({ agentControllers: { controller }, storage, }) ``` Faites pointer le webhook de chaque plateforme vers la route propre au contrôleur : ```text /api/agent-controllers//channels//webhook ``` Chaque fil de discussion externe correspond à une Session du contrôleur et à un fil de discussion Mastra. Par défaut, les nouvelles sessions utilisent un ID de ressource dérivé de l’ID du fil de discussion fourni par l’adaptateur et préfixé par `channel:`. Utilisez `resolveResourceId` pour associer les messages directs à un utilisateur existant de l’application ou choisir un autre propriétaire de la mémoire. Cette fonction de rappel ne concerne que les nouveaux fils de discussion ; un fil existant conserve l’ID de ressource stocké. Les sessions de canal sont créées par le contrôleur et non par votre code : configurez-les donc dans `onSessionStart`. Cette fonction de rappel s’exécute une seule fois par session, après l’association de celle-ci au fil de discussion correspondant et avant le traitement du premier message. Utilisez-la pour appliquer un modèle, des paramètres de mémoire ou un état de session dont la session de canal ne disposerait pas autrement. Les messages suivants du même fil réutilisent la session sans rappeler cette fonction. Les erreurs sont consignées puis absorbées, afin qu’une session qui ne peut pas être configurée réponde tout de même au message. Les sessions de canal du contrôleur et l’état d’approbation automatique sont conservés en mémoire : utilisez donc un serveur à longue durée de vie. Les approbations en attente et l’état actif de la Session ne subsistent pas après le redémarrage du processus. Les adaptateurs qui ne peuvent pas afficher de commandes d’approbation exécutent automatiquement les outils sans demander d’approbation, afin que l’exécution ne reste pas suspendue. Consultez la page [Canaux](https://mastra.zisheng.pro/fr/docs/capabilities/channels/overview) pour configurer les adaptateurs et les webhooks propres à chaque plateforme. ## Connecter une interface utilisateur Abonnez-vous aux événements de la Session pour recevoir les mises à jour incrémentielles. Lorsque l’interface utilisateur a besoin d’un instantané complet pour le rendu, consultez l’état d’affichage agrégé avec [`session.displayState.get()`](https://mastra.zisheng.pro/fr/reference/agent-controller/session) : ```typescript const unsubscribe = session.subscribe(event => { if (event.type === 'display_state_changed') { render(event.displayState) } }) render(session.displayState.get()) // Call when the UI disconnects. unsubscribe() ``` Les abonnements sont isolés par Session. Les événements d’une autre Session du même contrôleur ne sont pas transmis à cet écouteur. Consultez le guide [Créer un agent de programmation](https://mastra.zisheng.pro/fr/guides/guide/coding-agent) pour découvrir un exemple complet d’interface utilisateur en mode texte. ## Voir aussi - [Agents](https://mastra.zisheng.pro/fr/docs/agents/overview) - [Workspace](https://mastra.zisheng.pro/fr/docs/workspace/overview) - [Mémoire observationnelle](https://mastra.zisheng.pro/fr/docs/memory/observational-memory) - [Canaux](https://mastra.zisheng.pro/fr/docs/capabilities/channels/overview)