API Pastukhov Agent — это способ отдавать команды агенту и получать ответы без браузера. Другие программы могут создавать чаты, отправлять промпты и забирать результаты по набору команд API: из сборочных конвейеров, внешних инструментов и обёрток. Тот же ключ открывает и расширенные возможности (чаты, навыки, модели, настройки, git, аналитику и распознавание речи) и подписку на живые события — именно так Research Agent подключается к своему полю ввода, микрофону и аналитике. Раздел ниже — справочник этих адресов для разработчиков; если вы впервые слышите об API, достаточно понять общую идею: программа общается с агентом по тем же правилам, что и человек в интерфейсе.
Аутентификация
API открывается ключом доступа, и получить его можно двумя способами. Первый — задать переменную окружения AGENT_API_KEY: в ней хранится не сам ключ, а его «отпечаток» (SHA-256 хеш — короткая строка, по которой ключ восстановить нельзя), и при каждом запросе сервер вычисляет отпечаток присланного ключа и сравнивает с сохранённым. Второй — выдать именованные ключи прямо в интерфейсе агента (Настройки → Конфигурация → «Ключи доступа»): тогда у каждого устройства или программы свой ключ, и отзыв одного не мешает остальным. Подробнее — на странице Ключи доступа.
Ключ передаётся в заголовке X-API-Key — служебном поле запроса, где программа указывает свой ключ доступа:
X-API-Key: my-secret-api-key
Для живых подключений (WebSocket/SignalR) заголовки задать нельзя, поэтому тот же ключ принимается и как параметр адреса api_key:
/svelteChatHub?api_key=my-secret-api-key
Именованные ключи вместо переменной
Проще всего выдать ключ прямо в агенте: откройте Настройки → группа «Конфигурация» → карточка «Ключи доступа» и нажмите «Сгенерировать ключ». Ключ показывается один раз — сразу скопируйте его и передайте тому устройству или программе, для которых он создан. В файле keys.yml внутри проекта остаётся только солёный хеш: соль — общая случайная строка, а сам ключ из файла восстановить нельзя, поэтому файл безопасно хранить и коммитить в репозиторий. Отозвать доступ можно одним удалением ключа из списка, не трогая остальные.
Для запросов разницы нет: именованный ключ передаётся тем же заголовком X-API-Key. Вид у него такой — agent_ и ещё 32 случайных символа; по приставке ключ легко узнать среди других ключей и токенов. Как выдать ключ, как он выглядит в списке и что именно открывает, — на странице Ключи доступа.
Как получить хеш ключа
Если удобнее один ключ из переменной окружения, его отпечаток можно вычислить на странице входа приложения (кнопка «SHA256-генератор» под формой входа) или вручную:
# Linux / macOS
echo -n "my-secret-api-key" | sha256sum | awk '{print $1}'
# Windows PowerShell
$hash = [System.BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([System.Text.Encoding]::UTF8.GetBytes("my-secret-api-key"))).Replace("-", "").ToLower()
$hash
Полученный отпечаток укажите в AGENT_API_KEY (переменная уровня приложения, задаётся до запуска — системной переменной, аргументом командной строки или через файл .env в корне проекта).
Коды при ошибках аутентификации
- 401 Unauthorized — ключ не передан или неверный: «Invalid or missing API key». Неверный ключ отклоняется на любом адресе API — даже если рядом передан правильный токен входа;
- 503 Service Unavailable — Remote API выключен: не задана переменная
AGENT_API_KEYи в файлеkeys.ymlнет ни одного ключа. Сообщение называет оба источника: «AGENT_API_KEY environment variable is not set and keys.yml defines no keys».
Команды /api/remote
Каждая команда — это отдельный адрес, по которому программа обращается к серверу, чтобы что-то получить или сделать. Все команды /api/remote описаны ниже.
Создание чата
POST /api/remote/chats
Создаёт новый чат. Промпт, если он передан, ставится в очередь и обрабатывается автоматически — напрямую он не отправляется. Чат можно дополнительно привязать к боту (botId); привязка «молчаливая»: она никогда не спамит в Telegram и не может помешать созданию чата, а её исход возвращается флагами botLinked и botLinkNote.
Тело запроса
prompt(опц.) — начальное сообщение; при наличии чат создаётся со статусомqueued, без него —created;title(опц.) — название чата (по умолчанию «Remote API Chat»);model(опц.) — модель для чата (см. Модели);skill(опц.) — навык; отсутствие = «none» (без наследования);systemPrompt(опц.) — системный промпт, сохраняется на чате;botId(опц.) — id бота для молчаливой привязки чата.
Ответ (201 Created)
{
"chatId": 123,
"url": "/123",
"status": "queued",
"createdAt": "2026-09-04T10:00:00Z",
"botLinked": null,
"botLinkNote": ""
}
Пример
curl -X POST http://localhost:5173/api/remote/chats \
-H "X-API-Key: my-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Explain what this code does",
"title": "Code Analysis",
"model": "claude-sonnet"
}'
Статус чата
GET /api/remote/chats/{chatId}/status
Возвращает текущий статус обработки: processing — агент работает, queued — чат свободен, но в его очереди есть сообщения, иначе completed. Вместе со статусом приходят заголовок, метки времени, количество сообщений и накопленная стоимость. Поле error в ответе всегда пустое.
{
"chatId": 123,
"status": "processing",
"title": "Code Analysis",
"createdAt": "2026-09-04T10:00:00Z",
"updatedAt": "2026-09-04T10:00:15Z",
"messageCount": 2,
"totalCost": 0.005
}
Пример:
curl http://localhost:5173/api/remote/chats/123/status \
-H "X-API-Key: my-secret-api-key"
Сообщения чата
GET /api/remote/chats/{chatId}/messages?since={timestamp}
Инкрементальное чтение сообщений — программа забирает только то, что появилось после указанной метки, и не разбирает всю историю заново. Параметр since (ISO 8601) возвращает сообщения от указанной метки включительно и сам отражается в ответе; неверное значение since молча игнорируется — возвращается полная история. Содержимое упрощается по типу: сообщение пользователя — его текст; ответ агента — текст без разметки кнопок; ошибка — текст ошибки; использование инструмента — Tool: <имя>.
{
"chatId": 123,
"messages": [
{
"id": 456,
"role": "user",
"content": "Explain what this code does",
"createdAt": "2026-09-04T10:00:00Z",
"tokens": { "input": 120, "output": 0 },
"cost": 0.0001
},
{
"id": 457,
"role": "assistant",
"content": "This module handles ...",
"createdAt": "2026-09-04T10:00:20Z",
"tokens": { "input": 140, "output": 320 },
"cost": 0.003
}
],
"since": "2026-09-04T10:00:00Z"
}
Примеры:
# Все сообщения
curl http://localhost:5173/api/remote/chats/123/messages \
-H "X-API-Key: my-secret-api-key"
# Только новые с указанной метки
curl "http://localhost:5173/api/remote/chats/123/messages?since=2026-09-04T10:00:10Z" \
-H "X-API-Key: my-secret-api-key"
Очередь промптов
Пять команд под /api/remote/chats/{chatId}/queue управляют промптами, ожидающими отправки агенту. В отличие от внутренних команд очереди, удалённые строже: неизвестный чат или промпт, которого нет в очереди (никогда не было, принадлежит другому чату или уже отправлен), — ошибка 404; пустой или состоящий из пробелов текст — 400.
Список очереди
GET /api/remote/chats/{chatId}/queue
Очередь в порядке отправки: id, prompt, isPaused, model (переопределение для сообщения), createdAt. Приостановленные промпты включены и помечены isPaused.
{
"chatId": 123,
"prompts": [
{
"id": 456,
"prompt": "Refactor the auth module",
"isPaused": false,
"model": "",
"createdAt": "2026-09-04T10:00:00Z"
},
{
"id": 457,
"prompt": "Then update the README",
"isPaused": true,
"model": "claude-sonnet",
"createdAt": "2026-09-04T10:01:00Z"
}
]
}
Добавить промпт в конец очереди
POST /api/remote/chats/{chatId}/queue
Дописывает промпт в конец очереди (как любой другой источник сообщений). prompt обязателен и непустой; model — необязательное переопределение модели для этого сообщения. Ответ 201 — добавленный промпт с его id.
curl -X POST http://localhost:5173/api/remote/chats/123/queue \
-H "X-API-Key: my-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Now add unit tests for the refactored module"
}'
Переписать текст одного промпта
PUT /api/remote/chats/{chatId}/queue/{promptId}
Изменяет только текст: id, позиция, модель и пауза строки сохраняются. 400 при пустом тексте; 404, если промпта нет в очереди этого чата или он уже отправлен.
curl -X PUT http://localhost:5173/api/remote/chats/123/queue/456 \
-H "X-API-Key: my-secret-api-key" \
-H "Content-Type: application/json" \
-d '{ "prompt": "Refactor the auth module and update the docs" }'
Удалить один промпт
DELETE /api/remote/chats/{chatId}/queue/{promptId}
Удаляет промпт из очереди; успех — 204 No Content.
curl -X DELETE http://localhost:5173/api/remote/chats/123/queue/456 \
-H "X-API-Key: my-secret-api-key"
Заменить очередь целиком
PUT /api/remote/chats/{chatId}/queue
Переданный массив становится всей очередью. Правила замены:
- элемент с
id, совпавшим с существующим, сохраняет идентичность — ту же строку, модель и паузу (еслиisPausedне задан явно); - элемент без
id(или сid: 0) создаёт новый промпт; - существующие промпты, которых нет в массиве, удаляются — включая добавленные другими источниками после вашего последнего чтения (last writer wins);
- порядок массива становится порядком диспетчеризации — перестановка массива меняет очередь;
- пустой массив (
[]) очищает очередь; - id уже отправленного промпта пропускается (не воскрешается) — повторная отправка продублировала бы сообщение, которое агент уже обрабатывает.
Ошибки 400: массив не передан; любой элемент с пустым текстом; один и тот же положительный id встречается дважды.
curl -X PUT http://localhost:5173/api/remote/chats/123/queue \
-H "X-API-Key: my-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompts": [
{ "id": 457, "prompt": "Refactor the auth module (edited)" },
{ "prompt": "Then update the README" }
]
}'
Список ботов
GET /api/remote/bots
Только чтение: каждый настроенный бот возвращается с id, title, enabled, running и pollingError — достаточно, чтобы внешняя программа показала ботов со статусными точками. Никаких токенов, промптов и управления: боты настраиваются только в интерфейсе Pastukhov Agent.
{
"bots": [
{
"id": "release-bot",
"title": "Release Bot",
"enabled": true,
"running": true,
"pollingError": null
}
]
}
Статусы чата
created | чат создан без начального промпта, ждёт ввода |
queued | чат создан с промптом, сообщение в очереди |
processing | агент обрабатывает сообщение |
completed | все сообщения обработаны, чат бездействует |
error | ошибка обработки (в удалённом API поле error в ответе всегда пустое) |
Расширенная поверхность по API-ключу
Тот же ключ открывает гораздо больше, чем /api/remote. Передав его на эти пути, вы действуете под ролью Manager — как при входе менеджером. Именованный ключ из keys.yml даёт ровно те же права, а его удаление или перегенерация действуют сразу, без перезапуска агента:
/api/chats,/api/chat— чтение чатов и работа с ними;/svelteChatHub— живое соединение SignalR (см. ниже);/api/skills— навыки (список, выбор);/api/models— модели (список, выбор);/api/autofix— статус и переключение автоисправления;/api/settings— настройки (settings/all,settings/set);/api/skills-settings— цвета навыков изskills.yml;/api/git— статус и коммит рабочего репозитория;/api/MessageQueue— правка, удаление, пауза очереди сообщений;/api/analytics— аналитика чатов (только чтение);/api/chat-labels— метки чатов: список, создание, изменение и назначение (файлlabels.yml);/api/files— загрузка файлов в рабочую папку агента (изображения и файлы из буфера обмена);/api/speechrecognition— транскрибация аудио движками распознавания речи;/api/build— сборки: запуск, состояние и вывод (trigger,status,output);/api/deploy— развёртывания: запуск, остановка, перезапуск, состояние и вывод.
Сборки и развёртывания. POST /api/build/trigger/{имя} запускает сборку, GET /api/build/status[/{имя}] отдаёт состояние и число ошибок и предупреждений, GET /api/build/output/{имя} — текст вывода. Для развёртываний: POST /api/deploy/start|stop|restart/{имя}, GET /api/deploy/status[/{имя}], GET /api/deploy/output/{имя}. Запуск уже идущей сборки игнорируется, повторный запуск развёртывания ничего не меняет, а restart — это остановка, короткая пауза и запуск. Неизвестное имя сборки отвечает 404, а неизвестное имя развёртывания всё равно отвечает успехом — ничего не запускается, поэтому проверяйте результат адресом состояния.
Когда ключ не задан или не передан, эти пути работают как раньше — по обычному входу в интерфейс. Ничего не ломается: хранилище ключей и вход в систему сосуществуют.
Подписка на живые события (SignalR)
Вместо постоянных опросов статуса внешняя система может подписаться на живые события — получать уведомления, когда в чатах что-то происходит. Подключитесь к /svelteChatHub, передав ключ заголовком X-API-Key или параметром адреса api_key (для WebSocket обязателен параметр адреса — заголовки задать нельзя):
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5173/svelteChatHub?api_key=my-secret-api-key")
.build();
connection.on("messageUpdate", (chatId, message) => {
console.log("Новое сообщение в чате", chatId, message.content);
});
connection.start();
События приходят при изменениях: новые сообщения, обновления чатов (включая статусы обработки), изменения очереди сообщений и промптов, смена настроек, навыков и моделей. Для соединений включено аккуратное переподключение — разрыв не теряет подписку. Именно так Research Agent показывает интерфейс Pastukhov Agent.
Пример рабочего потока
Типичный сценарий: создать чат → опрашивать статус → забрать сообщения → дописать промпт в очередь → заменить очередь. Полный цикл на Python:
import time, requests
API_KEY = "my-secret-api-key"
BASE = "http://localhost:5173/api/remote"
H = {"X-API-Key": API_KEY}
# 1. Создать чат — промпт встанет в очередь
resp = requests.post(f"{BASE}/chats", headers=H, json={
"prompt": "Add error handling to the login endpoint",
"title": "Error Handling",
"model": "claude-sonnet"
})
chat_id = resp.json()["chatId"]
# 2. Опрашивать статус до завершения
while True:
status = requests.get(f"{BASE}/chats/{chat_id}/status", headers=H).json()["status"]
if status in ("completed", "error"):
break
time.sleep(2)
# 3. Забрать ответы (инкрементально через since)
messages = requests.get(f"{BASE}/chats/{chat_id}/messages", headers=H).json()["messages"]
for msg in messages:
if msg["role"] == "assistant":
print(msg["content"])
# 4. Дописать follow-up в конец очереди
requests.post(f"{BASE}/chats/{chat_id}/queue", headers=H,
json={"prompt": "Now add unit tests"})
# 5. Заменить очередь целиком
requests.put(f"{BASE}/chats/{chat_id}/queue", headers=H, json={
"prompts": [
{"prompt": "Fix the auth flow"},
{"prompt": "Update the README"}
]
})
Формат ошибок
Все ошибки следуют единому формату {error, message, details}:
{
"error": "NotFound",
"message": "Chat 123 not found",
"details": ""
}
Unauthorized— 401, ключ не передан или неверный;BadRequest— 400, неверное тело запроса (пустой промпт, дубль id, нет массива);NotFound— 404, чат или промпт не найден;Remote API is disabled— 503, не задана переменнаяAGENT_API_KEYи вkeys.ymlнет ни одного ключа;InternalServerError— 500, неожиданная ошибка сервера (detailsсодержит текст исключения).
Связанные разделы
- Удалённое управление через Яндекс.Диск — файловая очередь и десктоп-приложение AgentRemote;
- Управление очередью из интерфейса — диалог промптов и серверный AutoSend;
- Модели — какие модели можно передавать в
model. - Ключи доступа — выдача ключей в интерфейсе, файл
keys.ymlи правила безопасности.