Skip to main content

API

API Велеса живет внутри процесса veles gateway. Его используют Nerve, интеграции и служебные клиенты, которым нужен доступ к состоянию шлюза, сессиям, задачам, файлам рабочей области, личностям и вызовам моделей. Интерфейс делится на два транспорта:
  • HTTP-маршруты для простых операций, загрузки вложений и доски задач.
  • WebSocket JSON-RPC на /ws для интерактивного управления сессиями, чатом, файлами, личностями и секретами.

Адрес и авторизация

Хост, порт и токен задаются в gateway-разделе config.json:
{
  "gateway": {
    "host": "127.0.0.1",
    "port": 18790,
    "token": "..."
  }
}
Токен можно задать и через переменную окружения VELES_GATEWAY_TOKEN (она переопределяет значение из config.json, в том числе при запуске с уже существующим файлом конфигурации). Если токен не задан вообще, gateway не запускается, а любые запросы получают 401. HTTP-запросы должны передавать токен в заголовке:
Authorization: Bearer <gateway.token>
При отсутствии или несовпадении токена HTTP-маршруты отвечают 401 Unauthorized с заголовком WWW-Authenticate: Bearer realm="veles-gateway". Сравнение токена выполняется в постоянном времени (compare_digest). WebSocket-клиент сначала подключается к /ws. Сразу после accept gateway присылает событие connect.challenge со случайным одноразовым nonce:
{
  "type": "event",
  "event": "connect.challenge",
  "payload": { "nonce": "kZ8s...generated" },
  "seq": 1
}
Затем клиент отправляет JSON-RPC запрос connect с токеном. Поддерживаются две формы параметров: вложенная auth.token (предпочтительно) и плоская token.
{
  "type": "req",
  "id": "connect-1",
  "method": "connect",
  "params": {
    "auth": {
      "token": "<gateway.token>"
    }
  }
}
До успешного connect любой другой метод возвращает ошибку -32001 Unauthorized, а входящие/исходящие события не доставляются клиенту. Успешный ответ:
{
  "type": "res",
  "id": "connect-1",
  "ok": true,
  "payload": {
    "protocol": 3,
    "server": "veles"
  }
}

Формат WebSocket RPC

Запросы имеют общий вид:
{
  "type": "req",
  "id": "request-id",
  "method": "sessions.history",
  "params": {}
}
Ответы:
{
  "type": "res",
  "id": "request-id",
  "ok": true,
  "payload": {}
}
Ошибки:
{
  "type": "res",
  "id": "request-id",
  "ok": false,
  "error": {
    "code": -32602,
    "message": "validation message"
  }
}
Gateway также отправляет события с type: "event". У события всегда есть поля event (имя), payload (данные) и seq (монотонный счётчик событий gateway для упорядочивания и восстановления после переподключения):
{
  "type": "event",
  "event": "chat",
  "payload": { "...": "..." },
  "seq": 42
}
Основные события: connect.challenge при подключении и chat для потока сообщений ассистента и пользователя.

Коды ошибок

Ошибки возвращаются в поле error с числовым code (совместимым с JSON-RPC) и человекочитаемым message:
CodeКогда возникает
-32700Тело запроса не является валидным JSON.
-32601Неизвестный метод.
-32602Ошибка валидации параметров (ValueError в обработчике).
-32001Не пройдена авторизация: отсутствует или неверен токен.
-32000Внутренняя ошибка обработчика.

HTTP endpoints

MethodRouteНазначение
GET/healthПроверка доступности gateway.
GET/statusОбщий статус gateway, модели, thinking, каналов, сессий и task storage.
POST/tools/invokeСовместимый HTTP-вызов отдельных gateway tools.
POST/attachments/uploadЗагрузка вложения в workspace с привязкой к x-session-key.
GET/POST/api/personalities/selectLLM-выбор лучшей Personality для пользовательского запроса.
GET/api/tasksСписок задач с фильтрами status, priority, assignee, label, q, limit, offset.
POST/api/tasksСоздание задачи.
GET/api/tasks/configКонфигурация task board.
PUT/api/tasks/configОбновление конфигурации task board.
GET/api/tasks/proposalsСписок предложений ассистента для задач.
POST/api/tasks/proposalsСоздание предложения.
POST/api/tasks/proposals/{proposal_id}/approveПринять предложение.
POST/api/tasks/proposals/{proposal_id}/rejectОтклонить предложение.
GET/api/tasks/{task_id}Получить задачу.
PATCH/api/tasks/{task_id}Обновить задачу.
DELETE/api/tasks/{task_id}Удалить задачу.
POST/api/tasks/{task_id}/reorderПереместить задачу между колонками или позициями.
POST/api/tasks/{task_id}/executeЗапустить выполнение задачи в выбранной сессии.
POST/api/tasks/{task_id}/completeЗаписать результат выполнения задачи.
POST/api/tasks/{task_id}/approveПодтвердить выполненную задачу.
POST/api/tasks/{task_id}/rejectОтклонить выполненную задачу.
POST/api/tasks/{task_id}/abortПрервать выполнение задачи.

