API-сервер

API-сервер отдаёт hermes-agent наружу как OpenAI-совместимый HTTP-эндпоинт. Любой фронтенд, который говорит на формате OpenAI — Open WebUI, LobeChat, LibreChat, NextChat, ChatBox и сотни других — подключается к hermes-agent и использует его как бэкенд.

Агент обрабатывает запросы со всем своим набором инструментов (терминал, операции с файлами, веб-поиск, память, навыки) и возвращает итоговый ответ. При стриминге индикаторы прогресса инструментов идут прямо в потоке, так что фронтенд показывает, чем агент занят прямо сейчас.

совет
Один бэкенд закрывает и модели, и инструменты

Чтобы API-сервер приносил пользу, самому Hermes нужны настроенный провайдер и бэкенды инструментов. Подписка Nous Portal закрывает и то и другое — 300+ моделей плюс веб/изображения/TTS/браузер через Tool Gateway. Выполните hermes setup --portal один раз перед запуском API-сервера, и фронтенды вроде Open WebUI или LobeChat получат полностью оснащённый инструментами бэкенд.

Быстрый старт

1. Включите API-сервер

Добавьте в ~/.hermes/.env:

API_SERVER_ENABLED=true
API_SERVER_KEY=change-me-local-dev
# Опционально: только если браузер должен обращаться к Hermes напрямую
# API_SERVER_CORS_ORIGINS=http://localhost:3000

2. Запустите шлюз

hermes gateway

Вы увидите:

[API Server] API server listening on http://127.0.0.1:8642

3. Подключите фронтенд

Направьте любой OpenAI-совместимый клиент на http://localhost:8642/v1:

# Проверка через curl
curl http://localhost:8642/v1/chat/completions \
  -H "Authorization: Bearer change-me-local-dev" \
  -H "Content-Type: application/json" \
  -d '{"model": "hermes-agent", "messages": [{"role": "user", "content": "Hello!"}]}'

Либо подключите Open WebUI, LobeChat или любой другой фронтенд — пошаговые инструкции смотрите в руководстве по интеграции Open WebUI.

Эндпоинты

POST /v1/chat/completions

Стандартный формат OpenAI Chat Completions. Без состояния — полная переписка передаётся в каждом запросе через массив messages.

Запрос:

{
  "model": "hermes-agent",
  "messages": [
    {"role": "system", "content": "You are a Python expert."},
    {"role": "user", "content": "Write a fibonacci function"}
  ],
  "stream": false
}

Ответ:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1710000000,
  "model": "hermes-agent",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "Here's a fibonacci function..."},
    "finish_reason": "stop"
  }],
  "usage": {"prompt_tokens": 50, "completion_tokens": 200, "total_tokens": 250}
}

Изображения во входных данных: пользовательские сообщения могут передавать content массивом из частей text и image_url. Поддерживаются и удалённые URL по http(s), и URL вида data:image/...:

{
  "model": "hermes-agent",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What is in this image?"},
        {"type": "image_url", "image_url": {"url": "https://example.com/cat.png", "detail": "high"}}
      ]
    }
  ]
}

Загруженные файлы (file / input_file / file_id) и URL data:, не являющиеся изображениями, возвращают 400 unsupported_content_type.

Стриминг ("stream": true): возвращает Server-Sent Events (SSE) с кусками ответа токен за токеном. Для Chat Completions в потоке используются стандартные события chat.completion.chunk плюс собственное событие Hermes hermes.tool.progress для UX начала работы инструмента. Для Responses в потоке используются типы событий OpenAI Responses, такие как response.created, response.output_text.delta, response.output_item.added, response.output_item.done и response.completed.

Прогресс инструментов в потоках:

  • Chat Completions: Hermes отправляет event: hermes.tool.progress, чтобы показать начало работы инструмента, не засоряя сохраняемый текст ассистента.
  • Responses: Hermes отправляет элементы вывода function_call и function_call_output по спецификации прямо во время SSE-потока, поэтому клиенты могут рисовать структурированный UI инструментов в реальном времени.

POST /v1/responses

Формат OpenAI Responses API. Поддерживает серверное состояние переписки через previous_response_id — сервер хранит полную историю разговора (включая вызовы инструментов и их результаты), так что многоходовой контекст сохраняется без управления им со стороны клиента.

