Gateway sessions had their own inline toolset resolution that only read platform_toolsets from config, which never includes MCP server names. MCP tools were discovered and registered but invisible to the model. - Replace duplicated gateway toolset resolution in _run_agent() and _run_background_task() with calls to the shared _get_platform_tools() - Extend _get_platform_tools() to include globally enabled MCP servers at runtime (include_default_mcp_servers=True), while config-editing flows use include_default_mcp_servers=False to avoid persisting implicit MCP defaults into platform_toolsets - Add homeassistant to PLATFORMS dict (was missing, caused KeyError) - Fix CLI entry point to use _get_platform_tools() as well, so MCP tools are visible in CLI mode too - Remove redundant platform_key reassignment in _run_background_task Co-authored-by: kshitijk4poor <kshitijk4poor@users.noreply.github.com>
240 lines
7.6 KiB
Python
240 lines
7.6 KiB
Python
"""Tests for hermes_cli.tools_config platform tool persistence."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from hermes_cli.tools_config import (
|
|
_get_platform_tools,
|
|
_platform_toolset_summary,
|
|
_save_platform_tools,
|
|
_toolset_has_keys,
|
|
)
|
|
|
|
|
|
def test_get_platform_tools_uses_default_when_platform_not_configured():
|
|
config = {}
|
|
|
|
enabled = _get_platform_tools(config, "cli")
|
|
|
|
assert enabled
|
|
|
|
|
|
def test_get_platform_tools_preserves_explicit_empty_selection():
|
|
config = {"platform_toolsets": {"cli": []}}
|
|
|
|
enabled = _get_platform_tools(config, "cli")
|
|
|
|
assert enabled == set()
|
|
|
|
|
|
def test_platform_toolset_summary_uses_explicit_platform_list():
|
|
config = {}
|
|
|
|
summary = _platform_toolset_summary(config, platforms=["cli"])
|
|
|
|
assert set(summary.keys()) == {"cli"}
|
|
assert summary["cli"] == _get_platform_tools(config, "cli")
|
|
|
|
|
|
def test_get_platform_tools_includes_enabled_mcp_servers_by_default():
|
|
config = {
|
|
"mcp_servers": {
|
|
"exa": {"url": "https://mcp.exa.ai/mcp"},
|
|
"web-search-prime": {"url": "https://api.z.ai/api/mcp/web_search_prime/mcp"},
|
|
"disabled-server": {"url": "https://example.com/mcp", "enabled": False},
|
|
}
|
|
}
|
|
|
|
enabled = _get_platform_tools(config, "cli")
|
|
|
|
assert "exa" in enabled
|
|
assert "web-search-prime" in enabled
|
|
assert "disabled-server" not in enabled
|
|
|
|
|
|
def test_get_platform_tools_keeps_enabled_mcp_servers_with_explicit_builtin_selection():
|
|
config = {
|
|
"platform_toolsets": {"cli": ["web", "memory"]},
|
|
"mcp_servers": {
|
|
"exa": {"url": "https://mcp.exa.ai/mcp"},
|
|
"web-search-prime": {"url": "https://api.z.ai/api/mcp/web_search_prime/mcp"},
|
|
},
|
|
}
|
|
|
|
enabled = _get_platform_tools(config, "cli")
|
|
|
|
assert "web" in enabled
|
|
assert "memory" in enabled
|
|
assert "exa" in enabled
|
|
assert "web-search-prime" in enabled
|
|
|
|
|
|
def test_toolset_has_keys_for_vision_accepts_codex_auth(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
|
(tmp_path / "auth.json").write_text(
|
|
'{"active_provider":"openai-codex","providers":{"openai-codex":{"tokens":{"access_token": "codex-...oken","refresh_token": "codex-...oken"}}}}'
|
|
)
|
|
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
|
monkeypatch.delenv("OPENAI_BASE_URL", raising=False)
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
monkeypatch.delenv("AUXILIARY_VISION_PROVIDER", raising=False)
|
|
monkeypatch.delenv("CONTEXT_VISION_PROVIDER", raising=False)
|
|
|
|
assert _toolset_has_keys("vision") is True
|
|
|
|
|
|
def test_save_platform_tools_preserves_mcp_server_names():
|
|
"""Ensure MCP server names are preserved when saving platform tools.
|
|
|
|
Regression test for https://github.com/NousResearch/hermes-agent/issues/1247
|
|
"""
|
|
config = {
|
|
"platform_toolsets": {
|
|
"cli": ["web", "terminal", "time", "github", "custom-mcp-server"]
|
|
}
|
|
}
|
|
|
|
new_selection = {"web", "browser"}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "cli", new_selection)
|
|
|
|
saved_toolsets = config["platform_toolsets"]["cli"]
|
|
|
|
assert "time" in saved_toolsets
|
|
assert "github" in saved_toolsets
|
|
assert "custom-mcp-server" in saved_toolsets
|
|
assert "web" in saved_toolsets
|
|
assert "browser" in saved_toolsets
|
|
assert "terminal" not in saved_toolsets
|
|
|
|
|
|
def test_save_platform_tools_handles_empty_existing_config():
|
|
"""Saving platform tools works when no existing config exists."""
|
|
config = {}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "telegram", {"web", "terminal"})
|
|
|
|
saved_toolsets = config["platform_toolsets"]["telegram"]
|
|
assert "web" in saved_toolsets
|
|
assert "terminal" in saved_toolsets
|
|
|
|
|
|
def test_save_platform_tools_handles_invalid_existing_config():
|
|
"""Saving platform tools works when existing config is not a list."""
|
|
config = {
|
|
"platform_toolsets": {
|
|
"cli": "invalid-string-value"
|
|
}
|
|
}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "cli", {"web"})
|
|
|
|
saved_toolsets = config["platform_toolsets"]["cli"]
|
|
assert "web" in saved_toolsets
|
|
|
|
|
|
def test_save_platform_tools_does_not_preserve_platform_default_toolsets():
|
|
"""Platform default toolsets (hermes-cli, hermes-telegram, etc.) must NOT
|
|
be preserved across saves.
|
|
|
|
These "super" toolsets resolve to ALL tools, so if they survive in the
|
|
config, they silently override any tools the user unchecked. Previously,
|
|
the preserve filter only excluded configurable toolset keys (web, browser,
|
|
terminal, etc.) and treated platform defaults as unknown custom entries
|
|
(like MCP server names), causing them to be kept unconditionally.
|
|
|
|
Regression test: user unchecks image_gen and homeassistant via
|
|
``hermes tools``, but hermes-cli stays in the config and re-enables
|
|
everything on the next read.
|
|
"""
|
|
config = {
|
|
"platform_toolsets": {
|
|
"cli": [
|
|
"browser", "clarify", "code_execution", "cronjob",
|
|
"delegation", "file", "hermes-cli", # <-- the culprit
|
|
"memory", "session_search", "skills", "terminal",
|
|
"todo", "tts", "vision", "web",
|
|
]
|
|
}
|
|
}
|
|
|
|
# User unchecks image_gen, homeassistant, moa — keeps the rest
|
|
new_selection = {
|
|
"browser", "clarify", "code_execution", "cronjob",
|
|
"delegation", "file", "memory", "session_search",
|
|
"skills", "terminal", "todo", "tts", "vision", "web",
|
|
}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "cli", new_selection)
|
|
|
|
saved = config["platform_toolsets"]["cli"]
|
|
|
|
# hermes-cli must NOT survive — it's a platform default, not an MCP server
|
|
assert "hermes-cli" not in saved
|
|
|
|
# The individual toolset keys the user selected must be present
|
|
assert "web" in saved
|
|
assert "terminal" in saved
|
|
assert "browser" in saved
|
|
|
|
# Tools the user unchecked must NOT be present
|
|
assert "image_gen" not in saved
|
|
assert "homeassistant" not in saved
|
|
assert "moa" not in saved
|
|
|
|
|
|
def test_save_platform_tools_does_not_preserve_hermes_telegram():
|
|
"""Same bug for Telegram — hermes-telegram must not be preserved."""
|
|
config = {
|
|
"platform_toolsets": {
|
|
"telegram": [
|
|
"browser", "file", "hermes-telegram", "terminal", "web",
|
|
]
|
|
}
|
|
}
|
|
|
|
new_selection = {"browser", "file", "terminal", "web"}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "telegram", new_selection)
|
|
|
|
saved = config["platform_toolsets"]["telegram"]
|
|
assert "hermes-telegram" not in saved
|
|
assert "web" in saved
|
|
|
|
|
|
def test_save_platform_tools_still_preserves_mcp_with_platform_default_present():
|
|
"""MCP server names must still be preserved even when platform defaults
|
|
are being stripped out."""
|
|
config = {
|
|
"platform_toolsets": {
|
|
"cli": [
|
|
"web", "terminal", "hermes-cli", "my-mcp-server", "github-tools",
|
|
]
|
|
}
|
|
}
|
|
|
|
new_selection = {"web", "browser"}
|
|
|
|
with patch("hermes_cli.tools_config.save_config"):
|
|
_save_platform_tools(config, "cli", new_selection)
|
|
|
|
saved = config["platform_toolsets"]["cli"]
|
|
|
|
# MCP servers preserved
|
|
assert "my-mcp-server" in saved
|
|
assert "github-tools" in saved
|
|
|
|
# Platform default stripped
|
|
assert "hermes-cli" not in saved
|
|
|
|
# User selections present
|
|
assert "web" in saved
|
|
assert "browser" in saved
|
|
|
|
# Deselected configurable toolset removed
|
|
assert "terminal" not in saved
|