Files
hermes-agent/tests/hermes_cli/test_imagegen_managed_gateway.py
T
Teknium 6c745e81ae fix(tools-config): stop reconfigure flow clobbering image_gen.use_gateway on managed FAL rows
The Nous Subscription image_gen row carries imagegen_backend="fal", so
_reconfigure_provider's post-model-picker step ran

    img_cfg["use_gateway"] = False

unconditionally at two sites, immediately after the managed branch had
written use_gateway=True. A user who picked Nous Subscription and then
re-entered `hermes tools` to change the model was silently flipped onto
their personal FAL_KEY.

Same bug class as fe63353cb, which fixed the plugin-provider selector
but missed these two legacy-backend sites in the reconfigure flow. Both
now write bool(managed_feature), matching the existing correct site in
_configure_provider.

Adds regression tests driven through the real TOOL_CATEGORIES managed
row; sabotage-verified (tests fail with the old behavior restored).
2026-08-16 02:44:18 -07:00

125 lines
4.9 KiB
Python

"""Regression tests for image_gen use_gateway persistence (managed FAL clobber).
Bug: ``_select_plugin_image_gen_provider`` hardcoded
``image_gen.use_gateway = False``. When a user picked FAL through the
Nous-subscription managed flow, ``_write_provider_config`` first set
``use_gateway = True`` — then the image selector ran and clobbered it back
to False, silently routing every generation through the user's personal
FAL_KEY instead of the Nous Tool Gateway (real incident: personal key
drained to zero while the subscription sat unused).
The video twin (``_select_plugin_video_gen_provider``) already accepted a
``use_gateway`` kwarg; these tests pin the image path to the same contract.
"""
from hermes_cli.tools_config import (
_select_plugin_image_gen_provider,
_select_plugin_video_gen_provider,
_write_provider_config,
)
def _quiet(monkeypatch):
import hermes_cli.tools_config as tc
monkeypatch.setattr(tc, "_print_success", lambda *a, **k: None)
monkeypatch.setattr(tc, "_print_info", lambda *a, **k: None, raising=False)
monkeypatch.setattr(tc, "_configure_imagegen_model_for_plugin", lambda *a, **k: None)
monkeypatch.setattr(tc, "_configure_videogen_model_for_plugin", lambda *a, **k: None)
def test_image_gen_selector_preserves_managed_gateway_flag(monkeypatch):
"""Managed pick: use_gateway=True must survive the selector."""
_quiet(monkeypatch)
config = {}
# The managed flow first writes the managed flag...
_write_provider_config(
{"image_gen_plugin_name": "fal"}, config, managed_feature="image_gen"
)
assert config["image_gen"]["use_gateway"] is True
# ...then the selector runs; passing the managed flag must NOT clobber it.
_select_plugin_image_gen_provider("fal", config, use_gateway=True)
assert config["image_gen"]["provider"] == "fal"
assert config["image_gen"]["use_gateway"] is True
def test_image_gen_selector_direct_key_pick_clears_gateway(monkeypatch):
"""Non-managed pick keeps the historical default: direct key, no gateway."""
_quiet(monkeypatch)
config = {"image_gen": {"use_gateway": True}}
_select_plugin_image_gen_provider("fal", config)
assert config["image_gen"]["provider"] == "fal"
assert config["image_gen"]["use_gateway"] is False
def test_image_and_video_selectors_share_the_gateway_contract(monkeypatch):
"""The two selectors are twins: same kwarg, same persistence behavior."""
_quiet(monkeypatch)
for use_gateway in (True, False):
config = {}
_select_plugin_image_gen_provider("fal", config, use_gateway=use_gateway)
_select_plugin_video_gen_provider("fal", config, use_gateway=use_gateway)
assert config["image_gen"]["use_gateway"] is use_gateway
assert config["video_gen"]["use_gateway"] is use_gateway
def _quiet_reconfigure(monkeypatch):
"""Silence prints + model pickers for _reconfigure_provider paths."""
import hermes_cli.tools_config as tc
monkeypatch.setattr(tc, "_print_success", lambda *a, **k: None)
monkeypatch.setattr(tc, "_print_info", lambda *a, **k: None, raising=False)
monkeypatch.setattr(tc, "_print_warning", lambda *a, **k: None, raising=False)
monkeypatch.setattr(tc, "_configure_imagegen_model", lambda *a, **k: None)
monkeypatch.setattr(tc, "_run_post_setup", lambda *a, **k: None, raising=False)
# Managed rows gate on live Portal auth — stub it green.
import hermes_cli.nous_subscription as ns
monkeypatch.setattr(ns, "ensure_nous_portal_access", lambda **k: True)
def test_reconfigure_managed_fal_row_keeps_gateway_flag(monkeypatch):
"""The sibling bug of fe63353cb: the legacy-backend model-pick step in
_reconfigure_provider hardcoded use_gateway=False AFTER the managed
branch wrote True — a Nous Subscription user re-entering the picker to
change models was silently flipped onto their personal FAL_KEY."""
_quiet_reconfigure(monkeypatch)
import hermes_cli.tools_config as tc
managed_row = {
"name": "Nous Subscription",
"env_vars": [],
"requires_nous_auth": True,
"managed_nous_feature": "image_gen",
"override_env_vars": ["FAL_KEY"],
"imagegen_backend": "fal",
}
config = {"image_gen": {"model": "fal-ai/gpt-image-2"}}
tc._reconfigure_provider(managed_row, config)
assert config["image_gen"]["provider"] == "fal"
assert config["image_gen"]["use_gateway"] is True
def test_reconfigure_direct_fal_row_clears_gateway_flag(monkeypatch):
"""Direct-key FAL reconfig must still clear the flag (historical
behavior for genuinely non-managed picks)."""
_quiet_reconfigure(monkeypatch)
import hermes_cli.tools_config as tc
direct_row = {
"name": "FAL.ai",
"env_vars": [],
"imagegen_backend": "fal",
}
config = {"image_gen": {"use_gateway": True}}
tc._reconfigure_provider(direct_row, config)
assert config["image_gen"]["use_gateway"] is False