Встроенные инструменты агента
Это привязанные к серверу инструменты, которые встроенная среда выполнения агента регистрирует напрямую, — языковой сервер, структурный поиск, отладчик, ядра, вопросы и управление воркерами, — в отличие от инструментов MCP, которые она подключает извне, и универсальных инструментов работы с файлами, поиска и оболочки из среды выполнения харнесса. Их нет в реестре MCP: внешний клиент MCP их не увидит, потому что каждый из них привязан к живому ресурсу на стороне сервера — процессу языкового сервера, отладочному адаптеру, интерпретатору, — который принадлежит одному запуску.
Каждый инструмент здесь регистрируется, только когда для запуска подключён его опорный ресурс — супервизор языкового сервера или отладки, парсер tree-sitter, фабрика ядер, порт вопросов, состав vibe. Обнаружение языкового сервера или отладочного адаптера для этой рабочей копии — отдельная, более поздняя проверка (status / adapters): эти инструменты остаются на поверхности, чтобы агент мог спросить, почему ничего не работает, а не гадать.
Уровни подтверждения
Заголовок раздела «Уровни подтверждения»Каждый инструмент объявляет уровень, и уровень решает, какие поверхности его видят, — а не просто то, спрашивает ли он подтверждение. Режим плана и субагенты только для чтения ограничены уровнем read, поэтому инструмент уровня write или exec полностью отсутствует в их схеме.
| Уровень | Значение | Инструменты здесь |
|---|---|---|
read |
Без побочных эффектов | lsp, ast_grep, ask_user, пять vibe_* |
write |
Изменяет файлы | lsp_rename, ast_edit, resolve |
exec |
Запускает процесс или управляет им | debug, eval |
lsp — запросы к языковому серверу
Заголовок раздела «lsp — запросы к языковому серверу»Регистрируется, когда у запуска есть супервизор языкового сервера и рабочий каталог. Способен ли сервер на самом деле ответить, определяется в момент вызова как пересечение: маркер корня должен существовать, и бинарник сервера должен разрешаться. Каждое из условий само по себе означает, что сервер не запустится — status так и говорит, — а не молчаливое предположение.
Позиции адресуются строкой line плюс подстрокой symbol, никогда — столбцом. Модель, у которой просят столбец, гадает, а неверная догадка разрешается в другой символ на той же строке — ответ, который выглядит правильным, но говорит о другом. Пропуск symbol в навигационном действии — это ошибка, а не догадка о первом столбце.
| Действие | Аргументы | Возвращает |
|---|---|---|
diagnostics |
file (или "*") |
Ошибки и предупреждения; "*" вместо этого запускает проверку проекта |
definition |
file, line, symbol |
Где объявлен символ |
type_definition |
file, line, symbol |
Где объявлен его тип |
implementation |
file, line, symbol |
Конкретные реализации |
references |
file, line, symbol |
Все использования, не более 50 |
hover |
file, line, symbol |
Сигнатура и doc-комментарий |
symbols |
query или file |
Поиск по рабочему пространству с query (не более 100); символы документа с file (не более 200) |
code_actions |
file, line, symbol |
Быстрые исправления, которые предлагает сервер |
status |
— | Какие серверы работают и для каких корней |
reload |
— | Перезапускает сервер для этого корня |
Диагностика при записи
Заголовок раздела «Диагностика при записи»Выигрыш не в самом инструменте. write, edit и apply_patch обёрнуты: после записи файл синхронизируется и сохраняется через языковой сервер, и в результат инструмента подмешиваются только вновь появившиеся диагностики. Агент узнаёт, что сломал сборку, в тот самый момент, когда он её сломал, и ему не нужно помнить, чтобы спросить.
Уже отчитанные диагностики подавляются реестром уровня запуска, ключ которого строится по серьёзности, коду и сообщению, — позиция намеренно исключена, поэтому диагностика, которая всего лишь сместилась на четыре строки вниз, не отчитывается заново как новая.
lsp_rename — переименование в пределах проекта
Заголовок раздела «lsp_rename — переименование в пределах проекта»Отдельный инструмент уровня write ровно по одной причине: уровень решает видимость. Добавление переименования в lsp либо дало бы исследователю только для чтения возможность переписать репозиторий, либо поставило бы каждый hover за запрос подтверждения.
| Аргумент | Значение |
|---|---|
file |
Где находится символ |
line |
Строка с нумерацией от 1 |
symbol |
Подстрока, опознающая его в этой строке |
new_name |
Как его назвать |
ast_grep — структурный поиск
Заголовок раздела «ast_grep — структурный поиск»Находит код по форме, а не по тексту. $NAME сопоставляется с любым узлом, $$$NAME — с последовательностью соседних узлов, а $_ — это подстановочный знак, который ничего не связывает.
Свойство, которое делает его сопоставителем, а не регулярным выражением с лишними шагами: метапеременная, повторённая в одном шаблоне, должна захватить один и тот же текст.
ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")находит проверку, которая освобождает то же, что проверяла, и не находит ту, что освобождает что-то другое.
| Аргумент | Значение |
|---|---|
pattern |
Фрагмент кода с метапеременными |
path |
Файл или каталог для поиска; по умолчанию всё рабочее пространство |
language |
Идентификатор поставляемой грамматики (dart, python, rust, c, …). Выводится, когда path указывает на файл |
max_results |
По умолчанию 50 |
ast_edit — структурная перезапись с подготовкой
Заголовок раздела «ast_edit — структурная перезапись с подготовкой»То же сопоставление, плюс шаблон rewrite, в который подставляются обратно метапеременные. Ничего не записывается. Изменение подготавливается, и результат называет edit_id.
ast_edit(pattern: "dispose($X)", rewrite: "$X.dispose()", language: "dart")→ (proposed) 12 replacements in 4 files … call resolve with edit_id "edit_1"| Аргумент | Значение |
|---|---|
pattern |
Что сопоставлять |
rewrite |
Что подставить на это место, с подстановкой $NAME |
path |
Область; по умолчанию всё рабочее пространство |
language |
Идентификатор языка |
resolve — зафиксировать или отбросить подготовленное изменение
Заголовок раздела «resolve — зафиксировать или отбросить подготовленное изменение»| Аргумент | Значение |
|---|---|
edit_id |
Из результата (proposed) |
action |
accept или discard |
Каждый файл сверяется с содержимым, зафиксированным в момент подготовки изменения, и любое несовпадение отклоняет изменение целиком. Частично применённая структурная перезапись оставляет дерево, которое не компилируется ни под старой формой, ни под новой.
debug — управление отладчиком
Заголовок раздела «debug — управление отладчиком»Регистрируется, когда у запуска есть супервизор отладочных сессий, рабочий каталог и идентификатор разговора. Способен ли адаптер на самом деле запуститься, определяется в момент вызова по тому же правилу пересечения, что и для языкового сервера (маркер корня и бинарник). Уровень exec; небезопасен при параллельном выполнении (сессия — это состояние между вызовами, поэтому continue, обогнавший stack, прочитал бы кадр, который уже сдвинулся).
Одна сессия на разговор, с жёстким TTL (30 минут). Второй launch отклоняется, а не заменяет первый молча.
| Операция | Аргументы | Примечания |
|---|---|---|
adapters |
— | Какие адаптеры здесь пригодны и почему нет |
status |
— | Работает ли сессия и где она остановилась |
breakpoints |
file, lines[] |
Пустой lines очищает файл. Можно ставить до запуска |
launch |
program, args[] |
Запускает программу остановленной на ваших точках останова |
attach |
port |
Подключается к уже запущенной отлаживаемой программе |
continue |
thread_id? |
Выполняет до следующей остановки |
pause |
thread_id? |
Останавливает её там, где она есть |
step_over / step_in / step_out |
thread_id? |
Делает один шаг |
threads |
— | Идентификаторы и имена потоков |
stack |
thread_id? |
Кадры, не более 30 |
scopes |
frame_id |
Области видимости кадра, у каждой есть reference |
variables |
reference |
Дочерние элементы, не более 50; значения не длиннее 400 символов |
evaluate |
expression, frame_id? |
Вычисляется в собственной области видимости кадра |
output |
— | stdout/stderr отлаживаемой программы, с ограничением размера |
terminate |
— | Завершает сессию и убивает адаптер |
Адаптеры
Заголовок раздела «Адаптеры»| Идентификатор | Команда | Маркеры корня |
|---|---|---|
dart |
dart debug_adapter |
pubspec.yaml |
debugpy |
python3 -m debugpy.adapter |
pyproject.toml, setup.py, requirements.txt |
lldb |
lldb-dap |
Cargo.toml, CMakeLists.txt |
delve |
dlv dap |
go.mod |
debugpy предпочитает локальные для проекта .venv/bin или venv/bin вместо $PATH: python из $PATH — это другое окружение, и подключение не из того окружения падает так, что это читается как сломанный код.
eval — постоянные интерпретаторы
Заголовок раздела «eval — постоянные интерпретаторы»Ячейка Python или JavaScript, переменные, импорты и загруженные данные которой переживают переходы между вызовами. Уровень exec; небезопасна при параллельном выполнении.
| Аргумент | Значение |
|---|---|
code |
Ячейка |
description |
Обязательно. 5–10 слов для метки в транскрипте |
language |
python (по умолчанию) или javascript |
reset |
Отбросить интерпретатор и сначала начать с чистого |
- Последнее выражение отражается так, как это делает блокнот.
display()работает, датафрейм pandas отрисовывается как таблица, а график matplotlib возвращается как изображение, которое показывает транскрипт.- Идиомы IPython, которые люди набирают рефлекторно, —
%pip,%cd,!cmd,%%bash,%%timeit— переписываются в обычный код.%pipвдобавок вытесняетsys.modules, поэтому следующийimportвидит то, что только что установили.
Вызов собственных инструментов из ячейки
Заголовок раздела «Вызов собственных инструментов из ячейки»contents = tool("read", {"path": "lib/auth.dart"})Мост снова входит в реестр инструментов харнесса, поэтому ограничения, подтверждение и каждая обёртка применяются точно так же, как к вызову, сделанному моделью. Он идёт по собственному каналу ядра, а не через loopback-сокет: ни порта, ни секрета, ни правила исходящего доступа.
Тайм-аут ячейки — это бюджет бездействия (по умолчанию 5 минут), и он приостанавливается, пока не завершится вызов через мост, поэтому ячейка, которая разветвляется на субагентов, не убивается посреди разветвления.
ask_user — задать вопрос человеку
Заголовок раздела «ask_user — задать вопрос человеку»Уровень read. Единственный способ, которым запуск может спросить что-либо у оператора. Он отрисовывает в разговоре нумерованную карточку и блокируется, пока кто-нибудь не ответит, не пропустит её или пока вопрос не истечёт по тайм-ауту. Никогда не пишите вопрос как сообщение в чате — это завершает ход.
| Аргумент | Значение |
|---|---|
question |
Что спросить |
context |
Необязательно: почему вы спрашиваете и что зависит от ответа |
options[] |
Варианты, каждый {label, description?} |
allow_free_text |
Принимается ли ответ, набранный вручную |
multi_select |
Можно ли выбрать несколько вариантов |
Пропуск — это успех: действуйте на основании заявленного допущения и не спрашивайте снова. Тайм-аут — это ошибка с той же инструкцией. Запросы разрешения («можно мне это сделать?») — отдельный шлюз, и они отрисовываются в разговоре той же карточкой.
Регистрируется, только когда существуют и порт вопросов, и целевое пространство. Без подключённого человека вызов падает, а не блокируется навсегда, — та же позиция отказа по умолчанию, которую занимает prompt ограничения без подключённого подтверждающего.
vibe_* — управление фоновыми воркерами
Заголовок раздела «vibe_* — управление фоновыми воркерами»Регистрируются, только пока включён режим vibe. Все пять относятся к уровню read: шлюз должен стоять на инструментах воркера, там, где правка действительно происходит.
| Инструмент | Аргументы | Примечания |
|---|---|---|
vibe_spawn |
brief, label, tier? |
Возвращает управление сразу; воркер продолжает работу |
vibe_send |
worker_id, message |
Дописывает к заданию и запускает заново |
vibe_wait |
worker_id, timeout_seconds? |
Блокируется, пока он не завершится |
vibe_kill |
worker_id |
Останавливает его |
vibe_list |
— | Уровень, статус, затраченное время и последний результат |
tier — это fast (механическая работа с чёткой спецификацией) или good (проектирование, суждение или проверка результата воркера fast).