test_api_server_toolset.py
1 """Tests for hermes-api-server toolset and API server tool availability.""" 2 import os 3 import json 4 from unittest.mock import patch, MagicMock 5 6 import pytest 7 8 from toolsets import resolve_toolset, get_toolset, validate_toolset 9 10 11 class TestHermesApiServerToolset: 12 """Tests for the hermes-api-server toolset definition.""" 13 14 def test_toolset_exists(self): 15 ts = get_toolset("hermes-api-server") 16 assert ts is not None 17 18 def test_toolset_validates(self): 19 assert validate_toolset("hermes-api-server") 20 21 def test_toolset_includes_web_tools(self): 22 tools = resolve_toolset("hermes-api-server") 23 assert "web_search" in tools 24 assert "web_extract" in tools 25 26 def test_toolset_includes_core_tools(self): 27 tools = resolve_toolset("hermes-api-server") 28 expected = [ 29 "terminal", "process", 30 "read_file", "write_file", "patch", "search_files", 31 "vision_analyze", "image_generate", 32 "execute_code", "delegate_task", 33 "todo", "memory", "session_search", "cronjob", 34 ] 35 for tool in expected: 36 assert tool in tools, f"Missing expected tool: {tool}" 37 38 def test_toolset_includes_browser_tools(self): 39 tools = resolve_toolset("hermes-api-server") 40 for tool in ["browser_navigate", "browser_snapshot", "browser_click", 41 "browser_type", "browser_scroll", "browser_back", 42 "browser_press"]: 43 assert tool in tools, f"Missing browser tool: {tool}" 44 45 def test_toolset_includes_homeassistant_tools(self): 46 tools = resolve_toolset("hermes-api-server") 47 for tool in ["ha_list_entities", "ha_get_state", "ha_list_services", "ha_call_service"]: 48 assert tool in tools, f"Missing HA tool: {tool}" 49 50 def test_toolset_excludes_clarify(self): 51 tools = resolve_toolset("hermes-api-server") 52 assert "clarify" not in tools 53 54 def test_toolset_excludes_send_message(self): 55 tools = resolve_toolset("hermes-api-server") 56 assert "send_message" not in tools 57 58 def test_toolset_excludes_text_to_speech(self): 59 tools = resolve_toolset("hermes-api-server") 60 assert "text_to_speech" not in tools 61 62 63 class TestApiServerPlatformConfig: 64 def test_platforms_dict_includes_api_server(self): 65 from hermes_cli.tools_config import PLATFORMS 66 assert "api_server" in PLATFORMS 67 assert PLATFORMS["api_server"]["default_toolset"] == "hermes-api-server" 68 69 70 class TestApiServerAdapterToolset: 71 @patch("gateway.platforms.api_server.AIOHTTP_AVAILABLE", True) 72 def test_create_agent_reads_config_toolsets(self): 73 """API server resolves toolsets from config like all other platforms.""" 74 from gateway.platforms.api_server import APIServerAdapter 75 from gateway.config import PlatformConfig 76 77 adapter = APIServerAdapter(PlatformConfig()) 78 79 with patch("gateway.run._resolve_runtime_agent_kwargs") as mock_kwargs, \ 80 patch("gateway.run._resolve_gateway_model") as mock_model, \ 81 patch("gateway.run._load_gateway_config") as mock_config, \ 82 patch("run_agent.AIAgent") as mock_agent_cls: 83 84 mock_kwargs.return_value = {"api_key": "test-key", "base_url": None, 85 "provider": None, "api_mode": None, 86 "command": None, "args": []} 87 mock_model.return_value = "test/model" 88 # No platform_toolsets override — should fall back to hermes-api-server default 89 mock_config.return_value = {} 90 mock_agent_cls.return_value = MagicMock() 91 92 adapter._create_agent() 93 94 mock_agent_cls.assert_called_once() 95 call_kwargs = mock_agent_cls.call_args 96 toolsets = call_kwargs.kwargs.get("enabled_toolsets") 97 assert isinstance(toolsets, list) 98 assert len(toolsets) > 0 99 assert call_kwargs.kwargs.get("platform") == "api_server" 100 101 @patch("gateway.platforms.api_server.AIOHTTP_AVAILABLE", True) 102 def test_create_agent_respects_config_override(self): 103 """User can override API server toolsets via platform_toolsets in config.yaml.""" 104 from gateway.platforms.api_server import APIServerAdapter 105 from gateway.config import PlatformConfig 106 107 adapter = APIServerAdapter(PlatformConfig()) 108 109 with patch("gateway.run._resolve_runtime_agent_kwargs") as mock_kwargs, \ 110 patch("gateway.run._resolve_gateway_model") as mock_model, \ 111 patch("gateway.run._load_gateway_config") as mock_config, \ 112 patch("run_agent.AIAgent") as mock_agent_cls: 113 114 mock_kwargs.return_value = {"api_key": "test-key", "base_url": None, 115 "provider": None, "api_mode": None, 116 "command": None, "args": []} 117 mock_model.return_value = "test/model" 118 # User overrides with just web and terminal 119 mock_config.return_value = { 120 "platform_toolsets": {"api_server": ["web", "terminal"]} 121 } 122 mock_agent_cls.return_value = MagicMock() 123 124 adapter._create_agent() 125 126 mock_agent_cls.assert_called_once() 127 call_kwargs = mock_agent_cls.call_args 128 toolsets = call_kwargs.kwargs.get("enabled_toolsets") 129 assert sorted(toolsets) == ["terminal", "web"]