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/stream | SSE-обёртка над одним ходом — отправляет события 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_ENABLED | false | Включить API-сервер |
API_SERVER_PORT | 8642 | Порт HTTP-сервера |
API_SERVER_HOST | 127.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 WebUI | 126k | Есть полное руководство |
| LobeChat | 73k | Эндпоинт кастомного провайдера |
| LibreChat | 34k | Кастомный эндпоинт в librechat.yaml |
| AnythingLLM | 56k | Универсальный провайдер OpenAI |
| NextChat | 87k | Переменная окружения BASE_URL |
| ChatBox | 39k | Настройка API Host |
| Jan | 26k | Конфигурация удалённой модели |
| HF Chat-UI | 8k | OPENAI_BASE_URL |
| big-AGI | 7k | Кастомный эндпоинт |
| OpenAI Python SDK | — | OpenAI(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→ модельalicehttp://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.