Pular para o conteúdo principal

Documentação oficial desta página · v0.20.6

Criar um Plugin de Provedor de Geração de Imagem

Plugins de provedor de geração de imagem registram um backend que atende toda chamada da ferramenta image_generate — DALL·E, gpt-image, Grok, Flux, Imagen, Stable Diffusion, fal, Replicate, uma instalação local do ComfyUI, o que for. Os provedores embutidos (OpenAI, OpenAI-Codex, xAI, FAL, Krea, DeepInfra, OpenRouter) são todos entregues como plugins. Você pode acrescentar um novo, ou substituir um dos que vêm junto, colocando um diretório em plugins/image_gen/<name>/.

dica

A geração de imagem é um dos vários plugins de backend que o Hermes aceita. Os outros (com ABCs mais especializadas) são os Plugins de Provedor de Memória, os Plugins de Motor de Contexto e os Plugins de Provedor de Modelo. Plugins gerais de ferramenta/hook/CLI ficam em Criar um Plugin do Hermes.

Como funciona a descoberta​

O Hermes procura backends de geração de imagem em três lugares:

  1. Embutidos — <repo>/plugins/image_gen/<name>/ (carregados automaticamente com kind: backend, sempre disponíveis)
  2. Do usuário — ~/.hermes/plugins/image_gen/<name>/ (habilitados sob demanda por plugins.enabled)
  3. Pip — pacotes que declaram um ponto de entrada hermes_agent.plugins

A função register(ctx) de cada plugin chama ctx.register_image_gen_provider(...) — isso o coloca no registro em agent/image_gen_registry.py. O provedor ativo é escolhido por image_gen.provider no config.yaml; o hermes tools guia o usuário na seleção.

O invólucro da ferramenta image_generate pergunta ao registro qual é o provedor ativo e despacha para lá. Se nenhum provedor estiver registrado, a ferramenta mostra um erro útil apontando para o hermes tools.

Estrutura de diretórios​

plugins/image_gen/meu-backend/
├── __init__.py # subclasse de ImageGenProvider + register()
└── plugin.yaml # manifesto com kind: backend

Um plugin embutido já está completo nesse ponto. Plugins do usuário em ~/.hermes/plugins/image_gen/<name>/ precisam ser adicionados a plugins.enabled no config.yaml (ou rode hermes plugins enable <name>).

A ABC ImageGenProvider​

Crie uma subclasse de agent.image_gen_provider.ImageGenProvider. Os únicos membros obrigatórios são a propriedade name e o método generate() — todo o resto tem padrões razoáveis:

# plugins/image_gen/meu-backend/__init__.py
from typing import Any, Dict, List, Optional
import os

from agent.image_gen_provider import (
DEFAULT_ASPECT_RATIO,
ImageGenProvider,
error_response,
normalize_reference_images,
resolve_aspect_ratio,
save_b64_image,
success_response,
)


class MyBackendImageGenProvider(ImageGenProvider):
@property
def name(self) -> str:
# ID estável usado na configuração image_gen.provider. Minúsculas, sem espaços.
return "my-backend"

@property
def display_name(self) -> str:
# Rótulo legível exibido no `hermes tools`. Se omitido, usa name.title().
return "My Backend"

def is_available(self) -> bool:
# Retorne False se faltarem credenciais ou dependências.
# A checagem de disponibilidade da ferramenta chama isto antes de despachar.
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]]:
# Catálogo mostrado no seletor de modelos do `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]:
# Metadados para o seletor do `hermes tools` — chaves a pedir na configuração.
return {
"name": "My Backend",
"badge": "paid", # opcional; aparece como etiqueta curta no seletor
"tag": "Descrição de uma linha exibida abaixo do nome",
"env_vars": [
{
"key": "MY_BACKEND_API_KEY",
"prompt": "Chave de API do My Backend",
"url": "https://my-backend.example.com/api-keys",
},
],
}

def capabilities(self) -> Dict[str, Any]:
# Declare se este backend aceita imagem-para-imagem / edição.
# A camada de ferramentas expõe isso no schema dinâmico para o modelo
# saber quando `image_url` é respeitado. O padrão (se você omitir) é
# só texto: {"modalities": ["text"], "max_reference_images": 0}.
return {"modalities": ["text", "image"], "max_reference_images": 4}

def generate(
self,
prompt: str,
aspect_ratio: str = DEFAULT_ASPECT_RATIO,
*,
image_url: Optional[str] = None,
reference_image_urls: Optional[List[str]] = None,
**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,
)

# Roteamento: se image_url (ou reference_image_urls) estiver definido, a chamada
# é um pedido de imagem-para-imagem / edição; senão, é texto-para-imagem. Informe
# qual caminho você seguiu pelo campo `modality` de success_response.
sources = []
if image_url:
sources.append(image_url)
sources.extend(normalize_reference_images(reference_image_urls) or [])
modality = "image" if sources else "text"