Выбор личности

Endpoint GET /api/personalities/select?query=... и POST /api/personalities/select используют модель по умолчанию, чтобы выбрать подходящую Personality по тексту запроса. Этот служебный выбор вызывается без reasoning/thinking effort, чтобы не тратить расширенное рассуждение на маршрутизацию. Промпт ограничивает выбор списком реально настроенных personalityId, а backend проверяет, что выбранный идентификатор существует. Nerve также проксирует этот contract через свой POST /api/personalities/select, чтобы окно нового диалога могло предложить режим Подобрать без прямого доступа браузера к gateway token. Тело POST:
{
  "query": "Нужно проверить PR и найти регрессии"
}
Ответ:
{
  "personalityId": "reviewer",
  "personality": {
    "personalityId": "reviewer",
    "id": "reviewer",
    "name": "Reviewer",
    "model": null,
    "thinkingLevel": "high",
    "isDefault": false,
    "rootSessionKey": "personality:reviewer:main"
  },
  "reason": "Запрос требует ревью кода и поиска рисков.",
  "confidence": 0.91,
  "model": "openrouter/...",
  "candidateCount": 3,
  "usage": {}
}
SOUL.md всех личностей передается модели для выбора, но не возвращается в поле personality.

Загрузка вложений

POST /attachments/upload принимает raw body файла и заголовки:
HeaderЗначение
x-session-keyСессия, к которой относится вложение.
x-attachment-nameИмя файла.
x-attachment-mime-typeMIME type.
x-attachment-kindОпциональный тип: image, audio, voice, file.
Ответ содержит объект вложения с id, workspacePath, absolutePath, mimeType и другими полями. Nerve затем передает такие объекты в chat.send как attachmentRefs.

Вызов tools по HTTP

POST /tools/invoke — это HTTP-обёртка над частью операций gateway, удобная для клиентов без WebSocket-соединения. Тело запроса:
{
  "tool": "sessions_list",
  "args": {},
  "sessionKey": "web:default"
}
Ответ:
{
  "ok": true,
  "result": { "...": "..." }
}
Ошибки возвращаются как { "ok": false, "error": { "message": "..." } } (HTTP 400 для невалидного тела или ошибки аргументов). Поддерживаемые значения tool:
toolНазначение
sessions_listСписок сессий (аналог sessions.list).
sessions_historyИстория диалога по sessionKey/conversationId/sessionId.
session_statusИзменить model/thinkingLevel сессии.
sessions_spawnСоздать дочернюю сессию и отправить в неё задачу.
cronУправление расписаниями: list, add, update, delete, run, runs.
tasksОперации с доской задач (зеркало части /api/tasks).
memory_storeNo-op ({ "stored": false, "mode": "noop" }); память хранится навыком, а не gateway.
subagentsВозвращает пустой список (зарезервировано).
Для интерактивного управления чатом и сессиями предпочитайте WebSocket RPC — /tools/invoke рассчитан на скриптовые и служебные вызовы.

WebSocket RPC methods

Статус

MethodНазначение
statusСтатус gateway и текущей или указанной сессии.
openrouter.balanceБаланс OpenRouter, если настроен OpenRouter API key.

Чат

MethodНазначение
chat.sendОтправить сообщение в сессию. Поддерживает sessionKey, conversationId, message, attachmentRefs, idempotencyKey, deliver.
chat.abortОстановить активный ответ в сессии.
chat.historyПолучить историю сообщений по sessionKey, conversationId или sessionId.
События ответа ассистента приходят через WebSocket event chat. Поле state определяет фазу:
stateЗначение
startedАссистент начал новый ответ (новый runId).
deltaПромежуточный фрагмент ответа или обновление прогресса инструментов.
finalФинальное сообщение. Приходит и для сообщений ассистента, и для входящих сообщений пользователя из других каналов (role: "user").
abortedОтвет остановлен через chat.abort.
Поля payload события chat:
ПолеОписание
sessionKey, sourceSessionKeyКлюч сессии события.
stateФаза ответа (см. выше).
runIdИдентификатор текущего ответа; стабилен для всех событий одного ответа.
seqПорядковый номер события внутри сессии (для упорядочивания/дедупликации).
totalTokens, contextTokensСчётчики токенов сессии, если доступны.
conversationId, conversationKey, rootSessionKeyПривязка к корневому диалогу Nerve (только для root-сессий).
toolEvents, toolHintПрогресс инструментов и флаг активности инструмента.
messageОбъект сообщения: role, content, timestamp (ms), а также toolEvents, toolHint, attachments при наличии. Присутствует для delta/final.
error, errorMessageТекст ошибки, если ответ завершился ошибкой.
Клиент группирует события по runId, применяет delta поверх накопленного текста и фиксирует ответ на final.