Запрос:

{
  "model": "hermes-agent",
  "input": "What files are in my project?",
  "instructions": "You are a helpful coding assistant.",
  "store": true
}

Ответ:

{
  "id": "resp_abc123",
  "object": "response",
  "status": "completed",
  "model": "hermes-agent",
  "output": [
    {"type": "function_call", "name": "terminal", "arguments": "{\"command\": \"ls\"}", "call_id": "call_1"},
    {"type": "function_call_output", "call_id": "call_1", "output": "README.md src/ tests/"},
    {"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "Your project has..."}]}
  ],
  "usage": {"input_tokens": 50, "output_tokens": 200, "total_tokens": 250}
}

Изображения во входных данных: input[].content может содержать части input_text и input_image. Поддерживаются и удалённые URL, и URL вида data:image/...:

{
  "model": "hermes-agent",
  "input": [
    {
      "role": "user",
      "content": [
        {"type": "input_text", "text": "Describe this screenshot."},
        {"type": "input_image", "image_url": "data:image/png;base64,iVBORw0K..."}
      ]
    }
  ]
}

Загруженные файлы (input_file / file_id) и URL data:, не являющиеся изображениями, возвращают 400 unsupported_content_type.

Многоходовой режим с previous_response_id

Сцепляйте ответы, чтобы держать полный контекст (включая вызовы инструментов) между ходами:

{
  "input": "Now show me the README",
  "previous_response_id": "resp_abc123"
}

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

Именованные разговоры

Используйте параметр conversation вместо отслеживания идентификаторов ответов:

{"input": "Hello", "conversation": "my-project"}
{"input": "What's in src/?", "conversation": "my-project"}
{"input": "Run the tests", "conversation": "my-project"}

Сервер автоматически сцепляет запрос с последним ответом в этом разговоре. Похоже на команду /title для сессий шлюза.

GET /v1/responses/{id}

Получить ранее сохранённый ответ по идентификатору.

DELETE /v1/responses/{id}

Удалить сохранённый ответ.

GET /v1/models

Выдаёт агента как доступную модель. Анонсируемое имя модели по умолчанию совпадает с именем профиля (или hermes-agent для профиля по умолчанию). Большинству фронтендов оно нужно для обнаружения моделей.

GET /v1/capabilities

Возвращает машиночитаемое описание стабильной поверхности API-сервера для внешних UI, оркестраторов и мостов-плагинов.

{
  "object": "hermes.api_server.capabilities",
  "platform": "hermes-agent",
  "model": "hermes-agent",
  "auth": {"type": "bearer", "required": true},
  "features": {
    "chat_completions": true,
    "responses_api": true,
    "run_submission": true,
    "run_status": true,
    "run_events_sse": true,
    "run_stop": true
  }
}

Обращайтесь к этому эндпоинту при интеграции дашбордов, браузерных UI или панелей управления — так они узнают, поддерживает ли запущенная версия Hermes прогоны, стриминг, отмену и непрерывность сессий, не завязываясь на приватные внутренности Python.

GET /health

Проверка здоровья. Возвращает {"status": "ok"}. Доступна также по GET /v1/health для OpenAI-совместимых клиентов, которые ждут префикс /v1/.

GET /health/detailed

Расширенная проверка здоровья: дополнительно сообщает об активных сессиях, запущенных агентах и потреблении ресурсов. Пригодится для инструментов мониторинга и наблюдаемости.

Runs API (удобная альтернатива со стримингом)

Помимо /v1/chat/completions и /v1/responses, сервер отдаёт API runs — для длинных сессий, где клиент хочет подписаться на события прогресса, а не управлять стримингом сам.

POST /v1/runs

Создать новый прогон агента. Возвращает run_id, по которому можно подписаться на события прогресса.

{
  "run_id": "run_abc123",
  "status": "started"
}

Прогоны принимают простую строку input и опциональные session_id, instructions, conversation_history или previous_response_id. Если задан session_id, Hermes выводит его в статусе прогона, чтобы внешние UI могли сопоставить прогоны со своими идентификаторами разговоров.

GET /v1/runs/{run_id}

Опросить текущее состояние прогона. Удобно для дашбордов, которым нужен статус без удержания открытого SSE-соединения, и для UI, которые переподключаются после навигации.

{
  "object": "hermes.run",
  "run_id": "run_abc123",
  "status": "completed",
  "session_id": "space-session",
  "model": "hermes-agent",
  "output": "Done.",
  "usage": {"input_tokens": 50, "output_tokens": 200, "total_tokens": 250}
}

Статусы недолго держатся после финальных состояний (completed, failed или cancelled) — для опроса и согласования состояния в UI.

GET /v1/runs/{run_id}/events

Поток Server-Sent Events с прогрессом вызовов инструментов, дельтами токенов и событиями жизненного цикла прогона. Сделан для дашбордов и толстых клиентов, которым нужно подключаться и отключаться, не теряя состояния.

POST /v1/runs/{run_id}/stop

Прервать текущий ход агента. Эндпоинт сразу возвращает {"status": "stopping"}, пока Hermes просит активного агента остановиться в ближайшей безопасной точке прерывания.

POST /v1/runs/{run_id}/approval

Разрешить ожидающее подтверждение для прогона, который встал на человеческое решение (например, вызов инструмента, закрытый политикой согласования). Тело запроса содержит решение об одобрении; прогон возобновляется, как только решение зафиксировано. Эндпоинт анонсируется в /v1/capabilities как возможность run_approval, чтобы внешние UI определяли поддержку перед тем, как показывать пользователю запрос на подтверждение.

Jobs API (фоновые задачи по расписанию)

Сервер отдаёт лёгкий CRUD-интерфейс задач для управления фоновыми прогонами агента по расписанию с удалённого клиента. Все эндпоинты закрыты той же bearer-авторизацией.

GET /api/jobs

Список всех задач по расписанию.

POST /api/jobs

Создать новую задачу по расписанию. Тело принимает ту же форму, что и hermes cron — промпт, расписание, навыки, переопределение провайдера, цель доставки.

GET /api/jobs/{job_id}

Получить определение одной задачи и состояние её последнего запуска.

PATCH /api/jobs/{job_id}

Обновить поля существующей задачи (промпт, расписание и т. д.). Частичные обновления сливаются.

DELETE /api/jobs/{job_id}

Удалить задачу. Заодно отменяет любой выполняющийся прогон.

POST /api/jobs/{job_id}/pause

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

POST /api/jobs/{job_id}/resume

Возобновить ранее приостановленную задачу.

POST /api/jobs/{job_id}/run

Запустить задачу немедленно, вне расписания.

Sessions API (управление сессиями через REST)

Внешние UI могут управлять сессиями Hermes через REST, не поднимая дашборд. Все эндпоинты закрыты ключом API_SERVER_KEY и живут под /api/sessions/*.

МетодПутьОписание
GET/api/sessionsСписок сессий (с пагинацией — limit, offset, source, include_children)
POST/api/sessionsСоздать пустую сессию
GET/api/sessions/{id}Прочитать метаданные сессии
PATCH/api/sessions/{id}Обновить заголовок или end_reason
DELETE/api/sessions/{id}Удалить сессию
GET/api/sessions/{id}/messagesИстория сообщений сессии
POST/api/sessions/{id}/forkОтветвить сессию через родословную SessionDB (совпадает с семантикой CLI /branch)
POST/api/sessions/{id}/chatВыполнить один синхронный ход агента
POST/api/sessions/{id}/chat/streamSSE-обёртка над одним ходом — отправляет события assistant.delta, tool.started, tool.completed, run.completed

/v1/capabilities анонсирует всю поверхность через флаги возможностей session_* и записи endpoints.session_*, чтобы внешние UI определяли поддержку и безопасно откатывались. Изображения во входных данных поддерживаются в полезной нагрузке chat и chat/stream (путь с поддержкой мультимодальности).

# ответвить сессию и выполнить один ход
curl -X POST http://localhost:8642/api/sessions/$ID/fork \
  -H "Authorization: Bearer $API_SERVER_KEY" \
  -d '{"title": "explore alt path"}'

# стримить ход по SSE
curl -N -X POST http://localhost:8642/api/sessions/$ID/chat/stream \
  -H "Authorization: Bearer $API_SERVER_KEY" \
  -d '{"input": "what files changed in the last hour?"}'

Обнаружение навыков и наборов инструментов

GET /v1/skills и GET /v1/toolsets позволяют внешним клиентам детерминированно перечислить возможности агента через REST, а не выспрашивать их у модели. Оба эндпоинта только на чтение и закрыты ключом API_SERVER_KEY.

curl http://localhost:8642/v1/skills \
  -H "Authorization: Bearer $API_SERVER_KEY"
# → [{"name": "github-pr-workflow", "description": "...", "category": "..."}, ...]

curl http://localhost:8642/v1/toolsets \
  -H "Authorization: Bearer $API_SERVER_KEY"
# → [{"name": "core", "label": "...", "description": "...", "enabled": true,
#     "configured": true, "tools": ["read_file", "write_file", ...]}, ...]

/v1/skills возвращает те же метаданные, которые хаб навыков использует внутри себя. /v1/toolsets возвращает наборы инструментов, разрешённые для платформы api_server, с конкретным списком tools, в который раскрывается каждый набор. Оба анонсируются под endpoints.* в /v1/capabilities.

Область долговременной памяти (X-Hermes-Session-Key)

Многопользовательским фронтендам вроде Open WebUI нужен стабильный идентификатор на канал для долговременной памяти (Honcho и т. п.), независимый от привязанного к транскрипту X-Hermes-Session-Id (который меняется по /new). Передайте X-Hermes-Session-Key в /v1/chat/completions, /v1/responses или /v1/runs, и Hermes протянет его до AIAgent(gateway_session_key=...), где провайдер памяти Honcho выведет из него стабильную область.

POST /v1/chat/completions HTTP/1.1
Authorization: Bearer ***
X-Hermes-Session-Id: transcript-alpha
X-Hermes-Session-Key: agent:main:webui:dm:user-42

Правила: максимум 256 символов; управляющие символы (\r, \n, \x00) отвергаются; значение возвращается обратно в ответах (JSON + SSE). /v1/capabilities анонсирует поддержку через "session_key_header": "X-Hermes-Session-Key". Без этого ключа стратегия per-session у Honcho даёт разную область на каждый session_id — ровно так, как Hermes вёл себя раньше.

Обработка системного промпта

Когда фронтенд присылает сообщение system (Chat Completions) или поле instructions (Responses API), hermes-agent накладывает его поверх своего основного системного промпта. Агент сохраняет все свои инструменты, память и навыки — системный промпт фронтенда добавляет дополнительные указания.

Так можно настроить поведение под конкретный фронтенд, не теряя возможностей:

  • Системный промпт Open WebUI: «You are a Python expert. Always include type hints.»
  • У агента по-прежнему есть терминал, файловые инструменты, веб-поиск, память и т. д.

Аутентификация

Bearer-токен через заголовок Authorization:

Authorization: Bearer ***

Ключ задаётся переменной окружения API_SERVER_KEY. Если нужно, чтобы браузер обращался к Hermes напрямую, дополнительно задайте API_SERVER_CORS_ORIGINS с явным списком разрешений.

внимание
Безопасность

API-сервер даёт полный доступ к набору инструментов hermes-agent, включая команды терминала. API_SERVER_KEY обязателен для любого развёртывания, в том числе при привязке к локальному 127.0.0.1 по умолчанию. Держите API_SERVER_CORS_ORIGINS узким, чтобы контролировать доступ из браузера, когда вы явно разрешаете браузерных клиентов.

Конфигурация

Переменные окружения

ПеременнаяПо умолчаниюОписание
API_SERVER_ENABLEDfalseВключить API-сервер
API_SERVER_PORT8642Порт HTTP-сервера
API_SERVER_HOST127.0.0.1Адрес привязки (по умолчанию только localhost)
API_SERVER_KEY(обязательно)Bearer-токен для аутентификации
API_SERVER_CORS_ORIGINS(нет)Разрешённые браузерные источники через запятую
API_SERVER_MODEL_NAME(имя профиля)Имя модели в /v1/models. По умолчанию имя профиля или hermes-agent для профиля по умолчанию.

config.yaml

# Not yet supported — use environment variables.
# config.yaml support coming in a future release.

Заголовки безопасности

Все ответы содержат заголовки безопасности:

  • X-Content-Type-Options: nosniff — отключает угадывание MIME-типа
  • Referrer-Policy: no-referrer — предотвращает утечку реферера

CORS

API-сервер по умолчанию не включает браузерный CORS.

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

API_SERVER_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000

Когда CORS включён:

  • Предварительные (preflight) ответы содержат Access-Control-Max-Age: 600 (кэш на 10 минут)
  • SSE-потоки содержат CORS-заголовки, чтобы браузерные клиенты EventSource работали корректно
  • Idempotency-Key входит в разрешённые заголовки запроса — клиенты могут отправлять его для дедупликации (ответы кэшируются по ключу на 5 минут)

Большинству описанных фронтендов, таких как Open WebUI, CORS не нужен вовсе: они подключаются по схеме сервер-сервер.

Совместимые фронтенды

Подходит любой фронтенд с поддержкой формата OpenAI API. Проверенные и описанные интеграции:

ФронтендЗвёздыПодключение
Open WebUI126kЕсть полное руководство
LobeChat73kЭндпоинт кастомного провайдера
LibreChat34kКастомный эндпоинт в librechat.yaml
AnythingLLM56kУниверсальный провайдер OpenAI
NextChat87kПеременная окружения BASE_URL
ChatBox39kНастройка API Host
Jan26kКонфигурация удалённой модели
HF Chat-UI8kOPENAI_BASE_URL
big-AGI7kКастомный эндпоинт
OpenAI Python SDKOpenAI(base_url="http://localhost:8642/v1")
curlПрямые HTTP-запросы

Многопользовательская настройка с профилями

Чтобы выдать нескольким пользователям по своему изолированному экземпляру Hermes (отдельные конфиг, память, навыки), используйте профили:

# Создаём по профилю на пользователя
hermes profile create alice
hermes profile create bob

# Настраиваем API-сервер каждого профиля на отдельном порту. API_SERVER_* — это
# переменные окружения (не ключи config.yaml), поэтому пишем их в .env каждого профиля:
cat >> ~/.hermes/profiles/alice/.env <<EOF
API_SERVER_ENABLED=true
API_SERVER_PORT=8643
API_SERVER_KEY=alice-secret
EOF

cat >> ~/.hermes/profiles/bob/.env <<EOF
API_SERVER_ENABLED=true
API_SERVER_PORT=8644
API_SERVER_KEY=bob-secret
EOF

# Запускаем шлюз каждого профиля
hermes -p alice gateway &
hermes -p bob gateway &

API-сервер каждого профиля автоматически анонсирует имя профиля как идентификатор модели:

  • http://localhost:8643/v1/models → модель alice
  • http://localhost:8644/v1/models → модель bob

В Open WebUI добавьте каждый как отдельное подключение. В выпадающем списке моделей появятся alice и bob как разные модели, за каждой стоит полностью изолированный экземпляр Hermes. Подробности — в руководстве по Open WebUI.

Ограничения

  • Хранение ответов — сохранённые ответы (для previous_response_id) лежат в SQLite и переживают перезапуски шлюза. Максимум 100 сохранённых ответов (вытеснение по LRU).
  • Нет загрузки файлов — изображения во входных данных поддерживаются и в /v1/chat/completions, и в /v1/responses, но загруженные файлы (file, input_file, file_id) и неизображённые документы через API не поддерживаются.
  • Поле model косметическое — поле model в запросах принимается, но фактическая используемая LLM-модель настраивается на стороне сервера в config.yaml.

Режим прокси

API-сервер служит и бэкендом для режима прокси шлюза. Когда другой экземпляр шлюза Hermes настроен с GATEWAY_PROXY_URL, указывающим на этот API-сервер, он пересылает все сообщения сюда вместо запуска собственного агента. Так получаются раздельные развёртывания — например, Docker-контейнер обрабатывает Matrix E2EE и ретранслирует запросы агенту на хосте.

Полное руководство по настройке — в разделе Matrix Proxy Mode.

ESC