diff --git a/api/commands.py b/api/commands.py index 68b9a777..36d85920 100644 --- a/api/commands.py +++ b/api/commands.py @@ -418,6 +418,8 @@ def resolve_moa_config(preset: str | None = None) -> dict: if resolve_moa_preset is not None: try: selected = resolve_moa_preset(moa_raw, preset_name) + if not isinstance(selected, dict): + selected = {} except Exception: selected = {} preset_name = str(moa_cfg.get("default_preset") or "default") diff --git a/tests/test_moa_model_picker_provider.py b/tests/test_moa_model_picker_provider.py index f8f9abb3..9013cdb5 100644 --- a/tests/test_moa_model_picker_provider.py +++ b/tests/test_moa_model_picker_provider.py @@ -151,3 +151,49 @@ def test_resolve_moa_config_falls_back_when_preset_resolution_raises(monkeypatch assert resolved["preset"] == "default" assert resolved["default_preset"] == "default" assert resolved["usage"] == "Usage: /moa " + + +def test_resolve_moa_config_ignores_non_dict_preset_result(monkeypatch): + import sys + from types import ModuleType + from typing import Any, cast + + import api.commands as commands + + cfg = { + "moa": { + "default_preset": "default", + "presets": {"default": {"enabled": True}}, + } + } + hermes_cli_pkg = sys.modules.get("hermes_cli") or ModuleType("hermes_cli") + hermes_cli_pkg.__path__ = [] + moa_config = ModuleType("hermes_cli.moa_config") + + def normalize_moa_config(raw): + return { + "default_preset": raw.get("default_preset", "default"), + "presets": raw.get("presets", {}), + } + + # A hermes-agent build that returns ``None`` for a missing/unknown preset + # instead of raising. Without a dict guard, ``resolved.update(None)`` would + # raise ``TypeError`` and bypass the routes.py ``except RuntimeError`` guard, + # surfacing as an unhandled 500 on chat start. + def resolve_moa_preset(_raw, _preset_name): + return None + + moa_config_any = cast(Any, moa_config) + moa_config_any.normalize_moa_config = normalize_moa_config + moa_config_any.resolve_moa_preset = resolve_moa_preset + moa_config_any.moa_usage = lambda: "Usage: /moa " + monkeypatch.setitem(sys.modules, "hermes_cli", hermes_cli_pkg) + monkeypatch.setitem(sys.modules, "hermes_cli.moa_config", moa_config) + monkeypatch.setattr(commands, "_load_config_for_moa_resolution", lambda: cfg, raising=False) + + resolved = commands.resolve_moa_config("default") + + assert isinstance(resolved, dict) + assert resolved["preset"] == "default" + assert resolved["default_preset"] == "default" + assert resolved["usage"] == "Usage: /moa "