Сессии

MethodНазначение
sessions.listАктивные и технические сессии.
sessions.historyИстория корневых диалогов Nerve.
sessions.createСоздать новый корневой диалог.
sessions.activateАктивировать сохраненный корневой диалог.
sessions.getПолучить summary сессии или диалога.
sessions.patchОбновить label, model, thinkingLevel или parentId.
sessions.resetОчистить live session.
sessions.deleteУдалить или скрыть сессию/диалог.
Ключи корневых сессий Personality имеют вид personality:<id>:main.

Личности

MethodНазначение
personalities.listСписок Personality из workspace.
personalities.selectLLM-выбор лучшей Personality для запроса.
personalities.getПолучить одну Personality.
personalities.createСоздать Personality и root session.
personalities.patchОбновить имя, SOUL.md, модель или thinkingLevel.
personalities.deleteУдалить не-main Personality и связанную root-history.

Файлы workspace

MethodНазначение
personalities.files.listСписок top-level файлов workspace.
personalities.files.getLegacy-чтение workspace-файла по имени.
personalities.files.setLegacy-запись workspace-файла по имени.
personalities.files.treeДерево файлов workspace.
personalities.files.readЧтение файла по workspace path.
personalities.files.writeЗапись файла по workspace path.
personalities.files.downloadInfoМетаданные для скачивания файла.
personalities.files.downloadChunkЧтение чанка файла.
personalities.files.deleteУдаление файла.
Файловые методы принимают personalityId, но workspace сейчас общий: Personality не создает отдельный workspace. Исключение - собственные файлы Personality внутри personalities/<id>/.

Навыки

MethodНазначение
personalities.skills.catalogЭффективный каталог навыков для Personality с учетом overlay порядка: personality, workspace, built-in.

Секреты

MethodНазначение
secrets.catalogКаталог secret targets и статусов.
secrets.setСохранить секрет.
secrets.deleteУдалить секрет.
secrets.refreshПеречитать runtime secrets и hot-swap provider/tool config.
secrets.oauth.startНачать OAuth flow.
secrets.oauth.statusПроверить OAuth flow.
secrets.oauth.completeЗавершить OAuth flow.
secrets.oauth.deleteУдалить OAuth profile.

LLM

MethodНазначение
llm.chatНебольшой authenticated LLM chat request для control API callers. Поддерживает messages, tools, model, maxTokens, temperature, toolChoice.
llm.chat предназначен для control flows, а не для обычных пользовательских сессий. Для пользовательского чата используйте chat.send.

Пример жизненного цикла WebSocket-клиента

Минимальный сценарий «подключиться и отправить сообщение»:
1. Открыть WebSocket на ws://<host>:<port>/ws
2. Получить event "connect.challenge" с nonce
3. Отправить req "connect" с { auth: { token } }
   → res ok: { protocol: 3, server: "veles" }
4. (опц.) Отправить req "status" → текущая модель, thinking, активная сессия
5. Отправить req "chat.send" с { sessionKey, message }
   → res ok: { runId, status: "started" }
6. Принимать event "chat":
     state "started" → начался ответ runId
     state "delta"   → дописать payload.message.content
     state "final"   → ответ готов; зафиксировать сообщение
7. (опц.) req "chat.abort" с { sessionKey } для остановки
runId и seq позволяют клиенту переподключиться и восстановить состояние без дублирования сообщений: события одного ответа разделяют runId, а seq задаёт их порядок.

Совместимость с Nerve

Nerve поверх этого API имеет собственные HTTP routes, но состояние задач, Personality, файлов, сессий и чата остается на стороне Veles gateway. Если добавляется новая backend-возможность для Nerve, сначала стоит определить gateway RPC или HTTP contract здесь, а затем проксировать его на стороне Nerve.
Канонический источник истины — код gateway: HTTP-маршруты в veles/api/routes.py, диспетчер RPC в veles/api/ws_handler.py, схема gateway в veles/config/schema.py. При изменении контрактов обновляйте эту страницу (см. инструкцию в AGENTS.md).