Перейти к содержанию

Gen Provider Plugin

On this page

Плагины генерации изображений (image-gen provider plugins) регистрируют бэкенд, который обрабатывает каждый вызов инструмента image_generate — DALL·E, gpt-image, Grok, Flux, Imagen, Stable Diffusion, fal, Replicate, локальный ComfyUI и всё остальное. Встроенные провайдеры (OpenAI, OpenAI-Codex, xAI) поставляются как плагины. Вы можете добавить новый или переопределить встроенный, поместив директорию в plugins/image_gen/<name>/.

tip Генерация изображений — один из нескольких backend-плагинов, которые поддерживает Hermes. Другие (с более специализированными ABC) — это Memory Provider Plugins, Context Engine Plugins и Model Provider Plugins. Плагины общего назначения (инструменты, хуки, CLI-команды) описаны в разделе Build a Hermes Plugin.

Как работает обнаружение

Hermes сканирует бэкенды генерации изображений в трёх местах:

  1. Встроенные<repo>/plugins/image_gen/<name>/ (автоматически загружаются с kind: backend, всегда доступны)
  2. Пользовательские~/.hermes/plugins/image_gen/<name>/ (подключаются через plugins.enabled)
  3. 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.

Структура директории

[code] plugins/image_gen/my-backend/
├── init.py # Подкласс ImageGenProvider + register()
└── plugin.yaml # Манифест с kind: backend

[/code]

На этом встроенный плагин готов. Пользовательские плагины в ~/.hermes/plugins/image_gen/<name>/ нужно добавить в plugins.enabled в config.yaml (или выполнить hermes plugins enable <name>).

Абстрактный базовый класс ImageGenProvider

Унаследуйтесь от agent.image_gen_provider.ImageGenProvider. Единственные обязательные члены — это свойство name и метод generate() — всё остальное имеет разумные значения по умолчанию:

[code] # 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": "Быстрая итерация",  
                "price": "$0.01/image",  
            },  
            {  
                "id": "my-model-hq",  
                "display": "My Model (HQ)",  
                "speed": "~30s",  
                "strengths": "Максимальное качество",  
                "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": "Однострочное описание под названием",  
            "env_vars": [  
                {  
                    "key": "MY_BACKEND_API_KEY",  
                    "prompt": "API-ключ My Backend",  
                    "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",  
                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())

[/code]

plugin.yaml

[code] name: my-backend
version: 1.0.0
description: Мой бэкенд изображений — текст-в-изображение через My Backend SDK
author: Ваше Имя
kind: backend
requires_env:
- MY_BACKEND_API_KEY

[/code]

kind: backend указывает, что плагин должен быть зарегистрирован через путь регистрации генерации изображений. requires_env запрашивается во время hermes plugins install.

Справочник по ABC

Полный контракт в agent/image_gen_provider.py. Методы, которые вы обычно переопределяете:

Член Обязательный По умолчанию Назначение
name Стабильный ID, используемый в конфиге 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.

Успех:

[code] success_response(
image=,
model=,
prompt=<возвращённый-prompt>,
aspect_ratio="landscape" | "square" | "portrait",
provider=<имя-вашего-провайдера>,
extra={...}, # необязательные поля бэкенда
)

[/code]

Ошибка:

[code] error_response(
error="человекочитаемое сообщение",
error_type="provider_error" | "invalid_input" | "<имя класса исключения>",
provider=<имя-вашего-провайдера>,
model=,
prompt=,
aspect_ratio=<разрешённое соотношение сторон>,
)

[/code]

Обёртка инструмента JSON-сериализует словарь и передаёт его LLM. Ошибки отображаются как результат инструмента; LLM решает, как объяснить их пользователю.

Обработка вывода base64 vs URL

Некоторые бэкенды возвращают URL изображений (fal, Replicate); другие — полезную нагрузку base64 (OpenAI gpt-image-2). Для случая base64 используйте save_b64_image() — она записывает файл в $HERMES_HOME/cache/images/<префикс>_<метка времени>_<uuid>.<расширение> и возвращает абсолютный Path. Передайте этот путь (как str) в параметре image= в success_response(). Доставка через шлюзы (Telegram photo bubble, Discord attachment) распознаёт как URL, так и абсолютные пути.

Переопределение пользователем

Поместите пользовательский плагин в ~/.hermes/plugins/image_gen/<name>/ с тем же свойством name, что и у встроенного, и включите его через hermes plugins enable <name> — в реестре действует правило «последний записавший побеждает», поэтому ваша версия заменит встроенную. Это полезно для направления плагина openai на частный прокси или замены каталога моделей.

Тестирование

[code] 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 "Сгенерируй изображение корги в скафандре"

[/code]

Или интерактивно: hermes tools → «Image Generation» → выберите my-backend → введите API-ключ, если будет предложено.

Эталонные реализации

  • plugins/image_gen/openai/__init__.py — gpt-image-2 на трёх уровнях (низкий/средний/высокий) в виде трёх виртуальных ID моделей, использующих одну модель API с разными параметрами quality. Хороший пример многоуровневых моделей в одном бэкенде с цепочкой приоритетов config.yaml.
  • plugins/image_gen/xai/__init__.py — Grok Imagine через xAI. Другая форма (URL-вывод, упрощённый каталог).
  • plugins/image_gen/openai-codex/__init__.py — Вариант Responses API в стиле Codex, переиспользующий OpenAI SDK с другим базовым URL маршрутизации.

Распространение через pip

[code] # pyproject.toml
[project.entry-points."hermes_agent.plugins"]
my-backend-imggen = "my_backend_imggen_package"

[/code]

my_backend_imggen_package должен предоставлять функцию register верхнего уровня. См. Distribute via pip в общем руководстве по плагинам для полной настройки.

Связанные страницы