"""Tests for plugin image_gen providers injecting themselves into the picker. Covers `_plugin_image_gen_providers`, `_visible_providers`, and `_toolset_needs_configuration_prompt` handling of plugin providers. """ from __future__ import annotations from types import SimpleNamespace import pytest from agent import image_gen_registry from agent.image_gen_provider import ImageGenProvider class _FakeProvider(ImageGenProvider): def __init__(self, name: str, available: bool = True, schema=None, models=None): self._name = name self._available = available self._schema = schema or { "name": name.title(), "badge": "test", "tag": f"{name} test tag", "env_vars": [{"key": f"{name.upper()}_API_KEY", "prompt": f"{name} key"}], } self._models = models or [ {"id": f"{name}-model-v1", "display": f"{name} v1", "speed": "~5s", "strengths": "test", "price": "$"}, ] @property def name(self) -> str: return self._name def is_available(self) -> bool: return self._available def list_models(self): return list(self._models) def default_model(self): return self._models[0]["id"] if self._models else None def get_setup_schema(self): return dict(self._schema) def generate(self, prompt, aspect_ratio="landscape", **kw): return {"success": True, "image": f"{self._name}://{prompt}"} @pytest.fixture(autouse=True) def _reset_registry(): image_gen_registry._reset_for_tests() yield image_gen_registry._reset_for_tests() class TestPluginPickerInjection: def test_plugin_providers_returns_registered(self, monkeypatch): from hermes_cli import tools_config image_gen_registry.register_provider(_FakeProvider("myimg")) rows = tools_config._plugin_image_gen_providers() names = [r["name"] for r in rows] plugin_names = [r.get("image_gen_plugin_name") for r in rows] assert "Myimg" in names assert "myimg" in plugin_names def test_visible_providers_includes_plugins_for_image_gen(self, monkeypatch): from hermes_cli import tools_config image_gen_registry.register_provider(_FakeProvider("someimg")) cat = tools_config.TOOL_CATEGORIES["image_gen"] visible = tools_config._visible_providers(cat, {}) plugin_names = [p.get("image_gen_plugin_name") for p in visible if p.get("image_gen_plugin_name")] assert "someimg" in plugin_names def test_post_setup_omitted_when_not_declared(self, monkeypatch): from hermes_cli import tools_config image_gen_registry.register_provider(_FakeProvider("plain_img")) rows = tools_config._plugin_image_gen_providers() match = next(r for r in rows if r.get("image_gen_plugin_name") == "plain_img") assert "post_setup" not in match class TestPluginCatalog: def test_plugin_catalog_returns_models(self): from hermes_cli import tools_config image_gen_registry.register_provider(_FakeProvider("catimg")) catalog, default = tools_config._plugin_image_gen_catalog("catimg") assert "catimg-model-v1" in catalog assert default == "catimg-model-v1" class TestConfigPrompt: def test_image_gen_satisfied_by_plugin_provider(self, monkeypatch, tmp_path): """When a plugin provider reports is_available(), the picker should not force a setup prompt on the user.""" from hermes_cli import tools_config monkeypatch.setenv("HERMES_HOME", str(tmp_path)) monkeypatch.delenv("FAL_KEY", raising=False) image_gen_registry.register_provider(_FakeProvider("avail-img", available=True)) assert tools_config._toolset_needs_configuration_prompt("image_gen", {}) is False class TestConfigWriting: def test_picking_plugin_provider_writes_provider_and_model(self, monkeypatch, tmp_path): """When a user picks a plugin-backed image_gen provider with no env vars needed, ``_configure_provider`` should write both ``image_gen.provider`` and ``image_gen.model``.""" from hermes_cli import tools_config monkeypatch.setenv("HERMES_HOME", str(tmp_path)) image_gen_registry.register_provider(_FakeProvider("noenv", schema={ "name": "NoEnv", "badge": "free", "tag": "", "env_vars": [], })) # Stub out the interactive model picker — no TTY in tests. monkeypatch.setattr(tools_config, "_prompt_choice", lambda *a, **kw: 0) config: dict = {} provider_row = { "name": "NoEnv", "env_vars": [], "image_gen_plugin_name": "noenv", } tools_config._configure_provider(provider_row, config) assert config["image_gen"]["provider"] == "noenv" assert config["image_gen"]["model"] == "noenv-model-v1" def test_plugin_provider_active_overrides_managed_nous_active_label(self, monkeypatch): from hermes_cli import tools_config monkeypatch.setattr( tools_config, "get_nous_subscription_features", lambda config, **kwargs: SimpleNamespace( features={"image_gen": SimpleNamespace(managed_by_nous=True)} ), ) config = {"image_gen": {"provider": "openai", "use_gateway": False}} nous_row = { "name": "Nous Subscription", "managed_nous_feature": "image_gen", } openai_row = { "name": "OpenAI", "image_gen_plugin_name": "openai", } assert tools_config._is_provider_active(openai_row, config) is True assert tools_config._is_provider_active(nous_row, config) is False