fix(webui): guard non-dict resolve_moa_preset result in resolve_moa_config

A hermes-agent build that returns a non-dict (e.g. None) for an unknown
preset without raising would make resolved.update(selected) raise TypeError,
which bypasses the routes.py except RuntimeError guard and surfaces as an
unhandled 500 on /api/chat/start. Coerce a non-dict result to {} so preset
resolution degrades cleanly. Adds a regression test.
This commit is contained in:
promptclickrun committed 2026-07-01 07:54:48 -05:00
1 parent fb8bf2f5bd
commit f838cc902a
2 files changed
+48

No files matched your search

+2
View File
@@ -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")
+46
View File
@@ -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 <prompt>"
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 <prompt>"
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 <prompt>"