Image-gen provider plugins 注册一个 backend,用于处理每一次 image_generate tool call —— DALL·E、gpt-image、Grok、Flux、Imagen、Stable Diffusion、fal、Replicate、本地 ComfyUI 设备,任何都可以。内置 providers(OpenAI、OpenAI-Codex、xAI)都以 plugins 形式发布。你可以通过将目录放入 plugins/image_gen/<name>/ 来添加新的 provider,或覆盖 bundled provider。
发现机制如何工作
Section titled “发现机制如何工作”Hermes 会在三个地方扫描 image-gen backends:
- Bundled ——
<repo>/plugins/image_gen/<name>/(以kind: backend自动加载,始终可用) - User ——
~/.hermes/plugins/image_gen/<name>/(通过plugins.enabled选择启用) - Pip —— 声明
hermes_agent.pluginsentry point 的 packages
每个 plugin 的 register(ctx) 函数会调用 ctx.register_image_gen_provider(...) —— 这会将它放入 agent/image_gen_registry.py 中的 registry。active provider 由 config.yaml 中的 image_gen.provider 选择;hermes tools 会引导用户完成选择。
image_generate tool wrapper 会向 registry 请求 active provider,并 dispatch 到那里。如果没有注册 provider,该 tool 会显示一个有用的错误,指向 hermes tools。
plugins/image_gen/my-backend/├── __init__.py # ImageGenProvider subclass + register()└── plugin.yaml # Manifest with kind: backendBundled plugin 到这里就完整了。位于 ~/.hermes/plugins/image_gen/<name>/ 的 User plugins 需要被添加到 config.yaml 的 plugins.enabled 中(或运行 hermes plugins enable <name>)。
ImageGenProvider ABC
Section titled “ImageGenProvider ABC”子类化 agent.image_gen_provider.ImageGenProvider。唯一必需的成员是 name property 和 generate() 方法 —— 其他所有内容都有合理默认值:
from typing import Any, Dict, List, Optionalimport 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 config 中使用的稳定 id。小写,不含空格。 return "my-backend"
@property def display_name(self) -> str: # 在 `hermes tools` 中显示的人类可读标签。如果省略,默认为 name.title()。 return "My Backend"
def is_available(self) -> bool: # 如果缺少 credentials 或 deps,则返回 False。 # tool 的 availability gate 会在 dispatch 前调用它。 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` model picker 中显示的 catalog。 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` picker 的 metadata —— setup 时要提示的 keys。 return { "name": "My Backend", "badge": "paid", # 可选;在 picker 中显示为一个短标签 "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, )
# Model selection precedence:env var → config → default。 # built-in openai plugin 中的 helper _resolve_model() 是一个很好的参考。 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, )
# 支持两种 shape: # - URL string:将其作为 `image` 返回 # - base64 data:通过 save_b64_image() 保存到 $HERMES_HOME/cache/images/ 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: """Plugin 入口点 —— 在加载时调用一次。""" ctx.register_image_gen_provider(MyBackendImageGenProvider())plugin.yaml
Section titled “plugin.yaml”name: my-backendversion: 1.0.0description: My image backend — 通过 My Backend SDK 进行 text-to-imageauthor: Your Namekind: backendrequires_env: - MY_BACKEND_API_KEYkind: backend 是将 plugin 路由到 image-gen 注册路径的内容。requires_env 会在 hermes plugins install 期间提示。
ABC 参考
Section titled “ABC 参考”完整契约位于 agent/image_gen_provider.py。你通常会 override 的方法:
| Member | Required | Default | Purpose |
|---|---|---|---|
name | ✅ | — | 在 image_gen.provider config 中使用的稳定 id |
display_name | — | name.title() | 在 hermes tools 中显示的标签 |
is_available() | — | True | 缺少 creds/deps 时的 gate |
list_models() | — | [] | hermes tools model picker 的 catalog |
default_model() | — | list_models() 中的第一个 | 未配置 model 时的 fallback |
get_setup_schema() | — | minimal | Picker metadata + env-var prompts |
generate(prompt, aspect_ratio, **kwargs) | ✅ | — | 调用 |
generate() 必须返回一个通过 success_response() 或 error_response() 构建的 dict。两者都位于 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={...}, # 可选的 backend-specific fields)错误:
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>,)tool wrapper 会将 dict JSON 序列化,并交给 LLM。错误会作为 tool result 显示;LLM 决定如何向用户解释它们。
处理 base64 与 URL 输出
Section titled “处理 base64 与 URL 输出”一些 backends 返回 image URLs(fal、Replicate);其他 backends 返回 base64 payloads(OpenAI gpt-image-2)。对于 base64 情况,请使用 save_b64_image() —— 它会写入 $HERMES_HOME/cache/images/<prefix>_<timestamp>_<uuid>.<ext>,并返回 absolute Path。将该 path(作为 str)作为 image= 传入 success_response()。Gateway delivery(Telegram photo bubble、Discord attachment)同时识别 URLs 和 absolute paths。
User overrides
Section titled “User overrides”在 ~/.hermes/plugins/image_gen/<name>/ 放入一个 user plugin,并让它的 name property 与某个 bundled plugin 相同,然后通过 hermes plugins enable <name> 启用它 —— registry 是 last-writer-wins,所以你的版本会替换 built-in。这对于将 openai plugin 指向 private proxy,或换入自定义 model catalog 很有用。
export HERMES_HOME=/tmp/hermes-imggen-testmkdir -p $HERMES_HOME/plugins/image_gen/my-backend# …将 __init__.py + plugin.yaml 复制到该目录…
export MY_BACKEND_API_KEY=your-test-keyhermes plugins enable my-backend
# 将它选为 active providerecho "image_gen:" >> $HERMES_HOME/config.yamlecho " 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 key。
plugins/image_gen/openai/__init__.py —— gpt-image-2 的 low / medium / high tiers,作为三个 virtual model IDs,共享一个 API model,但使用不同 quality params。适合作为单一 backend 下 tiered models + config.yaml precedence chain 的示例。
plugins/image_gen/xai/__init__.py —— 通过 xAI 使用 Grok Imagine。不同 shape(URL output,更简单的 catalog)。
plugins/image_gen/openai-codex/__init__.py —— Codex-style Responses API 变体,复用 OpenAI SDK,但使用不同 routing base URL。
通过 pip 分发
Section titled “通过 pip 分发”[project.entry-points."hermes_agent.plugins"]my-backend-imggen = "my_backend_imggen_package"my_backend_imggen_package 必须暴露一个顶层 register 函数。完整设置请参见通用 plugin 指南中的 Distribute via pip。
- Image Generation —— 面向用户的功能文档
- Plugins overview —— 所有 plugin 类型一览
- Build a Hermes Plugin —— 通用 tools / hooks / slash commands 指南