Создание плагина провайдера генерации изображений
Плагины провайдеров генерации изображений регистрируют бэкенд, который обрабатывает каждый вызов инструмента image_generate — DALL·E, gpt-image, Grok, Flux, Imagen, Stable Diffusion, fal, Replicate, локальная установка ComfyUI, всё что угодно. Встроенные провайдеры (OpenAI, OpenAI-Codex, xAI) поставляются как плагины. Вы можете добавить новый или переопределить встроенный, поместив директорию в plugins/image_gen/<name>/.
Как работает обнаружение
Hermes сканирует бэкенды генерации изображений в трёх местах:
-
Встроенные —
<repo>/plugins/image_gen/<name>/(автозагружаются сkind: backend, всегда доступны) -
Пользовательские —
~/.hermes/plugins/image_gen/<name>/(включаются черезplugins.enabled) -
Pip — пакеты, объявляющие точку входа
hermes_agent.plugins
Функция register(ctx) каждого плагина вызывает ctx.register_image_gen_provider(...) — это помещает его в реестр в agent/image_gen_registry.py. Активный провайдер выбирается параметром image_gen.provider в config.yaml; hermes tools проводит пользователя через процесс выбора.
Обёртка инструмента image_generate запрашивает у реестра активный провайдер и направляет вызов туда. Если провайдер не зарегистрирован, инструмент выводит понятную ошибку со ссылкой на hermes tools.
Структура директории
plugins/image_gen/my-backend/
├── __init__.py # Подкласс ImageGenProvider + register()
└── plugin.yaml # Манифест с kind: backend
Встроенный плагин на этом этапе полностью готов. Пользовательские плагины в ~/.hermes/plugins/image_gen/<name>/ нужно добавить в plugins.enabled в config.yaml (или выполнить hermes plugins enable <name>).
ABC ImageGenProvider
Унаследуйтесь от agent.image_gen_provider.ImageGenProvider. Обязательными элементами являются только свойство name и метод generate() — всё остальное имеет разумные значения по умолчанию:
# plugins/image_gen/my-backend/__init__.py
from typing import Any, Dict, List, Optional
import os
from agent.image_gen_provider import (
DEFAULT_ASPECT_RATIO,
ImageGenProvider,
error_response,
resolve_aspect_ratio,
save_b64_image,
success_response,
)
class MyBackendImageGenProvider(ImageGenProvider):
@property
def name(self) -> str:
# Стабильный идентификатор, используемый в конфигурации image_gen.provider. Нижний регистр, без пробелов.
return "my-backend"
@property
def display_name(self) -> str:
# Человекочитаемая метка, показываемая в `hermes tools`. По умолчанию name.title().
return "My Backend"
def is_available(self) -> bool:
# Возвращайте False, если отсутствуют учётные данные или зависимости.
# Шлюз доступности инструмента вызывает этот метод перед отправкой.
if not os.environ.get("MY_BACKEND_API_KEY"):
return False
try:
import my_backend_sdk # noqa: F401
except ImportError:
return False
return True
def list_models(self) -> List[Dict[str, Any]]:
# Каталог, показываемый в выборе модели `hermes tools`.
return [
{
"id": "my-model-fast",
"display": "My Model (Fast)",
"speed": "~5s",
"strengths": "Quick iteration",
"price": "$0.01/image",
},
{
"id": "my-model-hq",
"display": "My Model (HQ)",
"speed": "~30s",
"strengths": "Highest fidelity",
"price": "$0.04/image",
},
]
def default_model(self) -> Optional[str]:
return "my-model-fast"
def get_setup_schema(self) -> Dict[str, Any]:
# Метаданные для выбора в `hermes tools` — ключи, которые будут запрошены при настройке.
return {
"name": "My Backend",
"badge": "paid", # опционально; показывается как короткий тег в выборе
"tag": "One-line description shown under the name",
"env_vars": [
{
"key": "MY_BACKEND_API_KEY",
"prompt": "My Backend API key",
"url": "https://my-backend.example.com/api-keys",
},
],
}
def generate(
self,
prompt: str,
aspect_ratio: str = DEFAULT_ASPECT_RATIO,
**kwargs: Any,
) -> Dict[str, Any]:
prompt = (prompt or "").strip()
aspect_ratio = resolve_aspect_ratio(aspect_ratio)
if not prompt:
return error_response(
error="Prompt is required",
error_type="invalid_input",
provider=self.name,
prompt="",
aspect_ratio=aspect_ratio,
)
# Приоритет выбора модели: переменная окружения → конфиг → значение по умолчанию.
# Вспомогательный метод _resolve_model() во встроенном плагине openai — хороший пример.
model_id = kwargs.get("model") or self.default_model() or "my-model-fast"
try:
import my_backend_sdk
client = my_backend_sdk.Client(api_key=os.environ["MY_BACKEND_API_KEY"])
result = client.generate(
prompt=prompt,
model=model_id,
aspect_ratio=aspect_ratio,
)
# Поддерживается два формата:
# - URL-строка: возвращается как `image`
# - base64-данные: сохраняются в $HERMES_HOME/cache/images/ через save_b64_image()
if result.get("image_b64"):
path = save_b64_image(
result["image_b64"],
prefix=self.name,
extension="png",
)
image = str(path)
else:
image = result["image_url"]
return success_response(
image=image,
model=model_id,
prompt=prompt,
aspect_ratio=aspect_ratio,
provider=self.name,
)
except Exception as exc:
return error_response(
error=str(exc),
error_type=type(exc).__name__,
provider=self.name,
model=model_id,
prompt=prompt,
aspect_ratio=aspect_ratio,
)
def register(ctx) -> None:
"""Точка входа плагина — вызывается один раз при загрузке."""
ctx.register_image_gen_provider(MyBackendImageGenProvider())
plugin.yaml
name: my-backend
version: 1.0.0
description: My image backend — text-to-image via My Backend SDK
author: Your Name
kind: backend
requires_env:
- MY_BACKEND_API_KEY
kind: backend определяет маршрутизацию плагина по пути регистрации генерации изображений. requires_env запрашивается во время hermes plugins install.
Справочник по ABC
Полный контракт в agent/image_gen_provider.py. Методы, которые вы обычно будете переопределять:
| Свойство | Обязательно | По умолчанию | Назначение |
|---|---|---|---|
name |
✅ | — | Стабильный идентификатор, используемый в конфигурации image_gen.provider |
display_name |
— | name.title() |
Метка, отображаемая в hermes tools |
is_available() |
— | True |
Проверка отсутствующих учётных данных/зависимостей |
list_models() |
— | [] |
Каталог для выбора модели в hermes tools |
default_model() |
— | первая из list_models() |
Резервное значение, если модель не настроена |
get_setup_schema() |
— | минимальная | Метаданные для выбора + подсказки по переменным окружения |
generate(prompt, aspect_ratio, **kwargs) |
✅ | — | Вызов |
Формат ответа
generate() должен возвращать словарь, созданный через success_response() или error_response(). Обе функции находятся в agent/image_gen_provider.py.
Успех:
success_response(
image=<url-or-absolute-path>,
model=<model-id>,
prompt=<echoed-prompt>,
aspect_ratio="landscape" | "square" | "portrait",
provider=<your-provider-name>,
extra={...}, # опциональные поля, специфичные для бэкенда
)
Ошибка:
error_response(
error="human-readable message",
error_type="provider_error" | "invalid_input" | "<exception class name>",
provider=<your-provider-name>,
model=<model-id>,
prompt=<prompt>,
aspect_ratio=<resolved aspect>,
)
Обёртка инструмента сериализует словарь в JSON и передаёт его LLM. Ошибки отображаются как результат инструмента; LLM решает, как объяснить их пользователю.
Обработка base64 и URL-вывода
Некоторые бэкенды возвращают URL-ссылки на изображения (fal, Replicate); другие — полезную нагрузку в base64 (OpenAI gpt-image-2). Для случая с base64 используйте save_b64_image() — она записывает файл в $HERMES_HOME/cache/images/<prefix>_<timestamp>_<uuid>.<ext> и возвращает абсолютный путь Path. Передайте этот путь (как str) в качестве image= в success_response(). Доставка через шлюз (Telegram photo bubble, Discord attachment) распознаёт как URL, так и абсолютные пути.
Пользовательские переопределения
Поместите пользовательский плагин в ~/.hermes/plugins/image_gen/<name>/ с тем же свойством name, что и у встроенного, и включите его через hermes plugins enable <name> — в реестре действует правило «последний записавший побеждает», поэтому ваша версия заменит встроенную. Полезно для направления плагина openai на приватный прокси или для замены каталога моделей.
Тестирование
export HERMES_HOME=/tmp/hermes-imggen-test
mkdir -p $HERMES_HOME/plugins/image_gen/my-backend
# …скопируйте __init__.py и plugin.yaml в эту директорию…
export MY_BACKEND_API_KEY=your-test-key
hermes plugins enable my-backend
# Выберите его как активный провайдер
echo "image_gen:" >> $HERMES_HOME/config.yaml
echo " provider: my-backend" >> $HERMES_HOME/config.yaml
# Проверьте его работу
hermes -z "Generate an image of a corgi in a spacesuit"
Или интерактивно: hermes tools → «Image Generation» → выберите my-backend → введите API-ключ, если будет предложено.
Эталонные реализации
-
plugins/image_gen/openai/__init__.py— gpt-image-2 на уровнях low/medium/high как три виртуальных ID моделей, использующих одну API-модель с разными параметрамиquality. Хороший пример многоуровневых моделей в одном бэкенде с цепочкой приоритетов config.yaml. -
plugins/image_gen/xai/__init__.py— Grok Imagine через xAI. Другая форма (URL-вывод, более простой каталог). -
plugins/image_gen/openai-codex/__init__.py— Вариант API Responses API в стиле Codex, переиспользующий OpenAI SDK с другим базовым URL маршрутизации.
Распространение через pip
# pyproject.toml
[project.entry-points."hermes_agent.plugins"]
my-backend-imggen = "my_backend_imggen_package"
Пакет my_backend_imggen_package должен предоставлять функцию register на верхнем уровне. См. Распространение через pip в общем руководстве по плагинам для полной настройки.
Связанные страницы
-
Генерация изображений — пользовательская документация функции
-
Обзор плагинов — все типы плагинов на одном экране
-
Создание плагина Hermes — общее руководство по инструментам/хукам/слэш-командам