mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
fix: widen None-deref guards to config-derived sibling sites + tests
Sibling sites of the salvaged #55997 fix, all reading user-editable config values through .get(key, '').method(): MoA slot provider/model labels, gateway quick-command alias targets (2 sites), gateway.proxy_url, and gateway.relay_url. Regression tests for the contributor's two sites plus the MoA labels.
This commit is contained in:
parent
838aa742cb
commit
a0972b9748
4 changed files with 45 additions and 5 deletions
|
|
@ -120,7 +120,7 @@ _REFERENCE_SYSTEM_PROMPT = (
|
|||
|
||||
|
||||
def _slot_label(slot: dict[str, str]) -> str:
|
||||
return f"{slot.get('provider', '').strip()}:{slot.get('model', '').strip()}"
|
||||
return f"{(slot.get('provider') or '').strip()}:{(slot.get('model') or '').strip()}"
|
||||
|
||||
|
||||
def _slot_runtime(slot: dict[str, str]) -> dict[str, Any]:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ def relay_url() -> Optional[str]:
|
|||
from gateway.run import _load_gateway_config # late import to avoid cycle
|
||||
|
||||
cfg = _load_gateway_config()
|
||||
url = (cfg.get("gateway") or {}).get("relay_url", "").strip()
|
||||
url = (cfg.get("gateway") or {}).get("relay_url")
|
||||
url = (url or "").strip()
|
||||
if url:
|
||||
return url.rstrip("/")
|
||||
except Exception: # noqa: BLE001 - config absence/parse must never crash registration
|
||||
|
|
|
|||
|
|
@ -9609,7 +9609,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
if isinstance(quick_commands, dict) and command in quick_commands:
|
||||
qcmd = quick_commands[command]
|
||||
if qcmd.get("type") == "alias":
|
||||
target = qcmd.get("target", "").strip()
|
||||
target = (qcmd.get("target") or "").strip()
|
||||
if target:
|
||||
target = target if target.startswith("/") else f"/{target}"
|
||||
target_command = target.lstrip("/")
|
||||
|
|
@ -10021,7 +10021,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
else:
|
||||
return f"Quick command '/{command}' has no command defined."
|
||||
elif qcmd.get("type") == "alias":
|
||||
target = qcmd.get("target", "").strip()
|
||||
target = (qcmd.get("target") or "").strip()
|
||||
if target:
|
||||
target = target if target.startswith("/") else f"/{target}"
|
||||
target_command = target.lstrip("/")
|
||||
|
|
@ -16523,7 +16523,8 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
if url:
|
||||
return url.rstrip("/")
|
||||
cfg = _load_gateway_config()
|
||||
url = (cfg.get("gateway") or {}).get("proxy_url", "").strip()
|
||||
url = (cfg.get("gateway") or {}).get("proxy_url")
|
||||
url = (url or "").strip()
|
||||
if url:
|
||||
return url.rstrip("/")
|
||||
return None
|
||||
|
|
|
|||
38
tests/agent/test_none_deref_guards.py
Normal file
38
tests/agent/test_none_deref_guards.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"""Regression tests for None-dereference guards on ``.get(key, "").method()``
|
||||
patterns (#55997 salvage + config-derived sibling sites).
|
||||
|
||||
``dict.get(key, default)`` only returns the default when the key is ABSENT;
|
||||
a present-but-null value sails through as None and crashes any chained
|
||||
method call.
|
||||
"""
|
||||
|
||||
from agent.anthropic_adapter import _convert_user_message
|
||||
from agent.moa_loop import _slot_label
|
||||
|
||||
|
||||
class TestAnthropicNullTextBlock:
|
||||
def test_null_text_block_treated_as_empty(self):
|
||||
"""A text block with ``text: null`` must not crash the empty-message
|
||||
check in _convert_user_message (#55997)."""
|
||||
result = _convert_user_message([{"type": "text", "text": None}])
|
||||
# Must not raise; result is a valid user message dict
|
||||
assert result["role"] == "user"
|
||||
|
||||
def test_mixed_null_and_real_text_blocks(self):
|
||||
result = _convert_user_message(
|
||||
[
|
||||
{"type": "text", "text": None},
|
||||
{"type": "text", "text": "hello"},
|
||||
]
|
||||
)
|
||||
assert result["role"] == "user"
|
||||
|
||||
|
||||
class TestMoaSlotLabelNullFields:
|
||||
def test_null_provider_and_model(self):
|
||||
"""MoA slot with ``provider: null`` in config.yaml must not crash
|
||||
label construction."""
|
||||
assert _slot_label({"provider": None, "model": None}) == ":" # type: ignore[arg-type]
|
||||
|
||||
def test_normal_slot(self):
|
||||
assert _slot_label({"provider": "openrouter", "model": "m"}) == "openrouter:m"
|
||||
Loading…
Add table
Add a link
Reference in a new issue