> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Créer un agent de programmation Dans ce guide, vous allez créer une petite application d’agent de programmation du même type que Mastra Code, Claude Code ou Codex. Vous créerez l’agent de programmation avec `buildBasePrompt()` et `createCodingAgent()`, l’encapsulerez dans un `AgentController` pour gérer les sessions interactives et l’approbation des outils, puis exécuterez le contrôleur dans une interface de terminal conçue avec pi-tui. La vidéo ci-dessous montre en action l’agent de programmation que vous allez créer. ## Prérequis - Node.js `v22.19.0` ou version ultérieure installé - Une clé API provenant d’un [fournisseur de modèles](https://mastra.zisheng.pro/fr/models) pris en charge - Un projet Mastra existant. Si nécessaire, suivez le [guide d’installation](https://mastra.zisheng.pro/fr/guides/getting-started/quickstart). ## Installer les dépendances du terminal Installez [pi-tui](https://github.com/earendil-works/pi/tree/main/packages/tui) et `tsx` : **npm**: ```bash npm install @earendil-works/pi-tui npm install --save-dev tsx ``` **pnpm**: ```bash pnpm add @earendil-works/pi-tui pnpm add --save-dev tsx ``` **Yarn**: ```bash yarn add @earendil-works/pi-tui yarn add --dev tsx ``` **Bun**: ```bash bun add @earendil-works/pi-tui bun add --dev tsx ``` pi-tui fournit le moteur de rendu du terminal et l’éditeur de saisie. `tsx` exécute directement le point d’entrée TypeScript. ## Créer l’agent de programmation Créez `src/mastra/agents/coding-agent.ts`. Le prompt décrit le projet actuel et associe les noms d’outils génériques du prompt aux outils fournis par le Workspace par défaut. ```typescript import { basename } from 'node:path' import { buildBasePrompt, createCodingAgent } from '@mastra/core/coding-agent' export const projectPath = process.cwd() const model = 'openai/gpt-5.6-sol' const instructions = buildBasePrompt({ projectPath, projectName: basename(projectPath), platform: process.platform, date: new Date().toISOString().slice(0, 10), mode: 'build', modelId: model, productName: 'My Coding Agent', coAuthorName: 'My Coding Agent', coAuthorEmail: 'coding-agent@example.com', toolGuidance: `# Workspace tools - Use mastra_workspace_read_file for view. - Use mastra_workspace_list_files for find_files. - Use mastra_workspace_grep for search_content. - Use mastra_workspace_execute_command for execute_command. - Use mastra_workspace_write_file, mastra_workspace_edit_file, and mastra_workspace_file_stat for writing, editing, and inspecting file metadata. - Use only the workspace tools provided to you. Do not attempt unavailable capabilities.`, }) export const codingAgent = createCodingAgent({ id: 'coding-agent', name: 'Coding Agent', model, instructions, basePath: projectPath, }) ``` Remplacez les valeurs d’identité visuelle par le nom de votre agent et les informations sur le coauteur. `createCodingAgent()` fournit un système de fichiers local et un Workspace exécuté dans une sandbox, ainsi que des paramètres par défaut permettant de récupérer après des erreurs temporaires du fournisseur. `basePath` limite la portée des outils du système de fichiers et définit le répertoire de travail initial des commandes. Toute configuration transmise à la fabrique prévaut sur ses valeurs par défaut. Le sandbox local par défaut exécute les commandes directement sur l’hôte, sans isolation. `basePath` ne constitue donc pas une frontière de sécurité du système d’exploitation. Cet exemple ajoute dans le terminal une approbation pour chaque appel d’outil, mais vous ne devez malgré tout l’exécuter que sur un projet local de confiance. ## Enregistrer l’agent de programmation Enregistrez l’Agent renvoyé comme n’importe quel autre Agent Mastra dans `src/mastra/index.ts`. Cet enregistrement rend également l’Agent sous-jacent disponible dans Studio et via le serveur Mastra. ```typescript import { Mastra } from '@mastra/core/mastra' import { codingAgent } from './agents/coding-agent' export const mastra = new Mastra({ agents: { codingAgent }, }) ``` ## Tester l’agent de programmation Avant d’ajouter l’interface de terminal, vérifiez l’Agent sous-jacent dans Studio. Lorsque le serveur de développement démarre, son répertoire de travail est `src/mastra/public`. Ajoutez-y donc un fichier non sensible que l’Agent pourra examiner : ```md # Project notes Name: Acme support portal Status: In development Owner: Platform team ``` Démarrez le serveur de développement : **npm**: ```bash npm run dev ``` **pnpm**: ```bash pnpm run dev ``` **Yarn**: ```bash yarn dev ``` **Bun**: ```bash bun run dev ``` Ouvrez [Studio](https://mastra.zisheng.pro/fr/docs/studio/overview), sélectionnez **Coding Agent**, puis saisissez : ```text Inspect project-notes.md and report the project name, status, and owner. Do not modify files. ``` La réponse doit identifier le portail d’assistance Acme et décrire son état de développement. Elle doit indiquer que l’équipe Platform est responsable du projet et laisser le fichier inchangé. La formulation peut varier selon le modèle. ## Créer le contrôleur de l’Agent Créez `src/mastra/coding-agent-controller.ts`. Le contrôleur gère la session interactive, expose les événements de l’interface utilisateur et suspend les outils du Workspace afin d’obtenir leur approbation. ```typescript import { AgentController } from '@mastra/core/agent-controller' import { codingAgent, projectPath } from './agents/coding-agent' export async function createCodingAgentSession() { const workspace = await codingAgent.getWorkspace() if (!workspace) { throw new Error('The coding agent requires a workspace.') } const controller = new AgentController({ id: 'coding-agent-controller', agent: codingAgent, workspace, modes: [{ id: 'build', name: 'Build', metadata: { default: true } }], disableBuiltinTools: [ 'ask_user', 'submit_plan', 'task_write', 'task_update', 'task_complete', 'task_check', 'subagent', ], }) await controller.init() const session = await controller.createSession({ id: 'local-session', ownerId: 'local-user', resourceId: projectPath, }) return { controller, session } } ``` Cet exemple utilise un seul mode et désactive les outils intégrés supplémentaires du contrôleur afin que l’interface utilisateur d’introduction puisse se concentrer sur l’exécution dans le Workspace. Cette configuration simplifiée est destinée à ce tutoriel. Dans une application de production, activez les outils intégrés dont votre produit a besoin et implémentez leurs flux d’interface utilisateur : les outils interactifs comme `ask_user` et `submit_plan` restent suspendus jusqu’à ce que votre interface les reprenne, tandis que les outils de tâche et de sous-agent possèdent leurs propres événements de cycle de vie. Consultez la section sur [l’approbation et la suspension des outils](https://mastra.zisheng.pro/fr/docs/harness/agent-controller). L’exemple omet également le stockage : la conversation ne dure donc que le temps du processus en cours. Vous pourrez ajouter un stockage ultérieurement lorsque vous souhaiterez reprendre des sessions. ## Créer l’interface utilisateur du terminal Créez `src/coding-agent-tui.ts`. L’interface utilisateur affiche les mises à jour des messages de l’assistant ainsi que l’activité des outils. Elle demande également à l’utilisateur d’approuver ou de refuser chaque appel d’outil du Workspace. ```typescript import { pathToFileURL } from 'node:url' import { Editor, matchesKey, ProcessTerminal, Text, TUI, type EditorTheme, type Terminal, } from '@earendil-works/pi-tui' import { createCodingAgentSession } from './mastra/coding-agent-controller' const plain = (text: string) => text const editorTheme: EditorTheme = { borderColor: plain, selectList: { selectedPrefix: plain, selectedText: plain, description: plain, scrollInfo: plain, noMatch: plain, }, } function getText(message: { content: Array<{ type: string; text?: string }> }) { return message.content .filter(part => part.type === 'text') .map(part => part.text ?? '') .join('') } export async function startCodingAgentTui(terminal: Terminal = new ProcessTerminal()) { const { controller, session } = await createCodingAgentSession() const tui = new TUI(terminal) const output = new Text('Ask me to inspect or change this project.', 1, 0) const editor = new Editor(tui, editorTheme) let busy = false let pendingApproval: { toolCallId: string; toolName: string } | undefined const showError = (error: unknown) => { output.setText(`Error: ${error instanceof Error ? error.message : String(error)}`) busy = false pendingApproval = undefined tui.requestRender() } const unsubscribe = session.subscribe(event => { if (event.type === 'message_update' && event.message.role === 'assistant') { output.setText(getText(event.message)) } else if (event.type === 'tool_start') { output.setText(`Running ${event.toolName}...`) } else if (event.type === 'tool_approval_required') { pendingApproval = { toolCallId: event.toolCallId, toolName: event.toolName } output.setText(`Allow ${event.toolName}? Enter y or n.`) } else if (event.type === 'agent_end') { busy = false } else if (event.type === 'error') { showError(event.error) return } tui.requestRender() }) editor.onSubmit = value => { if (pendingApproval) { const answer = value.trim().toLowerCase() if (answer !== 'y' && answer !== 'n') { output.setText(`Allow ${pendingApproval.toolName}? Enter y or n.`) tui.requestRender() return } const approval = pendingApproval pendingApproval = undefined session.respondToToolApproval({ toolCallId: approval.toolCallId, decision: answer === 'y' ? 'approve' : 'decline', }) return } if (busy || !value.trim()) return busy = true output.setText('Thinking...') tui.requestRender() void session.sendMessage({ content: value.trim() }).catch(showError) } tui.addChild(new Text('My Coding Agent', 1, 0)) tui.addChild(output) tui.addChild(editor) tui.setFocus(editor) let stopPromise: Promise | undefined let removeInputListener = () => {} const stop = () => { stopPromise ??= (async () => { process.off('SIGINT', handleExit) removeInputListener() session.abort() unsubscribe() tui.stop() await controller.destroy() })() return stopPromise } const handleExit = () => { void stop().catch(error => { console.error(error) process.exitCode = 1 }) } removeInputListener = tui.addInputListener(data => { if (!matchesKey(data, 'ctrl+c')) return handleExit() return { consume: true } }) process.once('SIGINT', handleExit) tui.start() return { stop } } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { await startCodingAgentTui() } ``` Le paramètre facultatif `Terminal` permet d’effectuer des tests automatisés, tandis que `ProcessTerminal` est utilisé lors de l’exécution normale. L’interface utilisateur n’affiche volontairement que la réponse la plus récente. La `Session` conserve néanmoins le contexte de la conversation pour les prompts de suivi. ## Exécuter l’agent de programmation Démarrez l’application de terminal depuis la racine du projet afin que `process.cwd()` pointe vers le projet que l’Agent doit utiliser : **npm**: ```bash npx tsx src/coding-agent-tui.ts ``` **pnpm**: ```bash pnpm dlx tsx src/coding-agent-tui.ts ``` **Yarn**: ```bash yarn dlx tsx src/coding-agent-tui.ts ``` **Bun**: ```bash bun x tsx src/coding-agent-tui.ts ``` Saisissez ce prompt : ```text Inspect package.json and report the package name and available scripts. Do not modify files. ``` Lorsque le contrôleur demande s’il faut autoriser `mastra_workspace_read_file`, saisissez `y`. L’Agent lit `package.json` et indique ce qu’il y trouve. La formulation varie selon le modèle, mais la réponse doit inclure le nom du package et ses scripts sans modifier le fichier. Appuyez sur **Ctrl+C** pour fermer l’application et détruire le contrôleur. ## Étapes suivantes Vous pouvez étendre cette base afin de : - Ajouter un stockage pour conserver et reprendre les sessions du contrôleur - Ajouter d’autres modes avec des instructions et des listes d’autorisation d’outils du Workspace différentes - Remplacer le composant de réponse la plus récente par une transcription qui affiche les appels d’outils et leurs résultats - Ajouter une isolation sandbox avant d’accepter des prompts non fiables ou de distribuer l’application Pour en savoir plus : - [Référence de `createCodingAgent()`](https://mastra.zisheng.pro/fr/reference/coding-agent/create-coding-agent) - [Référence de `buildBasePrompt()`](https://mastra.zisheng.pro/fr/reference/coding-agent/build-base-prompt) - [Présentation d’AgentController](https://mastra.zisheng.pro/fr/docs/harness/agent-controller) - [Référence d’`AgentController`](https://mastra.zisheng.pro/fr/reference/agent-controller/agent-controller-class) - [Présentation de Workspace](https://mastra.zisheng.pro/fr/docs/workspace/overview)