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:
1 parent
fb8bf2f5bd
commit
f838cc902a
2 files changed
+48
No files matched your search
@@ -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")
|
||||
|
||||
@@ -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>"
|
||||
Reference in new issue
Block a user