hud-python 0.4.1__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hud-python might be problematic. Click here for more details.
- hud/__init__.py +22 -22
- hud/agents/__init__.py +13 -15
- hud/agents/base.py +599 -599
- hud/agents/claude.py +373 -373
- hud/agents/langchain.py +261 -250
- hud/agents/misc/__init__.py +7 -7
- hud/agents/misc/response_agent.py +82 -80
- hud/agents/openai.py +352 -352
- hud/agents/openai_chat_generic.py +154 -154
- hud/agents/tests/__init__.py +1 -1
- hud/agents/tests/test_base.py +742 -742
- hud/agents/tests/test_claude.py +324 -324
- hud/agents/tests/test_client.py +363 -363
- hud/agents/tests/test_openai.py +237 -237
- hud/cli/__init__.py +617 -617
- hud/cli/__main__.py +8 -8
- hud/cli/analyze.py +371 -371
- hud/cli/analyze_metadata.py +230 -230
- hud/cli/build.py +498 -427
- hud/cli/clone.py +185 -185
- hud/cli/cursor.py +92 -92
- hud/cli/debug.py +392 -392
- hud/cli/docker_utils.py +83 -83
- hud/cli/init.py +280 -281
- hud/cli/interactive.py +353 -353
- hud/cli/mcp_server.py +764 -756
- hud/cli/pull.py +330 -336
- hud/cli/push.py +404 -370
- hud/cli/remote_runner.py +311 -311
- hud/cli/runner.py +160 -160
- hud/cli/tests/__init__.py +3 -3
- hud/cli/tests/test_analyze.py +284 -284
- hud/cli/tests/test_cli_init.py +265 -265
- hud/cli/tests/test_cli_main.py +27 -27
- hud/cli/tests/test_clone.py +142 -142
- hud/cli/tests/test_cursor.py +253 -253
- hud/cli/tests/test_debug.py +453 -453
- hud/cli/tests/test_mcp_server.py +139 -139
- hud/cli/tests/test_utils.py +388 -388
- hud/cli/utils.py +263 -263
- hud/clients/README.md +143 -143
- hud/clients/__init__.py +16 -16
- hud/clients/base.py +378 -379
- hud/clients/fastmcp.py +222 -222
- hud/clients/mcp_use.py +298 -278
- hud/clients/tests/__init__.py +1 -1
- hud/clients/tests/test_client_integration.py +111 -111
- hud/clients/tests/test_fastmcp.py +342 -342
- hud/clients/tests/test_protocol.py +188 -188
- hud/clients/utils/__init__.py +1 -1
- hud/clients/utils/retry_transport.py +160 -160
- hud/datasets.py +327 -322
- hud/misc/__init__.py +1 -1
- hud/misc/claude_plays_pokemon.py +292 -292
- hud/otel/__init__.py +35 -35
- hud/otel/collector.py +142 -142
- hud/otel/config.py +164 -164
- hud/otel/context.py +536 -536
- hud/otel/exporters.py +366 -366
- hud/otel/instrumentation.py +97 -97
- hud/otel/processors.py +118 -118
- hud/otel/tests/__init__.py +1 -1
- hud/otel/tests/test_processors.py +197 -197
- hud/server/__init__.py +5 -5
- hud/server/context.py +114 -114
- hud/server/helper/__init__.py +5 -5
- hud/server/low_level.py +132 -132
- hud/server/server.py +170 -166
- hud/server/tests/__init__.py +3 -3
- hud/settings.py +73 -73
- hud/shared/__init__.py +5 -5
- hud/shared/exceptions.py +180 -180
- hud/shared/requests.py +264 -264
- hud/shared/tests/test_exceptions.py +157 -157
- hud/shared/tests/test_requests.py +275 -275
- hud/telemetry/__init__.py +25 -25
- hud/telemetry/instrument.py +379 -379
- hud/telemetry/job.py +309 -309
- hud/telemetry/replay.py +74 -74
- hud/telemetry/trace.py +83 -83
- hud/tools/__init__.py +33 -33
- hud/tools/base.py +365 -365
- hud/tools/bash.py +161 -161
- hud/tools/computer/__init__.py +15 -15
- hud/tools/computer/anthropic.py +437 -437
- hud/tools/computer/hud.py +376 -376
- hud/tools/computer/openai.py +295 -295
- hud/tools/computer/settings.py +82 -82
- hud/tools/edit.py +314 -314
- hud/tools/executors/__init__.py +30 -30
- hud/tools/executors/base.py +539 -539
- hud/tools/executors/pyautogui.py +621 -621
- hud/tools/executors/tests/__init__.py +1 -1
- hud/tools/executors/tests/test_base_executor.py +338 -338
- hud/tools/executors/tests/test_pyautogui_executor.py +165 -165
- hud/tools/executors/xdo.py +511 -511
- hud/tools/playwright.py +412 -412
- hud/tools/tests/__init__.py +3 -3
- hud/tools/tests/test_base.py +282 -282
- hud/tools/tests/test_bash.py +158 -158
- hud/tools/tests/test_bash_extended.py +197 -197
- hud/tools/tests/test_computer.py +425 -425
- hud/tools/tests/test_computer_actions.py +34 -34
- hud/tools/tests/test_edit.py +259 -259
- hud/tools/tests/test_init.py +27 -27
- hud/tools/tests/test_playwright_tool.py +183 -183
- hud/tools/tests/test_tools.py +145 -145
- hud/tools/tests/test_utils.py +156 -156
- hud/tools/types.py +72 -72
- hud/tools/utils.py +50 -50
- hud/types.py +136 -136
- hud/utils/__init__.py +10 -10
- hud/utils/async_utils.py +65 -65
- hud/utils/design.py +236 -168
- hud/utils/mcp.py +55 -55
- hud/utils/progress.py +149 -149
- hud/utils/telemetry.py +66 -66
- hud/utils/tests/test_async_utils.py +173 -173
- hud/utils/tests/test_init.py +17 -17
- hud/utils/tests/test_progress.py +261 -261
- hud/utils/tests/test_telemetry.py +82 -82
- hud/utils/tests/test_version.py +8 -8
- hud/version.py +7 -7
- {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/METADATA +10 -8
- hud_python-0.4.3.dist-info/RECORD +131 -0
- {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/licenses/LICENSE +21 -21
- hud/agents/art.py +0 -101
- hud_python-0.4.1.dist-info/RECORD +0 -132
- {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/WHEEL +0 -0
- {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
"""Tests for the MCP client protocol and implementations."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
import pytest
|
|
8
|
-
from mcp import types
|
|
9
|
-
|
|
10
|
-
from hud.clients.base import AgentMCPClient, BaseHUDClient
|
|
11
|
-
from hud.clients.fastmcp import FastMCPHUDClient
|
|
12
|
-
from hud.clients.mcp_use import MCPUseHUDClient
|
|
13
|
-
from hud.types import MCPToolCall, MCPToolResult
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class MockClient(BaseHUDClient):
|
|
17
|
-
"""Mock client for testing the base class."""
|
|
18
|
-
|
|
19
|
-
def __init__(self, **kwargs):
|
|
20
|
-
super().__init__(mcp_config={"test": {"url": "mock://test"}}, **kwargs)
|
|
21
|
-
self._connected = False
|
|
22
|
-
self._mock_tools = [
|
|
23
|
-
types.Tool(
|
|
24
|
-
name="test_tool",
|
|
25
|
-
description="A test tool",
|
|
26
|
-
inputSchema={"type": "object", "properties": {}},
|
|
27
|
-
)
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
async def _connect(self, mcp_config: dict[str, dict[str, Any]]) -> None:
|
|
31
|
-
self._connected = True
|
|
32
|
-
|
|
33
|
-
async def list_tools(self) -> list[types.Tool]:
|
|
34
|
-
if not self._connected:
|
|
35
|
-
raise RuntimeError("Not connected")
|
|
36
|
-
return self._mock_tools
|
|
37
|
-
|
|
38
|
-
async def list_resources(self) -> list[types.Resource]:
|
|
39
|
-
"""Minimal list_resources for protocol satisfaction in tests."""
|
|
40
|
-
return []
|
|
41
|
-
|
|
42
|
-
async def _call_tool(self, tool_call: MCPToolCall) -> MCPToolResult:
|
|
43
|
-
if tool_call.name == "test_tool":
|
|
44
|
-
return MCPToolResult(
|
|
45
|
-
content=[types.TextContent(type="text", text="Success")], isError=False
|
|
46
|
-
)
|
|
47
|
-
raise ValueError(f"Tool {tool_call.name} not found")
|
|
48
|
-
|
|
49
|
-
async def read_resource(self, uri: str) -> types.ReadResourceResult | None:
|
|
50
|
-
if uri == "telemetry://live":
|
|
51
|
-
from pydantic import AnyUrl
|
|
52
|
-
|
|
53
|
-
return types.ReadResourceResult(
|
|
54
|
-
contents=[
|
|
55
|
-
types.TextResourceContents(
|
|
56
|
-
uri=AnyUrl(uri),
|
|
57
|
-
mimeType="application/json",
|
|
58
|
-
text='{"status": "healthy", "services": {"api": "running"}}',
|
|
59
|
-
)
|
|
60
|
-
]
|
|
61
|
-
)
|
|
62
|
-
return None
|
|
63
|
-
|
|
64
|
-
async def _disconnect(self) -> None:
|
|
65
|
-
"""Disconnect from the MCP server."""
|
|
66
|
-
self._connected = False
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class TestProtocol:
|
|
70
|
-
"""Test that all clients implement the protocol correctly."""
|
|
71
|
-
|
|
72
|
-
def test_mock_client_implements_protocol(self):
|
|
73
|
-
"""Test that our mock client implements the protocol."""
|
|
74
|
-
client = MockClient()
|
|
75
|
-
assert isinstance(client, AgentMCPClient)
|
|
76
|
-
|
|
77
|
-
def test_fastmcp_client_implements_protocol(self):
|
|
78
|
-
"""Test that FastMCPHUDClient implements the protocol."""
|
|
79
|
-
client = FastMCPHUDClient({"test": {"url": "http://localhost"}})
|
|
80
|
-
assert isinstance(client, AgentMCPClient)
|
|
81
|
-
|
|
82
|
-
def test_mcp_use_client_implements_protocol(self):
|
|
83
|
-
"""Test that MCPUseHUDClient implements the protocol."""
|
|
84
|
-
client = MCPUseHUDClient({"test": {"url": "http://localhost"}})
|
|
85
|
-
assert isinstance(client, AgentMCPClient)
|
|
86
|
-
|
|
87
|
-
@pytest.mark.asyncio
|
|
88
|
-
async def test_base_client_initialization(self):
|
|
89
|
-
"""Test that base client initialization works correctly."""
|
|
90
|
-
client = MockClient()
|
|
91
|
-
|
|
92
|
-
# Not initialized yet
|
|
93
|
-
assert not client._initialized
|
|
94
|
-
# Can't call list_tools before initialization, it would raise an error
|
|
95
|
-
|
|
96
|
-
# Initialize
|
|
97
|
-
await client.initialize()
|
|
98
|
-
|
|
99
|
-
# Should be initialized with tools discovered
|
|
100
|
-
assert client._initialized
|
|
101
|
-
tools = await client.list_tools()
|
|
102
|
-
assert len(tools) == 1
|
|
103
|
-
assert tools[0].name == "test_tool"
|
|
104
|
-
|
|
105
|
-
@pytest.mark.asyncio
|
|
106
|
-
async def test_telemetry_fetching(self):
|
|
107
|
-
"""Test that telemetry is fetched during initialization."""
|
|
108
|
-
client = MockClient()
|
|
109
|
-
|
|
110
|
-
# No telemetry before initialization
|
|
111
|
-
assert not hasattr(client, "_telemetry_data") or client._telemetry_data == {}
|
|
112
|
-
|
|
113
|
-
# Initialize
|
|
114
|
-
await client.initialize()
|
|
115
|
-
|
|
116
|
-
# Should have telemetry
|
|
117
|
-
assert hasattr(client, "_telemetry_data")
|
|
118
|
-
assert client._telemetry_data["status"] == "healthy"
|
|
119
|
-
assert client._telemetry_data["services"]["api"] == "running"
|
|
120
|
-
|
|
121
|
-
@pytest.mark.asyncio
|
|
122
|
-
async def test_context_manager(self):
|
|
123
|
-
"""Test that clients work as context managers."""
|
|
124
|
-
client = MockClient()
|
|
125
|
-
|
|
126
|
-
async with client:
|
|
127
|
-
assert client._initialized
|
|
128
|
-
tools = await client.list_tools()
|
|
129
|
-
assert len(tools) == 1
|
|
130
|
-
|
|
131
|
-
# Should be closed after exiting context
|
|
132
|
-
assert not client._initialized
|
|
133
|
-
|
|
134
|
-
@pytest.mark.asyncio
|
|
135
|
-
async def test_tool_execution(self):
|
|
136
|
-
"""Test tool execution through the protocol."""
|
|
137
|
-
client = MockClient()
|
|
138
|
-
|
|
139
|
-
await client.initialize()
|
|
140
|
-
|
|
141
|
-
# Execute a tool - test both call signatures
|
|
142
|
-
# Test with MCPToolCall
|
|
143
|
-
tool_call = MCPToolCall(name="test_tool", arguments={"arg": "value"})
|
|
144
|
-
result = await client.call_tool(tool_call)
|
|
145
|
-
|
|
146
|
-
assert isinstance(result, MCPToolResult)
|
|
147
|
-
assert not result.isError
|
|
148
|
-
from mcp.types import TextContent
|
|
149
|
-
|
|
150
|
-
assert isinstance(result.content[0], TextContent) and result.content[0].text == "Success"
|
|
151
|
-
|
|
152
|
-
# Test with name/arguments
|
|
153
|
-
result2 = await client.call_tool(name="test_tool", arguments={"arg": "value"})
|
|
154
|
-
assert isinstance(result2, MCPToolResult)
|
|
155
|
-
assert not result2.isError
|
|
156
|
-
assert isinstance(result2.content[0], TextContent) and result2.content[0].text == "Success"
|
|
157
|
-
|
|
158
|
-
@pytest.mark.asyncio
|
|
159
|
-
async def test_tool_not_found(self):
|
|
160
|
-
"""Test error handling for missing tools."""
|
|
161
|
-
client = MockClient()
|
|
162
|
-
|
|
163
|
-
await client.initialize()
|
|
164
|
-
|
|
165
|
-
# Try to execute non-existent tool
|
|
166
|
-
with pytest.raises(ValueError, match="Tool unknown_tool not found"):
|
|
167
|
-
await client.call_tool(name="unknown_tool", arguments={})
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class TestClientCompatibility:
|
|
171
|
-
"""Test that clients are compatible with agents."""
|
|
172
|
-
|
|
173
|
-
def test_protocol_satisfied(self):
|
|
174
|
-
"""Test that all clients satisfy the protocol."""
|
|
175
|
-
# Test mock client
|
|
176
|
-
mock_client = MockClient()
|
|
177
|
-
assert isinstance(mock_client, AgentMCPClient)
|
|
178
|
-
assert hasattr(mock_client, "initialize")
|
|
179
|
-
assert hasattr(mock_client, "list_tools")
|
|
180
|
-
assert hasattr(mock_client, "call_tool")
|
|
181
|
-
|
|
182
|
-
# Test FastMCP client
|
|
183
|
-
fastmcp_client = FastMCPHUDClient({"test": {"url": "http://localhost"}})
|
|
184
|
-
assert isinstance(fastmcp_client, AgentMCPClient)
|
|
185
|
-
|
|
186
|
-
# Test MCP-use client
|
|
187
|
-
mcp_use_client = MCPUseHUDClient({"test": {"url": "http://localhost"}})
|
|
188
|
-
assert isinstance(mcp_use_client, AgentMCPClient)
|
|
1
|
+
"""Tests for the MCP client protocol and implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
from mcp import types
|
|
9
|
+
|
|
10
|
+
from hud.clients.base import AgentMCPClient, BaseHUDClient
|
|
11
|
+
from hud.clients.fastmcp import FastMCPHUDClient
|
|
12
|
+
from hud.clients.mcp_use import MCPUseHUDClient
|
|
13
|
+
from hud.types import MCPToolCall, MCPToolResult
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MockClient(BaseHUDClient):
|
|
17
|
+
"""Mock client for testing the base class."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, **kwargs):
|
|
20
|
+
super().__init__(mcp_config={"test": {"url": "mock://test"}}, **kwargs)
|
|
21
|
+
self._connected = False
|
|
22
|
+
self._mock_tools = [
|
|
23
|
+
types.Tool(
|
|
24
|
+
name="test_tool",
|
|
25
|
+
description="A test tool",
|
|
26
|
+
inputSchema={"type": "object", "properties": {}},
|
|
27
|
+
)
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
async def _connect(self, mcp_config: dict[str, dict[str, Any]]) -> None:
|
|
31
|
+
self._connected = True
|
|
32
|
+
|
|
33
|
+
async def list_tools(self) -> list[types.Tool]:
|
|
34
|
+
if not self._connected:
|
|
35
|
+
raise RuntimeError("Not connected")
|
|
36
|
+
return self._mock_tools
|
|
37
|
+
|
|
38
|
+
async def list_resources(self) -> list[types.Resource]:
|
|
39
|
+
"""Minimal list_resources for protocol satisfaction in tests."""
|
|
40
|
+
return []
|
|
41
|
+
|
|
42
|
+
async def _call_tool(self, tool_call: MCPToolCall) -> MCPToolResult:
|
|
43
|
+
if tool_call.name == "test_tool":
|
|
44
|
+
return MCPToolResult(
|
|
45
|
+
content=[types.TextContent(type="text", text="Success")], isError=False
|
|
46
|
+
)
|
|
47
|
+
raise ValueError(f"Tool {tool_call.name} not found")
|
|
48
|
+
|
|
49
|
+
async def read_resource(self, uri: str) -> types.ReadResourceResult | None:
|
|
50
|
+
if uri == "telemetry://live":
|
|
51
|
+
from pydantic import AnyUrl
|
|
52
|
+
|
|
53
|
+
return types.ReadResourceResult(
|
|
54
|
+
contents=[
|
|
55
|
+
types.TextResourceContents(
|
|
56
|
+
uri=AnyUrl(uri),
|
|
57
|
+
mimeType="application/json",
|
|
58
|
+
text='{"status": "healthy", "services": {"api": "running"}}',
|
|
59
|
+
)
|
|
60
|
+
]
|
|
61
|
+
)
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
async def _disconnect(self) -> None:
|
|
65
|
+
"""Disconnect from the MCP server."""
|
|
66
|
+
self._connected = False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestProtocol:
|
|
70
|
+
"""Test that all clients implement the protocol correctly."""
|
|
71
|
+
|
|
72
|
+
def test_mock_client_implements_protocol(self):
|
|
73
|
+
"""Test that our mock client implements the protocol."""
|
|
74
|
+
client = MockClient()
|
|
75
|
+
assert isinstance(client, AgentMCPClient)
|
|
76
|
+
|
|
77
|
+
def test_fastmcp_client_implements_protocol(self):
|
|
78
|
+
"""Test that FastMCPHUDClient implements the protocol."""
|
|
79
|
+
client = FastMCPHUDClient({"test": {"url": "http://localhost"}})
|
|
80
|
+
assert isinstance(client, AgentMCPClient)
|
|
81
|
+
|
|
82
|
+
def test_mcp_use_client_implements_protocol(self):
|
|
83
|
+
"""Test that MCPUseHUDClient implements the protocol."""
|
|
84
|
+
client = MCPUseHUDClient({"test": {"url": "http://localhost"}})
|
|
85
|
+
assert isinstance(client, AgentMCPClient)
|
|
86
|
+
|
|
87
|
+
@pytest.mark.asyncio
|
|
88
|
+
async def test_base_client_initialization(self):
|
|
89
|
+
"""Test that base client initialization works correctly."""
|
|
90
|
+
client = MockClient()
|
|
91
|
+
|
|
92
|
+
# Not initialized yet
|
|
93
|
+
assert not client._initialized
|
|
94
|
+
# Can't call list_tools before initialization, it would raise an error
|
|
95
|
+
|
|
96
|
+
# Initialize
|
|
97
|
+
await client.initialize()
|
|
98
|
+
|
|
99
|
+
# Should be initialized with tools discovered
|
|
100
|
+
assert client._initialized
|
|
101
|
+
tools = await client.list_tools()
|
|
102
|
+
assert len(tools) == 1
|
|
103
|
+
assert tools[0].name == "test_tool"
|
|
104
|
+
|
|
105
|
+
@pytest.mark.asyncio
|
|
106
|
+
async def test_telemetry_fetching(self):
|
|
107
|
+
"""Test that telemetry is fetched during initialization."""
|
|
108
|
+
client = MockClient()
|
|
109
|
+
|
|
110
|
+
# No telemetry before initialization
|
|
111
|
+
assert not hasattr(client, "_telemetry_data") or client._telemetry_data == {}
|
|
112
|
+
|
|
113
|
+
# Initialize
|
|
114
|
+
await client.initialize()
|
|
115
|
+
|
|
116
|
+
# Should have telemetry
|
|
117
|
+
assert hasattr(client, "_telemetry_data")
|
|
118
|
+
assert client._telemetry_data["status"] == "healthy"
|
|
119
|
+
assert client._telemetry_data["services"]["api"] == "running"
|
|
120
|
+
|
|
121
|
+
@pytest.mark.asyncio
|
|
122
|
+
async def test_context_manager(self):
|
|
123
|
+
"""Test that clients work as context managers."""
|
|
124
|
+
client = MockClient()
|
|
125
|
+
|
|
126
|
+
async with client:
|
|
127
|
+
assert client._initialized
|
|
128
|
+
tools = await client.list_tools()
|
|
129
|
+
assert len(tools) == 1
|
|
130
|
+
|
|
131
|
+
# Should be closed after exiting context
|
|
132
|
+
assert not client._initialized
|
|
133
|
+
|
|
134
|
+
@pytest.mark.asyncio
|
|
135
|
+
async def test_tool_execution(self):
|
|
136
|
+
"""Test tool execution through the protocol."""
|
|
137
|
+
client = MockClient()
|
|
138
|
+
|
|
139
|
+
await client.initialize()
|
|
140
|
+
|
|
141
|
+
# Execute a tool - test both call signatures
|
|
142
|
+
# Test with MCPToolCall
|
|
143
|
+
tool_call = MCPToolCall(name="test_tool", arguments={"arg": "value"})
|
|
144
|
+
result = await client.call_tool(tool_call)
|
|
145
|
+
|
|
146
|
+
assert isinstance(result, MCPToolResult)
|
|
147
|
+
assert not result.isError
|
|
148
|
+
from mcp.types import TextContent
|
|
149
|
+
|
|
150
|
+
assert isinstance(result.content[0], TextContent) and result.content[0].text == "Success"
|
|
151
|
+
|
|
152
|
+
# Test with name/arguments
|
|
153
|
+
result2 = await client.call_tool(name="test_tool", arguments={"arg": "value"})
|
|
154
|
+
assert isinstance(result2, MCPToolResult)
|
|
155
|
+
assert not result2.isError
|
|
156
|
+
assert isinstance(result2.content[0], TextContent) and result2.content[0].text == "Success"
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_tool_not_found(self):
|
|
160
|
+
"""Test error handling for missing tools."""
|
|
161
|
+
client = MockClient()
|
|
162
|
+
|
|
163
|
+
await client.initialize()
|
|
164
|
+
|
|
165
|
+
# Try to execute non-existent tool
|
|
166
|
+
with pytest.raises(ValueError, match="Tool unknown_tool not found"):
|
|
167
|
+
await client.call_tool(name="unknown_tool", arguments={})
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class TestClientCompatibility:
|
|
171
|
+
"""Test that clients are compatible with agents."""
|
|
172
|
+
|
|
173
|
+
def test_protocol_satisfied(self):
|
|
174
|
+
"""Test that all clients satisfy the protocol."""
|
|
175
|
+
# Test mock client
|
|
176
|
+
mock_client = MockClient()
|
|
177
|
+
assert isinstance(mock_client, AgentMCPClient)
|
|
178
|
+
assert hasattr(mock_client, "initialize")
|
|
179
|
+
assert hasattr(mock_client, "list_tools")
|
|
180
|
+
assert hasattr(mock_client, "call_tool")
|
|
181
|
+
|
|
182
|
+
# Test FastMCP client
|
|
183
|
+
fastmcp_client = FastMCPHUDClient({"test": {"url": "http://localhost"}})
|
|
184
|
+
assert isinstance(fastmcp_client, AgentMCPClient)
|
|
185
|
+
|
|
186
|
+
# Test MCP-use client
|
|
187
|
+
mcp_use_client = MCPUseHUDClient({"test": {"url": "http://localhost"}})
|
|
188
|
+
assert isinstance(mcp_use_client, AgentMCPClient)
|
hud/clients/utils/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"""HUD MCP client utilities."""
|
|
1
|
+
"""HUD MCP client utilities."""
|