# Precedência na escolha do modelo: variável de ambiente → configuração → padrão.
# O auxiliar _resolve_model() do plugin openai embutido é uma boa referência.
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"])
if modality == "image":
result = client.edit(
prompt=prompt,
model=model_id,
image_urls=sources,
)
else:
result = client.generate(
prompt=prompt,
model=model_id,
aspect_ratio=aspect_ratio,
)

# Dois formatos aceitos:
# - string de URL: devolva como `image`
# - dados em base64: salve em $HERMES_HOME/cache/images/ com 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,
modality=modality,
)
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:
"""Ponto de entrada do plugin — chamado uma vez no carregamento."""
ctx.register_image_gen_provider(MyBackendImageGenProvider())

plugin.yaml​

name: my-backend
version: 1.0.0
description: Meu backend de imagem — texto-para-imagem via My Backend SDK
author: Seu Nome
kind: backend
requires_env:
- MY_BACKEND_API_KEY

É o kind: backend que direciona o plugin para o caminho de registro de geração de imagem. O requires_env é solicitado durante o hermes plugins install.

Referência da ABC​

O contrato completo está em agent/image_gen_provider.py. Os métodos que você normalmente sobrescreve:

MembroObrigatórioPadrãoFinalidade
name✅—ID estável usado na configuração image_gen.provider
display_name—name.title()Rótulo exibido no hermes tools
is_available()—TrueBarreira para credenciais/dependências ausentes
list_models()—[]Catálogo para o seletor de modelos do hermes tools
default_model()—primeiro de list_models()Reserva quando nenhum modelo está configurado
get_setup_schema()—mínimoMetadados do seletor + perguntas de variáveis de ambiente
generate(prompt, aspect_ratio, **kwargs)✅—A chamada em si

Formato da resposta​

O generate() precisa retornar um dicionário construído por success_response() ou error_response(). Os dois ficam em agent/image_gen_provider.py.

Sucesso:

success_response(
image=<url-ou-caminho-absoluto>,
model=<id-do-modelo>,
prompt=<prompt-ecoado>,
aspect_ratio="landscape" | "square" | "portrait",
provider=<nome-do-seu-provedor>,
extra={...}, # campos opcionais específicos do backend
)

Erro:

error_response(
error="mensagem legível para humanos",
error_type="provider_error" | "invalid_input" | "<nome da classe da exceção>",
provider=<nome-do-seu-provedor>,
model=<id-do-modelo>,
prompt=<prompt>,
aspect_ratio=<proporção resolvida>,
)

O invólucro da ferramenta serializa o dicionário em JSON e entrega ao LLM. Erros aparecem como o resultado da ferramenta; o LLM decide como explicá-los ao usuário.

Lidar com saída em base64 ou em URL​

Alguns backends retornam URLs de imagem (fal, Replicate); outros retornam cargas em base64 (OpenAI gpt-image-2). No caso do base64, use save_b64_image() — ele grava em $HERMES_HOME/cache/images/<prefix>_<timestamp>_<uuid>.<ext> e retorna o Path absoluto. Passe esse caminho (como str) em image= no success_response(). A entrega pelo gateway (bolha de foto no Telegram, anexo no Discord) reconhece tanto URLs quanto caminhos absolutos.

Substituições do usuário​

Coloque um plugin de usuário em ~/.hermes/plugins/image_gen/<name>/ com a mesma propriedade name de um plugin embutido e habilite-o com hermes plugins enable <name> — o registro é de último a escrever vence, então a sua versão substitui a embutida. Útil para apontar um plugin openai para um proxy privado, ou para trocar por um catálogo de modelos personalizado.

Testar​

export HERMES_HOME=/tmp/hermes-imggen-test
mkdir -p $HERMES_HOME/plugins/image_gen/my-backend
# …copie __init__.py + plugin.yaml para esse diretório…

export MY_BACKEND_API_KEY=sua-chave-de-teste
hermes plugins enable my-backend

# Escolha-o como provedor ativo
echo "image_gen:" >> $HERMES_HOME/config.yaml
echo " provider: my-backend" >> $HERMES_HOME/config.yaml

# Coloque-o para funcionar
hermes -z "Gere uma imagem de um corgi em traje espacial"

Ou de forma interativa: hermes tools → "Image Generation" → selecione my-backend → informe a chave de API, se for pedida.

Implementações de referência​

  • plugins/image_gen/openai/__init__.py — gpt-image-2 nos níveis low/medium/high como três IDs de modelo virtuais que compartilham um mesmo modelo de API com parâmetros quality diferentes. Bom exemplo de modelos em níveis dentro de um único backend + cadeia de precedência do config.yaml.
  • plugins/image_gen/xai/__init__.py — Grok Imagine via xAI. Formato diferente (saída em URL, catálogo mais simples).
  • plugins/image_gen/openai-codex/__init__.py — variante da Responses API no estilo Codex, reaproveitando o SDK da OpenAI com uma URL base de roteamento diferente.

Distribuir via pip​

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

O my_backend_imggen_package precisa expor uma função register no nível superior. Veja Distribuir via pip no guia geral de plugins para a configuração completa.