Перейти к содержимому

Отладить падающий тест с агентом

Это руководство показывает, как заставить агента воспользоваться отладчиком для ошибки, которую не объясняют операторы print.

Инструмент debug управляет настоящей сессией Debug Adapter Protocol. Остановленный кадр отвечает сразу на все вопросы об этом моменте — каждая локальная переменная, каждый вызывающий и выражение, вычисленное в собственной области видимости кадра, — тогда как оператор print отвечает лишь на тот вопрос, который вы догадались задать до запуска.

Инструмент остаётся на поверхности, чтобы агент мог спросить, почему ничего не работает, а не гадать. Адаптер действительно может запуститься, только когда выполняются оба условия:

  • маркер проекта в рабочей копии и
  • бинарник адаптера резолвится.

Попросите агента проверить:

debug(op: "adapters")

Он ответит тем, что нашёл, или объяснит, что адаптеру нужны обе половины.

Язык Адаптер Маркер Установка
Dart / Flutter dart debug_adapter pubspec.yaml Поставляется с SDK — делать нечего
Python python3 -m debugpy.adapter pyproject.toml, setup.py, requirements.txt pip install debugpy
Rust / C / C++ lldb-dap Cargo.toml, CMakeLists.txt Поставляется с LLVM
Go dlv dap go.mod go install github.com/go-delve/delve/cmd/dlv@latest

Сначала поставьте точку останова, потом запускайте

Заголовок раздела «Сначала поставьте точку останова, потом запускайте»

Порядок важен, и инструмент его требует: точки останова можно ставить до появления сессии, потому что именно такую последовательность требует протокол.

Спросите агента примерно так:

Функция compute в bin/main.dart возвращает неверное значение. Поставьте точку останова на строке, которая присваивает product, запустите её под отладчиком и скажите, чему на самом деле равны a и b.

Он выполнит примерно следующее:

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

Запуск сообщает, где он остановился:

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)

Затем загляните внутрь:

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

Объект с дочерними элементами сообщает [expand: reference N] — но только когда за ним действительно что-то есть, поэтому раскрытие, которым агент не сможет воспользоваться, никогда не предлагается.

Для всего, что не видно как локальная переменная:

debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)
Что нужно Операция
Выполнять до следующей остановки continue
Следующая строка, тот же кадр step_over
Внутрь вызова step_in
Наружу, к вызывающему step_out
Остановить работающую программу pause

Для зависшего процесса, а не того, который вы запускаете:

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

Всегда завершайте сессию. Отладочный адаптер владеет остановленным процессом, который держит всё, что держит этот процесс, — порт, блокировку, соединение с базой данных.

Раскрытие variables на глубоком графе объектов по своей природе безгранично — один виджет Flutter дотягивается до всего дерева элементов. Число дочерних элементов на область видимости ограничено 50, значения — 400 символами, а кадры стека — 30. Результат инструмента, заполняющий окно контекста, — это инструмент, который завершает запуск, которому помогал.