Architecture

SDK — это транспортный слой: он отправляет ваш запрос в Copilot CLI по JSON-RPC и возвращает события обратно в приложение. CLI — это оркестратор, который запускает цикл использования агентных инструментов, выполняя один или несколько вызовов LLM API до завершения задачи.
Цикл использования инструментов
Когда вы вызываете session.send({ prompt }), CLI входит в цикл:

Модель видит полную историю разговоров по каждому звонку — системный запрос, пользовательское сообщение и все предыдущие вызовы и результаты.
Ключевые выводы: Каждая итерация этого цикла — это ровно один вызов LLM API, видимый как одна assistant.turn_start / assistant.turn_end пара в журнале событий. Скрытых звонков нет.
Повороты — что это такое
Ход — это один вызов LLM API и его последствия:
- CLI отправляет историю разговоров в LLM
- LLM отвечает (возможно, с помощью запросов инструментов)
- Если инструменты запрашивались, CLI их выполняет
assistant.turn_endизлучается
Одно сообщение пользователя обычно приводит к нескольким ходам. Например, вопрос вроде «как работает X в этой кодовой базе?» может привести к следующему:
| Повернуть | Что делает модель | toolRequests? |
|---|---|---|
| 1 | Вызовы grep и glob поиск по кодовой базе | |
| ✅ Да | ||
| 2 | Читает конкретные файлы на основе результатов поиска | |
| ✅ Да | ||
| 3 | Читайте больше файлов для более глубокого контекста | |
| ✅ Да | ||
| 4 | Получает итоговый текстовый ответ | |
| ❌ Нет → концов петли |
Модель решает на каждом ходу, запрашивать ли дополнительные инструменты или давать окончательный ответ. Каждый звонок видит полный накопленный контекст (все предыдущие вызовы и результаты), чтобы принять обоснованное решение о том, достаточно ли у него информации.
Поток событий для многоходового взаимодействия

Кто запускает каждый ход?
| Actor | Ответственность |
|---|---|
| Ваше приложение | Отправляет первоначальный запрос через session.send() |
| Copilot CLI | Запускает цикл использования инструментов — выполняет инструменты и возвращает результаты в LLM на следующий ход |
| LLM | Решает, запрашивать ли инструменты (продолжать цикл) или давать окончательный ответ (стоп) |
| Пакет SDK | Передаёт события; не управляет циклом |
CLI чисто механический: «модель запросила инструменты → выполнить → модель вызова снова». Модель принимает решение, когда остановиться.
session.idle и session.task_complete
Это два разных сигнала завершения с очень разными гарантиями:
session.idle
- Всегда излучается , когда цикл использования инструмента заканчивается
- Эфемерный: не сохраняется на диске, не воспроизводит при возобновлении сессии
- Означает: «агент прекратил обработку и готов к следующему сообщению»
- Используйте это как надёжный сигнал «готово»
Метод SDK sendAndWait() ждёт этого события:
// Blocks until session.idle fires
const response = await session.sendAndWait({ prompt: "Fix the bug" });
session.task_complete
- Опционально излучается: требует, чтобы модель явно сигнализировала
- Сохранено: сохранено в журнал событий сессии на диске
- Означает: «агент считает выполненную общую задачу»
- Несёт дополнительное
summaryполе
session.on("session.task_complete", (event) => {
console.log("Task done:", event.data.summary);
});
Режим автопилота: CLI подталкивает к task_complete
В режиме автопилота (безголовая/автономная работа) CLI активно отслеживает, вызывала task_completeли модель . Если цикл использования инструмента заканчивается без него, CLI вводит синтетическое пользовательское сообщение, подталкивающее модель:
«Вы ещё не отметили задание как завершённое с помощью инструмента task_complete. Если вы планировали, прекратите планирование и начните внедрять. Ты не закончишь, пока полностью не выполнишь задание.»
Это фактически запускает цикл использования инструмента — модель воспринимает подталкивание как сообщение нового пользователя и продолжает работать. Подталкивание также инструктует модель не вызывать task_complete преждевременно:
- Не звоните, если у вас есть открытые вопросы — принимайте решения и продолжайте работать.
- Не вызывайте её, если нашли ошибку — попробуйте её исправить
- Не называйте её, если остались шаги — сначала выполните их
Это создаёт двухуровневый механизм завершения в автопилоте:
- Модель вызывает
task_completeс резюме→ CLIsession.task_completeизлучает → выполнено - Модель останавливается, не вызывая её, → CLI подталкивает модель → продолжает или вызывает
task_complete
Почему task_complete бы не появиться
В интерактивном режиме (обычный чат) CLI не подталкивает к task_complete. Модель может полностью его пропустить. Распространенные причины:
- Разговорные вопросы и ответы: модель отвечает на вопрос и просто останавливается — нет отдельной «задачи» для выполнения
- Дискреция модели: модель генерирует итоговый текстовый ответ без вызова сигнала завершения задачи
- Прерванные сессии: сессия заканчивается до того, как модель достигает точки завершения
CLI всё равно излучает session.idle , потому что это механический сигнал (цикл завершился), а не семантический (модель считает, что всё сделано).
Какой из них следует использовать?
| Сценарий использования | Сигнал |
|---|---|
| «Жди, пока агент закончит обработку» | |
session.idle | |
| ✅ | |
| «Знать, когда выполнена задача по программированию» | |
session.task_complete (лучшее усилие) | |
| «Тайм-аут/обработка ошибок» | |
session.idle |
session.error
✅
|
Подсчёт вызовов LLM
Количество assistant.turn_start / assistant.turn_end пар в журнале событий равно общему числу LLM API вызовов. Нет скрытых требований к планированию, оценке или проверке завершения.
Чтобы проверить количество ходов за сессию:
# Count turns in a session's event log
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl
Дополнительные материалы
- События потоковых сессий: Полный справочник на уровне поля для каждого типа событий
- АВТОТИТРЫ: Как сохраняются и возобновляются сессии
- Работа с крючками: Перехват событий в цикле (разрешения, инструменты)