Construire votre premier agent géré
Sur cette page
Une boucle d’agent écrite à la main convient à beaucoup de fonctionnalités. Mais quand elle doit tourner des minutes, voire des heures, avec de nombreux outils, un état à garder, des fichiers à écrire et un travail à reprendre après une coupure réseau, mieux vaut ne plus la faire tourner sur votre serveur : on la délègue. Un agent géré, c’est une boucle d’agent qui tourne chez Anthropic. Vous décrivez l’agent une fois, vous lui donnez un environnement de travail, et vous lancez une session ; Anthropic fait tourner la boucle, et vous lisez les événements au fil du travail. Le service est activé par défaut sur tous les comptes API, et le SDK ajoute de lui-même l’en-tête bêta nécessaire (managed-agents-2026-04-01).
Quatre primitives, dans l’ordre
- L’agent : la personnalité, c’est-à-dire le modèle, le prompt système et les outils. Il sert pour de nombreuses exécutions.
- L’environnement : là où l’agent s’exécute, dans le cloud ou chez vous, avec sa configuration réseau.
- La session : une exécution de l’agent dans un environnement. C’est l’unité de travail.
- Les événements : ce qui entre et sort, c’est-à-dire les actions de l’agent, ses appels d’outils, leurs résultats et ses réponses.
Votre application parle à une session, la session fait travailler l’environnement, et tout ce qui se passe revient par le flux d’événements. Vous n’écrivez plus de boucle while : vous envoyez des événements et vous en lisez.
Le plus petit agent géré utile
L’exemple de la leçon officielle crée un fichier dans le répertoire temporaire, compte ses lignes et rend compte. Pour les outils, il prend la boîte à outils de l’agent (agent_toolset_20260401), les outils de fichiers, de commandes et de web fournis par Anthropic : inutile d’en définir.
1. L’agent, une seule fois
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const agent = await client.beta.agents.create({
name: "Line Counter",
model: "claude-opus-5-5",
system: "Tu es un agent serviable qui accomplit de petites tâches sur des fichiers.",
tools: [{ type: "agent_toolset_20260401", default_config: { enabled: true } }],
});
// Stockez agent.id : on ne recrée pas l'agent à chaque exécution
Dans un vrai projet, cette étape vit dans un script de mise en place, ou dans un fichier versionné synchronisé avec la CLI ant apply, pas dans le code exécuté à chaque requête.
2. L’environnement
const environment = await client.beta.environments.create({
name: "line-counter-env",
config: { type: "cloud", networking: { type: "limited" } },
});
Avec un réseau limited, le bac à sable et les outils web ne joignent que les hôtes listés dans allowed_hosts. Cette tâche n’a besoin d’aucun réseau : on n’en liste aucun. Réservez unrestricted aux agents qui doivent joindre des sites impossibles à lister d’avance. Indiquez toujours networking : une création qui l’omet reçoit unrestricted. Chaque session a son propre bac à sable, et c’est là que le fichier sera écrit.
3. La session, à chaque exécution
const session = await client.beta.sessions.create({
agent: agent.id,
environment_id: environment.id,
title: "Démo comptage de lignes",
});
Avec le seul identifiant, la session prend la dernière version de l’agent. Pour la reproductibilité, attachez-la à une version précise : agent: { type: "agent", id: agent.id, version: agent.version }.
4. Ouvrir le flux, puis envoyer le message
Le flux ne livre que les événements survenus après son ouverture : ouvrez-le toujours avant d’envoyer le message de départ. Notez le pluriel, events : tout passe par des événements dans cette API.
const stream = await client.beta.sessions.events.stream(session.id);
await client.beta.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [{ type: "text", text: "Crée un fichier dans le répertoire temporaire, compte ses lignes et rends compte." }],
},
],
});
5. Lire le flux
Trois événements comptent pour cette démonstration : agent.message (le texte de Claude), agent.tool_use (l’outil choisi) et session.status_idle (l’agent s’est arrêté et attend).
loop: for await (const event of stream) {
switch (event.type) {
case "agent.message":
for (const block of event.content) {
if (block.type === "text") process.stdout.write(block.text);
}
break;
case "agent.tool_use":
console.log(`\n[outil] ${event.name}`);
break;
case "session.status_idle":
console.log(`\n--- Agent à l'arrêt : ${event.stop_reason.type} ---`);
break loop;
}
}
La démonstration s’arrête au premier arrêt. Dans votre application, lisez stop_reason.type avant de considérer le travail comme fini : end_turn veut dire que l’agent a terminé son tour (ou que vous l’avez interrompu), requires_action qu’un appel d’outil attend votre réponse, budget_reached que la session a atteint son budget.
Quand un appel attend votre accord
Sous une politique always_ask, ou auto quand le serveur ne tranche pas, un appel d’outil est mis en pause. La session s’arrête alors avec requires_action et la liste des appels bloqués dans stop_reason.event_ids, et elle attend indéfiniment. Répondez à chacun par un événement user.tool_confirmation. Dans la boucle de l’étape 5, le cas session.status_idle devient :
case "session.status_idle":
if (event.stop_reason.type !== "requires_action") break loop; // fini, interrompu ou budget atteint
for (const eventId of event.stop_reason.event_ids) {
await client.beta.sessions.events.send(session.id, {
events: [{ type: "user.tool_confirmation", tool_use_id: eventId, result: await approuver(eventId) }],
});
}
break; // la session repart : on continue de lire le flux
La fonction approuver est la vôtre : elle demande à une personne ou applique votre propre règle, et renvoie "allow" ou "deny". Trois règles à retenir :
- Quand personne ne surveille, répondez
deny, avec undeny_messagequi explique le refus à l’agent. Ne répondez jamaisallowà tout sans examen. - Une session qui attend une action ne doit pas être abandonnée : tant que vous ne répondez pas, elle reste bloquée.
- Le flux ne se rejoue pas. L’historique des événements est conservé sur le serveur : à chaque reconnexion, ouvrez un nouveau flux, listez les événements passés, puis ignorez ceux que la liste vous a déjà donnés.
Ce que vous déléguez
Avec une boucle à vous, vous contrôlez tout. Avec un agent géré, vous déléguez la boucle, le bac à sable et la reprise, et vous consommez le flux. C’est la forme des tâches longues qui touchent beaucoup de fichiers, du genre « va me ranger ça ». La leçon officielle prend l’exemple d’un partage de fichiers à nettoyer. L’agent lit la structure cible, parcourt le dossier d’arrivée, range chaque fichier dans le bon projet, archive les doublons et les fichiers vides, et signale ce qu’il ne sait pas classer. Le tout tient dans une session de plusieurs minutes, sur des milliers de fichiers.
Pour suivre une session, la Console a une page Sessions (réservée aux rôles Developer et Admin) : la transcription, les outils appelés et le coût cumulé, sans rien configurer. Pour changer le prompt, un outil ou le modèle, mettez à jour l’agent : une nouvelle version est créée, les sessions en cours gardent la leur, les nouvelles prennent la dernière.
À vous de jouer
Votre premier agent géré. Faites tourner l’exemple, puis changez la tâche : par exemple, compter les fichiers d’un dossier et en résumer le contenu. Mettez à jour le prompt système de l’agent, lancez une session sur chacune des deux versions, et comparez leurs transcriptions dans la page Sessions de la Console.
Sources officielles : Building your first managed agent (Claude Academy) · Managed Agents quickstart · Environments · Session event stream · Permission policies · Session observability
Points clés à retenir
- Agent (une fois, versionné), environnement, session (à chaque exécution), événements : vous envoyez et lisez des événements au lieu d’écrire une boucle
- Indiquez toujours le réseau de l’environnement :
limitedetallowed_hosts, sinonunrestrictedpar défaut - Ouvrez le flux avant d’envoyer le message ; à l’arrêt, lisez
stop_reason.type(end_turn,requires_action,budget_reached) - Répondez aux appels mis en pause (
denyquand personne ne surveille) ; à la reconnexion, relisez l’historique et dédoublonnez