Agents et ACP
Turbo Python est un client de l'Agent Client Protocol. Il lance chaque agent comme processus fils et échange avec lui des messages JSON-RPC 2.0 sur son entrée et sa sortie standard, à raison d'un message par ligne.
Où se trouve le fichier
| Chemin | Lu | Rôle |
|---|---|---|
~/.config/turbo-python/acp.toml |
en premier | Les agents que vous voulez dans tous les projets |
<projet>/.turbo-python/acp.toml |
en second | Les agents propres à ce projet |
Les deux sont facultatifs. Quand un name d'agent apparaît dans les deux, celui du projet remplace celui de l'utilisateur, étant l'énoncé le plus spécifique — la règle que suivent déjà les snippets. Un fichier absent n'est pas une erreur ; un fichier présent mais illisible en est une, signalée sous Agent ▸ Agent status plutôt que de laisser silencieusement le menu vide.
TURBO_PYTHON_DIR remplace le dossier où le fichier utilisateur est cherché. Le fichier du projet est toujours .turbo-python/acp.toml sous le dossier depuis lequel l'éditeur a été lancé — il n'y a pas de remontée dans l'arborescence, pour la même raison que les réglages de projet ne remontent pas.
Format du fichier
Un bloc [[agent]] par agent, dans l'ordre souhaité dans le menu.
[[agent]]
name = "Bob (llama.cpp)"
command = "docker"
args = ["agent", "serve", "acp", ".turbo-python/agent.yaml"]
env = { TELEMETRY_ENABLED = "false" }
cwd = "."
| Clé | Type | Requise | Signification |
|---|---|---|---|
name |
chaîne | oui | Ce qu'affiche le menu Agent et le titre de la fenêtre. Doit être unique dans l'ensemble fusionné. |
command |
chaîne | oui | L'exécutable à lancer. Cherché dans PATH sauf s'il contient un séparateur. |
args |
liste de chaînes | non | Ses arguments, passés tels quels — pas de shell, donc ni guillemets, ni jokers, ni &&. |
env |
table de chaînes | non | Variables d'environnement ajoutées à celles de l'éditeur. Un nom donné ici l'emporte. |
cwd |
chaîne | non | Où le processus démarre, et le cwd annoncé à l'agent. Relatif à la racine du projet. Par défaut, la racine du projet. |
env peut aussi s'écrire en sous-table, ce qui est la même chose :
[[agent]]
name = "Bob (llama.cpp)"
command = "docker"
args = ["agent", "serve", "acp", ".turbo-python/agent.yaml"]
[agent.env]
TELEMETRY_ENABLED = "false"
Ce qui est refusé
Le fichier est refusé dans son ensemble, plutôt que chargé à moitié, dès que l'un de ces cas se présente. Un menu à moitié chargé proposant trois de vos cinq agents est pire qu'une erreur qui dit pourquoi.
| Problème | Message |
|---|---|
un agent sans name |
reading …/acp.toml: agent 1 has no name |
un agent sans command |
reading …/acp.toml: agent "Bob" has no command |
deux agents portant le même name |
reading …/acp.toml: two agents are called "Bob" |
| une clé que le format ne définit pas | reading …/acp.toml: agent.comand is not a key this file has |
Le dernier cas est voulu : une clé mal orthographiée silencieusement ignorée ressemblerait exactement à une clé sans effet.
Le menu Agent
Alt-A l'ouvre. Il est sur la barre qu'un agent soit configuré ou non, parce que c'est de là que Create agents file doit être atteignable.
| Entrée | Active quand | Effet |
|---|---|---|
| une entrée par agent, par son nom | toujours | Démarrer cet agent et ouvrir une fenêtre dessus |
| Create agents file | pas d'acp.toml dans le projet |
Écrire le fichier de départ et l'ouvrir |
| Cancel turn | un tour est en cours dans la fenêtre de devant | session/cancel |
| Agent status | toujours | Ce qui a été chargé, la ligne de commande de chacun, et ce qui a échoué |
Touches dans une fenêtre agent
Une fenêtre agent est une fenêtre ordinaire : F6, Alt-1…Alt-9, Tile, Maximise, [x] et [■] y fonctionnent tous. À l'intérieur :
| Touche | Effet |
|---|---|
Entrée |
Envoyer la zone de saisie comme invite |
Alt-Entrée |
Insérer un saut de ligne dans la zone de saisie |
Tab |
Déplacer le focus entre la conversation et la zone de saisie |
Ctrl-C, Ctrl-Ins |
Copier la sélection, ou le bloc sur lequel est le curseur |
Échap |
Abandonner la sélection ; s'il n'y en a pas, annuler le tour en cours |
Ctrl-W |
Fermer la fenêtre et arrêter l'agent |
Avec la zone de saisie au premier plan :
| Touche | Effet |
|---|---|
↑ ↓ ← → Début Fin |
Déplacer le curseur dans ce que vous tapez |
Retour arrière Suppr |
L'éditer ; le retour arrière en début de ligne la joint à celle du dessus |
/ en premier caractère |
Ouvrir la liste des commandes de l'agent — voir Commandes et mentions |
@ |
Ouvrir la liste des fichiers du projet, réduite par ce que vous tapez ensuite |
↑ ↓ PgUp PgDn, liste ouverte |
Se déplacer dans la liste |
Tab, liste ouverte |
Prendre l'entrée en surbrillance |
Entrée, liste ouverte |
Prendre l'entrée en surbrillance ; sur un mot déjà complet, envoyer |
Échap, liste ouverte |
Fermer la liste jusqu'à ce que le texte change |
Avec la conversation au premier plan :
| Touche | Effet |
|---|---|
↑ ↓ |
Déplacer le curseur d'une ligne |
PgUp PgDn |
Le déplacer d'un écran |
Début Fin |
Le début de la conversation, et la fin |
Shift- l'une d'elles |
Étendre la sélection à la place |
| Glisser avec le bouton 1 | Sélectionner à la main |
| Molette | Défiler de trois lignes sans bouger le curseur |
Contrairement à une fenêtre terminal, une fenêtre agent ne prend pas les raccourcis de l'éditeur : il n'y a pas de shell qui ait besoin de Ctrl-F, donc cette touche garde son sens habituel. Ctrl-C fait exception, et seulement parce que rien d'autre n'en veut dans une fenêtre agent.
Commandes et mentions
Deux caractères ouvrent une liste par-dessus le bas de la conversation pendant que vous tapez. Ce sont les deux mêmes que Zed, si bien que la documentation d'un agent — « tapez /web pour chercher » — reste vraie ici.
/ — les commandes de l'agent
Un agent peut annoncer des commandes par available_commands_update, au début de la session ou à tout moment pendant celle-ci. Taper / comme premier caractère de la zone de saisie les liste : le nom, la description donnée par l'agent et, entre chevrons, ce qu'il attend après le nom quand il attend quelque chose. Continuez à taper pour réduire la liste ; la correspondance porte sur le début du nom et ignore la casse.
Tab complète la commande en surbrillance. Une commande qui prend une entrée est complétée avec une espace à la fin, pour que la suite de votre frappe soit son argument ; une qui n'en prend pas est complétée au nom seul. Entrée complète aussi, sauf sur un mot qui se lit déjà exactement comme une commande, où elle envoie.
Sur le fil, une commande est du texte : /web agent client protocol part comme un seul bloc texte, et l'agent la reconnaît à son premier mot. C'est tout le protocole des commandes, et c'est pourquoi un / ailleurs qu'au début de la zone n'est qu'un caractère.
Sans commande annoncée, / est un caractère et Tab garde son sens habituel. Agent ▸ Agent status liste les commandes avec leur description.
@ — un fichier du projet
Taper @ n'importe où dans la zone liste les fichiers du projet, relatifs à sa racine, avec des barres obliques. Ce que vous tapez après le @ réduit la liste : les fichiers dont le nom propre commence par cela viennent d'abord, puis ceux dont le chemin le contient seulement. Tab ou Entrée complète celui en surbrillance et ajoute une espace.
À l'envoi de l'invite, chaque @nom qui désigne un fichier connu de la liste devient un bloc de contenu à la place du nom :
| L'agent a déclaré | Le bloc envoyé |
|---|---|
promptCapabilities.embeddedContext: true |
resource — l'uri du fichier, son mimeType et son text entier, lu comme fs/read_text_file le lit : depuis le tampon ouvert quand le fichier est ouvert et modifié |
| autre chose, ou le fichier n'a pas pu être lu | resource_link — l'uri, le name et le mimeType, pour que l'agent aille le chercher lui-même |
Les mots de part et d'autre partent en blocs texte, si bien que explique @docs/README.md s'il te plaît fait trois blocs : explique , le fichier, s'il te plaît. La conversation garde la ligne telle que vous l'avez tapée.
Un mot qui commence par @ et ne désigne aucun fichier reste du texte — une adresse électronique dans une invite n'est pas un fichier — et @main.go ne désigne pas main.gopher : le nom doit terminer le mot.
La liste est le projet parcouru depuis sa racine, .git exclu, au plus 5 000 fichiers, et au plus 200 d'entre eux affichés à la fois. Au-delà de l'une ou l'autre limite, tapez une lettre de plus. Le parcours est refait à chaque ouverture de la liste par @, si bien qu'un fichier que l'agent vient de créer y figure.
La copie
La sélection porte sur des lignes entières. Rien ne s'édite dans une conversation, donc une demi-ligne n'est jamais ce qu'on veut dire, et des lignes entières préservent l'indentation d'un bloc de code copié.
Sans rien de sélectionné, la copie prend la région sur laquelle est le curseur : un bloc de code délimité, un passage de prose, la sortie d'un appel d'outil. Le libellé d'un interlocuteur et l'en-tête d'un appel d'outil sont du mobilier et forment des régions à part : ni l'un ni l'autre n'est jamais copié avec ce qu'il surmonte.
L'indentation d'affichage de la conversation est retirée, donc le code collé arrive collé à la marge.
Le texte part à deux endroits à la fois :
| Presse-papiers | Comment | Collé avec |
|---|---|---|
| Celui de l'éditeur | directement | Shift-Ins, dans un fichier ouvert ici |
| Celui du système | OSC 52, à travers le terminal | Ctrl-V, n'importe où ailleurs |
Rien ne vérifie que le terminal a accepté le second : il n'y a pas de réponse à vérifier, et un terminal peut refuser OSC 52 par sécurité ou demander qu'on l'active. Le presse-papiers de l'éditeur contient le texte dans tous les cas, et la barre d'état dit combien de lignes ont été copiées.
Quelle part du protocole est implémentée
Version de protocole 1. Turbo Python annonce sa version dans initialize et accepte la version que l'agent répond, pourvu qu'il la connaisse.
Ce que l'éditeur appelle sur l'agent
| Méthode | Implémentée | Remarques |
|---|---|---|
initialize |
oui | Annonce la capacité fs ci-dessous ; terminal n'est pas annoncée |
session/new |
oui | cwd vient de la clé cwd de l'agent ; mcpServers est toujours vide — les serveurs MCP sont l'affaire de l'agent |
session/prompt |
oui | Des blocs texte, et un bloc resource ou resource_link par fichier désigné par @ — voir Commandes et mentions |
session/cancel |
oui | Échap, et Agent ▸ Cancel turn |
session/load |
non | Les conversations ne survivent pas à la fermeture de la fenêtre |
authenticate |
non | Un agent qui liste des authMethods est signalé comme exigeant une connexion que l'éditeur ne sait pas faire |
Ce que l'agent peut appeler sur l'éditeur
| Méthode | Implémentée | Remarques |
|---|---|---|
session/update |
oui | Voir la table ci-dessous |
session/request_permission |
oui | Une boîte modale portant les options de l'agent lui-même |
fs/read_text_file |
oui | Depuis le tampon quand le fichier est ouvert et modifié, sinon depuis le disque |
fs/write_text_file |
oui | Dans le tampon quand le fichier est ouvert, sinon sur le disque |
terminal/* |
non | Non annoncée, donc un agent conforme ne la demandera pas |
Mises à jour de session
sessionUpdate |
Affiché comme |
|---|---|
agent_message_chunk |
La réponse de l'agent, ajoutée au fil de son arrivée |
agent_thought_chunk |
La même chose, dans la couleur des commentaires, sous une étiquette réflexion |
user_message_chunk |
Votre propre message, tel que l'agent le renvoie |
tool_call |
Une ligne nommant l'outil et son titre, avec son état |
tool_call_update |
Repliée sur la ligne dont le toolCallId correspond, avec sa sortie |
plan |
Les entrées en liste, chacune avec son état |
available_commands_update |
La liste que / ouvre dans la zone de saisie ; aussi listée, avec les descriptions, par Agent ▸ Agent status |
usage_update |
Le compte de jetons dans la barre d'état quand la fenêtre est devant |
| tout le reste | Ignoré, et compté ; le compte figure dans Agent status |
Pendant qu'un tour est en cours, la règle entre les deux zones fait tourner un indicateur. Il est dessiné à partir de l'horloge et non d'un compteur, donc deux fenêtres qui réfléchissent en même temps tournent en phase et rien n'a besoin d'être remis à zéro au début d'un tour. Le titre de la fenêtre, lui, n'est délibérément pas animé : c'est aussi ce qu'affichent la liste des fenêtres et le menu Alt-chiffre, et un nom qui change huit fois par seconde les fait scintiller tous les deux.
Une mise à jour inconnue est ignorée plutôt que refusée : le protocole grandit, et un éditeur qui cesserait de parler à un agent parce que celui-ci a appris un nouveau type de message aurait tort plus souvent que raison.
Coloration
La conversation est dessinée avec des clés que tous les thèmes définissent déjà, donc aucun n'a eu besoin d'être touché :
| Élément | Classe |
|---|---|
| Le nom d'un interlocuteur | syntax.keyword |
| Une réflexion | syntax.comment |
| Un appel d'outil et son état | syntax.type |
| Un appel d'outil en échec, et les avis de l'éditeur | diagnostic.error |
| Une ligne sélectionnée, et la barre du curseur | editor.selection |
| Le code dans un bloc délimité | l'analyseur du langage annoncé |
| Tout le reste | le texte ordinaire de la fenêtre |
Un bloc délimité annonçant un langage que l'éditeur colore — python, toml, yaml, markdown, javascript, html, xml, dockerfile, bash — est coloré par cet analyseur. Un bloc annonçant autre chose, ou rien, est laissé brut.
Tracer la conversation avec un agent
| Variable | Effet |
|---|---|
TURBO_ACP_TRACE=<fichier> |
Ajouter à ce fichier chaque message vers et depuis chaque agent, un par ligne, horodaté et marqué -> (envoyé) ou <- (reçu) |
C'est pour la seule question à laquelle l'écran ne peut pas répondre — qu'a réellement envoyé l'agent ? Une mise à jour que cet éditeur ne sait pas décoder est comptée dans Agent ▸ Agent status, qui nomme aussi la dernière et son erreur ; la trace montre le message lui-même. Un fichier qui ne peut pas être ouvert veut dire pas de trace, et rien d'autre : la trace n'a jamais le droit de casser l'éditeur.
Limites
- Une session par fenêtre. Fermer la fenêtre termine la session ; il n'y a pas de reprise.
- Texte et fichiers seulement. L'éditeur envoie du texte, et les fichiers que vous désignez par
@; ni images ni audio, quoi que disent lespromptCapabilitiesde l'agent. - Pas d'authentification. Un agent exigeant une connexion doit être connecté par sa propre CLI avant que l'éditeur ne le lance.
argsn'est pas une commande shell.command = "sh",args = ["-c", "…"]est la façon délibérée d'en obtenir une.- Une entrée est plafonnée à un mégaoctet de texte. Un agent qui déverse tout un journal de compilation ne peut pas rendre la fenêtre inutilisable ; ce qui a été perdu est signalé dans l'entrée elle-même.
Voir aussi
- La tâche : Dialoguer avec un agent de code depuis l'éditeur
- Le raisonnement : Fenêtres agent
- Le protocole : agentclientprotocol.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
|