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.

Files changed (130) hide show
  1. hud/__init__.py +22 -22
  2. hud/agents/__init__.py +13 -15
  3. hud/agents/base.py +599 -599
  4. hud/agents/claude.py +373 -373
  5. hud/agents/langchain.py +261 -250
  6. hud/agents/misc/__init__.py +7 -7
  7. hud/agents/misc/response_agent.py +82 -80
  8. hud/agents/openai.py +352 -352
  9. hud/agents/openai_chat_generic.py +154 -154
  10. hud/agents/tests/__init__.py +1 -1
  11. hud/agents/tests/test_base.py +742 -742
  12. hud/agents/tests/test_claude.py +324 -324
  13. hud/agents/tests/test_client.py +363 -363
  14. hud/agents/tests/test_openai.py +237 -237
  15. hud/cli/__init__.py +617 -617
  16. hud/cli/__main__.py +8 -8
  17. hud/cli/analyze.py +371 -371
  18. hud/cli/analyze_metadata.py +230 -230
  19. hud/cli/build.py +498 -427
  20. hud/cli/clone.py +185 -185
  21. hud/cli/cursor.py +92 -92
  22. hud/cli/debug.py +392 -392
  23. hud/cli/docker_utils.py +83 -83
  24. hud/cli/init.py +280 -281
  25. hud/cli/interactive.py +353 -353
  26. hud/cli/mcp_server.py +764 -756
  27. hud/cli/pull.py +330 -336
  28. hud/cli/push.py +404 -370
  29. hud/cli/remote_runner.py +311 -311
  30. hud/cli/runner.py +160 -160
  31. hud/cli/tests/__init__.py +3 -3
  32. hud/cli/tests/test_analyze.py +284 -284
  33. hud/cli/tests/test_cli_init.py +265 -265
  34. hud/cli/tests/test_cli_main.py +27 -27
  35. hud/cli/tests/test_clone.py +142 -142
  36. hud/cli/tests/test_cursor.py +253 -253
  37. hud/cli/tests/test_debug.py +453 -453
  38. hud/cli/tests/test_mcp_server.py +139 -139
  39. hud/cli/tests/test_utils.py +388 -388
  40. hud/cli/utils.py +263 -263
  41. hud/clients/README.md +143 -143
  42. hud/clients/__init__.py +16 -16
  43. hud/clients/base.py +378 -379
  44. hud/clients/fastmcp.py +222 -222
  45. hud/clients/mcp_use.py +298 -278
  46. hud/clients/tests/__init__.py +1 -1
  47. hud/clients/tests/test_client_integration.py +111 -111
  48. hud/clients/tests/test_fastmcp.py +342 -342
  49. hud/clients/tests/test_protocol.py +188 -188
  50. hud/clients/utils/__init__.py +1 -1
  51. hud/clients/utils/retry_transport.py +160 -160
  52. hud/datasets.py +327 -322
  53. hud/misc/__init__.py +1 -1
  54. hud/misc/claude_plays_pokemon.py +292 -292
  55. hud/otel/__init__.py +35 -35
  56. hud/otel/collector.py +142 -142
  57. hud/otel/config.py +164 -164
  58. hud/otel/context.py +536 -536
  59. hud/otel/exporters.py +366 -366
  60. hud/otel/instrumentation.py +97 -97
  61. hud/otel/processors.py +118 -118
  62. hud/otel/tests/__init__.py +1 -1
  63. hud/otel/tests/test_processors.py +197 -197
  64. hud/server/__init__.py +5 -5
  65. hud/server/context.py +114 -114
  66. hud/server/helper/__init__.py +5 -5
  67. hud/server/low_level.py +132 -132
  68. hud/server/server.py +170 -166
  69. hud/server/tests/__init__.py +3 -3
  70. hud/settings.py +73 -73
  71. hud/shared/__init__.py +5 -5
  72. hud/shared/exceptions.py +180 -180
  73. hud/shared/requests.py +264 -264
  74. hud/shared/tests/test_exceptions.py +157 -157
  75. hud/shared/tests/test_requests.py +275 -275
  76. hud/telemetry/__init__.py +25 -25
  77. hud/telemetry/instrument.py +379 -379
  78. hud/telemetry/job.py +309 -309
  79. hud/telemetry/replay.py +74 -74
  80. hud/telemetry/trace.py +83 -83
  81. hud/tools/__init__.py +33 -33
  82. hud/tools/base.py +365 -365
  83. hud/tools/bash.py +161 -161
  84. hud/tools/computer/__init__.py +15 -15
  85. hud/tools/computer/anthropic.py +437 -437
  86. hud/tools/computer/hud.py +376 -376
  87. hud/tools/computer/openai.py +295 -295
  88. hud/tools/computer/settings.py +82 -82
  89. hud/tools/edit.py +314 -314
  90. hud/tools/executors/__init__.py +30 -30
  91. hud/tools/executors/base.py +539 -539
  92. hud/tools/executors/pyautogui.py +621 -621
  93. hud/tools/executors/tests/__init__.py +1 -1
  94. hud/tools/executors/tests/test_base_executor.py +338 -338
  95. hud/tools/executors/tests/test_pyautogui_executor.py +165 -165
  96. hud/tools/executors/xdo.py +511 -511
  97. hud/tools/playwright.py +412 -412
  98. hud/tools/tests/__init__.py +3 -3
  99. hud/tools/tests/test_base.py +282 -282
  100. hud/tools/tests/test_bash.py +158 -158
  101. hud/tools/tests/test_bash_extended.py +197 -197
  102. hud/tools/tests/test_computer.py +425 -425
  103. hud/tools/tests/test_computer_actions.py +34 -34
  104. hud/tools/tests/test_edit.py +259 -259
  105. hud/tools/tests/test_init.py +27 -27
  106. hud/tools/tests/test_playwright_tool.py +183 -183
  107. hud/tools/tests/test_tools.py +145 -145
  108. hud/tools/tests/test_utils.py +156 -156
  109. hud/tools/types.py +72 -72
  110. hud/tools/utils.py +50 -50
  111. hud/types.py +136 -136
  112. hud/utils/__init__.py +10 -10
  113. hud/utils/async_utils.py +65 -65
  114. hud/utils/design.py +236 -168
  115. hud/utils/mcp.py +55 -55
  116. hud/utils/progress.py +149 -149
  117. hud/utils/telemetry.py +66 -66
  118. hud/utils/tests/test_async_utils.py +173 -173
  119. hud/utils/tests/test_init.py +17 -17
  120. hud/utils/tests/test_progress.py +261 -261
  121. hud/utils/tests/test_telemetry.py +82 -82
  122. hud/utils/tests/test_version.py +8 -8
  123. hud/version.py +7 -7
  124. {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/METADATA +10 -8
  125. hud_python-0.4.3.dist-info/RECORD +131 -0
  126. {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/licenses/LICENSE +21 -21
  127. hud/agents/art.py +0 -101
  128. hud_python-0.4.1.dist-info/RECORD +0 -132
  129. {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/WHEEL +0 -0
  130. {hud_python-0.4.1.dist-info → hud_python-0.4.3.dist-info}/entry_points.txt +0 -0
@@ -1,173 +1,173 @@
1
- """Tests for async utilities."""
2
-
3
- from __future__ import annotations
4
-
5
- import asyncio
6
- import logging
7
- import threading
8
- from unittest.mock import patch
9
-
10
- import pytest
11
-
12
- from hud.utils.async_utils import fire_and_forget
13
-
14
-
15
- class TestFireAndForget:
16
- """Test fire_and_forget function."""
17
-
18
- @pytest.mark.asyncio
19
- async def test_fire_and_forget_with_running_loop(self, caplog):
20
- """Test fire_and_forget when event loop is already running."""
21
- # Create a simple coroutine that sets a flag
22
- flag = []
23
-
24
- async def test_coro():
25
- flag.append(True)
26
-
27
- # Call fire_and_forget in async context
28
- fire_and_forget(test_coro(), description="test task")
29
-
30
- # Give it a moment to execute
31
- await asyncio.sleep(0.1)
32
-
33
- # Check that the coroutine was executed
34
- assert flag == [True]
35
-
36
- @pytest.mark.asyncio
37
- async def test_fire_and_forget_with_exception(self, caplog):
38
- """Test fire_and_forget handles exceptions gracefully."""
39
-
40
- async def failing_coro():
41
- raise ValueError("Test exception")
42
-
43
- # This should not raise
44
- fire_and_forget(failing_coro(), description="failing task")
45
-
46
- # Give it a moment to execute
47
- await asyncio.sleep(0.1)
48
-
49
- # The exception should be handled silently
50
-
51
- def test_fire_and_forget_no_event_loop(self):
52
- """Test fire_and_forget when no event loop is running."""
53
- # This test runs in sync context
54
- flag = threading.Event()
55
-
56
- async def test_coro():
57
- flag.set()
58
-
59
- # Call fire_and_forget in sync context
60
- fire_and_forget(test_coro(), description="sync test")
61
-
62
- # Wait for the thread to complete
63
- assert flag.wait(timeout=2.0), "Coroutine did not execute in thread"
64
-
65
- def test_fire_and_forget_thread_exception(self, caplog):
66
- """Test fire_and_forget handles thread exceptions."""
67
-
68
- async def failing_coro():
69
- raise ValueError("Thread exception")
70
-
71
- # Patch the logger to capture the debug call
72
- from unittest.mock import patch
73
-
74
- with patch("hud.utils.async_utils.logger") as mock_logger:
75
- fire_and_forget(failing_coro(), description="thread fail")
76
-
77
- # Give thread time to execute and log
78
- import time
79
-
80
- time.sleep(0.5) # Wait for thread to complete
81
-
82
- # Check that error was logged with correct format
83
- mock_logger.debug.assert_called()
84
- # Get the actual call arguments
85
- calls = mock_logger.debug.call_args_list
86
- assert any(
87
- call[0][0] == "Error in threaded %s: %s"
88
- and call[0][1] == "thread fail"
89
- and "Thread exception" in str(call[0][2])
90
- for call in calls
91
- ), f"Expected log message not found in calls: {calls}"
92
-
93
- def test_fire_and_forget_interpreter_shutdown(self, caplog):
94
- """Test fire_and_forget handles interpreter shutdown gracefully."""
95
-
96
- async def test_coro():
97
- pass
98
-
99
- # Mock the scenario where we get interpreter shutdown error
100
- with patch("asyncio.get_running_loop") as mock_get_loop:
101
- mock_get_loop.side_effect = RuntimeError("no running event loop")
102
-
103
- with patch("threading.Thread") as mock_thread:
104
- mock_thread.side_effect = RuntimeError(
105
- "cannot schedule new futures after interpreter shutdown"
106
- )
107
-
108
- with caplog.at_level(logging.DEBUG):
109
- # This should not raise or log
110
- fire_and_forget(test_coro(), description="shutdown test")
111
-
112
- # No error should be logged for interpreter shutdown
113
- assert not any(
114
- "Could not shutdown test" in record.message for record in caplog.records
115
- )
116
-
117
- def test_fire_and_forget_other_thread_error(self, caplog):
118
- """Test fire_and_forget logs non-shutdown thread errors."""
119
-
120
- async def test_coro():
121
- pass
122
-
123
- # Mock the scenario where we get a different error
124
- with patch("asyncio.get_running_loop") as mock_get_loop:
125
- mock_get_loop.side_effect = RuntimeError("no running event loop")
126
-
127
- with patch("threading.Thread") as mock_thread:
128
- mock_thread.side_effect = RuntimeError("Some other error")
129
-
130
- # Patch the logger to capture the debug call
131
- with patch("hud.utils.async_utils.logger") as mock_logger:
132
- fire_and_forget(test_coro(), description="error test")
133
-
134
- # Check that error was logged with correct format
135
- mock_logger.debug.assert_called_once_with(
136
- "Could not %s - no event loop available: %s",
137
- "error test",
138
- mock_thread.side_effect,
139
- )
140
-
141
- @pytest.mark.asyncio
142
- async def test_fire_and_forget_cancelled_task(self):
143
- """Test fire_and_forget handles cancelled tasks."""
144
-
145
- cancel_event = asyncio.Event()
146
-
147
- async def long_running_coro():
148
- await cancel_event.wait()
149
-
150
- # Get the current loop
151
- loop = asyncio.get_running_loop()
152
-
153
- # Patch create_task to capture the task
154
- created_task = None
155
- original_create_task = loop.create_task
156
-
157
- def mock_create_task(coro):
158
- nonlocal created_task
159
- created_task = original_create_task(coro)
160
- return created_task
161
-
162
- with patch.object(loop, "create_task", side_effect=mock_create_task):
163
- fire_and_forget(long_running_coro(), description="cancel test")
164
-
165
- # Give it a moment to start
166
- await asyncio.sleep(0.01)
167
-
168
- # Cancel the task
169
- assert created_task is not None
170
- created_task.cancel()
171
-
172
- # This should not raise any exceptions
173
- await asyncio.sleep(0.01)
1
+ """Tests for async utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import logging
7
+ import threading
8
+ from unittest.mock import patch
9
+
10
+ import pytest
11
+
12
+ from hud.utils.async_utils import fire_and_forget
13
+
14
+
15
+ class TestFireAndForget:
16
+ """Test fire_and_forget function."""
17
+
18
+ @pytest.mark.asyncio
19
+ async def test_fire_and_forget_with_running_loop(self, caplog):
20
+ """Test fire_and_forget when event loop is already running."""
21
+ # Create a simple coroutine that sets a flag
22
+ flag = []
23
+
24
+ async def test_coro():
25
+ flag.append(True)
26
+
27
+ # Call fire_and_forget in async context
28
+ fire_and_forget(test_coro(), description="test task")
29
+
30
+ # Give it a moment to execute
31
+ await asyncio.sleep(0.1)
32
+
33
+ # Check that the coroutine was executed
34
+ assert flag == [True]
35
+
36
+ @pytest.mark.asyncio
37
+ async def test_fire_and_forget_with_exception(self, caplog):
38
+ """Test fire_and_forget handles exceptions gracefully."""
39
+
40
+ async def failing_coro():
41
+ raise ValueError("Test exception")
42
+
43
+ # This should not raise
44
+ fire_and_forget(failing_coro(), description="failing task")
45
+
46
+ # Give it a moment to execute
47
+ await asyncio.sleep(0.1)
48
+
49
+ # The exception should be handled silently
50
+
51
+ def test_fire_and_forget_no_event_loop(self):
52
+ """Test fire_and_forget when no event loop is running."""
53
+ # This test runs in sync context
54
+ flag = threading.Event()
55
+
56
+ async def test_coro():
57
+ flag.set()
58
+
59
+ # Call fire_and_forget in sync context
60
+ fire_and_forget(test_coro(), description="sync test")
61
+
62
+ # Wait for the thread to complete
63
+ assert flag.wait(timeout=2.0), "Coroutine did not execute in thread"
64
+
65
+ def test_fire_and_forget_thread_exception(self, caplog):
66
+ """Test fire_and_forget handles thread exceptions."""
67
+
68
+ async def failing_coro():
69
+ raise ValueError("Thread exception")
70
+
71
+ # Patch the logger to capture the debug call
72
+ from unittest.mock import patch
73
+
74
+ with patch("hud.utils.async_utils.logger") as mock_logger:
75
+ fire_and_forget(failing_coro(), description="thread fail")
76
+
77
+ # Give thread time to execute and log
78
+ import time
79
+
80
+ time.sleep(0.5) # Wait for thread to complete
81
+
82
+ # Check that error was logged with correct format
83
+ mock_logger.debug.assert_called()
84
+ # Get the actual call arguments
85
+ calls = mock_logger.debug.call_args_list
86
+ assert any(
87
+ call[0][0] == "Error in threaded %s: %s"
88
+ and call[0][1] == "thread fail"
89
+ and "Thread exception" in str(call[0][2])
90
+ for call in calls
91
+ ), f"Expected log message not found in calls: {calls}"
92
+
93
+ def test_fire_and_forget_interpreter_shutdown(self, caplog):
94
+ """Test fire_and_forget handles interpreter shutdown gracefully."""
95
+
96
+ async def test_coro():
97
+ pass
98
+
99
+ # Mock the scenario where we get interpreter shutdown error
100
+ with patch("asyncio.get_running_loop") as mock_get_loop:
101
+ mock_get_loop.side_effect = RuntimeError("no running event loop")
102
+
103
+ with patch("threading.Thread") as mock_thread:
104
+ mock_thread.side_effect = RuntimeError(
105
+ "cannot schedule new futures after interpreter shutdown"
106
+ )
107
+
108
+ with caplog.at_level(logging.DEBUG):
109
+ # This should not raise or log
110
+ fire_and_forget(test_coro(), description="shutdown test")
111
+
112
+ # No error should be logged for interpreter shutdown
113
+ assert not any(
114
+ "Could not shutdown test" in record.message for record in caplog.records
115
+ )
116
+
117
+ def test_fire_and_forget_other_thread_error(self, caplog):
118
+ """Test fire_and_forget logs non-shutdown thread errors."""
119
+
120
+ async def test_coro():
121
+ pass
122
+
123
+ # Mock the scenario where we get a different error
124
+ with patch("asyncio.get_running_loop") as mock_get_loop:
125
+ mock_get_loop.side_effect = RuntimeError("no running event loop")
126
+
127
+ with patch("threading.Thread") as mock_thread:
128
+ mock_thread.side_effect = RuntimeError("Some other error")
129
+
130
+ # Patch the logger to capture the debug call
131
+ with patch("hud.utils.async_utils.logger") as mock_logger:
132
+ fire_and_forget(test_coro(), description="error test")
133
+
134
+ # Check that error was logged with correct format
135
+ mock_logger.debug.assert_called_once_with(
136
+ "Could not %s - no event loop available: %s",
137
+ "error test",
138
+ mock_thread.side_effect,
139
+ )
140
+
141
+ @pytest.mark.asyncio
142
+ async def test_fire_and_forget_cancelled_task(self):
143
+ """Test fire_and_forget handles cancelled tasks."""
144
+
145
+ cancel_event = asyncio.Event()
146
+
147
+ async def long_running_coro():
148
+ await cancel_event.wait()
149
+
150
+ # Get the current loop
151
+ loop = asyncio.get_running_loop()
152
+
153
+ # Patch create_task to capture the task
154
+ created_task = None
155
+ original_create_task = loop.create_task
156
+
157
+ def mock_create_task(coro):
158
+ nonlocal created_task
159
+ created_task = original_create_task(coro)
160
+ return created_task
161
+
162
+ with patch.object(loop, "create_task", side_effect=mock_create_task):
163
+ fire_and_forget(long_running_coro(), description="cancel test")
164
+
165
+ # Give it a moment to start
166
+ await asyncio.sleep(0.01)
167
+
168
+ # Cancel the task
169
+ assert created_task is not None
170
+ created_task.cancel()
171
+
172
+ # This should not raise any exceptions
173
+ await asyncio.sleep(0.01)
@@ -1,17 +1,17 @@
1
- """Test utils package imports."""
2
-
3
- from __future__ import annotations
4
-
5
-
6
- def test_utils_imports():
7
- """Test that utils package can be imported."""
8
- import hud.utils
9
-
10
- # Check that the module exists
11
- assert hud.utils is not None
12
-
13
- # Try importing submodules
14
- from hud.utils import progress, telemetry
15
-
16
- assert progress is not None
17
- assert telemetry is not None
1
+ """Test utils package imports."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def test_utils_imports():
7
+ """Test that utils package can be imported."""
8
+ import hud.utils
9
+
10
+ # Check that the module exists
11
+ assert hud.utils is not None
12
+
13
+ # Try importing submodules
14
+ from hud.utils import progress, telemetry
15
+
16
+ assert progress is not None
17
+ assert telemetry is not None