Aller au contenu

Déboguer un test en échec avec un agent

Ce guide vous montre comment amener un agent à se servir d’un débogueur sur une défaillance que les instructions print n’expliquent pas.

L’outil debug pilote une véritable session Debug Adapter Protocol. Un cadre arrêté répond d’un coup à toutes les questions sur cet instant — chaque variable locale, chaque appelant, et une expression évaluée dans la portée propre du cadre — là où une instruction print ne répond qu’à la question que vous avez pensé à poser avant de lancer.

L’outil reste présent dans la surface d’outils, afin que l’agent puisse demander pourquoi rien n’est utilisable plutôt que de deviner. Un adaptateur ne peut réellement démarrer que si ces deux conditions sont réunies :

  • un marqueur de projet dans le checkout, et
  • le binaire de l’adaptateur qui se résout.

Demandez à l’agent de vérifier :

debug(op: "adapters")

Il répond avec ce qu’il a trouvé, ou explique qu’un adaptateur a besoin des deux moitiés.

Langage Adaptateur Marqueur Installation
Dart / Flutter dart debug_adapter pubspec.yaml Fourni avec le SDK — rien à faire
Python python3 -m debugpy.adapter pyproject.toml, setup.py, requirements.txt pip install debugpy
Rust / C / C++ lldb-dap Cargo.toml, CMakeLists.txt Fourni avec LLVM
Go dlv dap go.mod go install github.com/go-delve/delve/cmd/dlv@latest

L’ordre compte et l’outil l’impose : les points d’arrêt peuvent être posés avant qu’une session existe, car c’est la séquence qu’exige le protocole.

Demandez à l’agent quelque chose comme :

La fonction compute dans bin/main.dart renvoie une valeur erronée. Posez un point d’arrêt sur la ligne qui affecte product, lancez-le sous le débogueur et dites-moi ce que valent réellement a et b.

Il exécutera à peu près :

debug(op: "breakpoints", file: "bin/main.dart", lines: [7])
debug(op: "launch", program: "bin/main.dart")

Le lancement indique où il s’est arrêté :

Launched bin/main.dart on dart (session dart-1). Stopped: breakpoint. Use `stack` to see where.
debug(op: "stack")
→ #1 compute (bin/main.dart:7:3)
#2 main (bin/main.dart:2:18)

Puis descendez dedans :

debug(op: "scopes", frame_id: 1)
→ Locals (reference 12)
debug(op: "variables", reference: 12)
→ a (int) = 6
b (int) = 7
product (int) = 42

Un objet qui a des enfants indique [expand: reference N] — mais uniquement lorsqu’il y a réellement quelque chose derrière, si bien qu’une expansion inutilisable par l’agent n’est jamais proposée.

Pour tout ce qui n’apparaît pas comme variable locale :

debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)
Ce que vous voulez Opération
Exécuter jusqu’au prochain arrêt continue
Ligne suivante, même cadre step_over
Entrer dans l’appel step_in
Sortir vers l’appelant step_out
Arrêter un programme en cours pause

Pour un processus bloqué plutôt qu’un processus que vous lancez :

debug(op: "attach", port: 5858)
debug(op: "terminate")

Terminez toujours la session. Un adaptateur de débogage possède un processus arrêté qui retient tout ce que ce processus retient — un port, un verrou, une connexion à une base de données.

Une expansion variables sur un graphe d’objets profond est par nature non bornée — un seul widget Flutter atteint tout l’arbre d’éléments. Les enfants par portée sont plafonnés à 50, les valeurs à 400 caractères et les cadres de pile à 30. Un résultat d’outil qui remplit la fenêtre de contexte est un outil qui met fin à l’exécution qu’il aidait.