hud-python 0.3.5__py3-none-any.whl → 0.4.1__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 (192) hide show
  1. hud/__init__.py +22 -89
  2. hud/agents/__init__.py +15 -0
  3. hud/agents/art.py +101 -0
  4. hud/agents/base.py +599 -0
  5. hud/{mcp → agents}/claude.py +373 -321
  6. hud/{mcp → agents}/langchain.py +250 -250
  7. hud/agents/misc/__init__.py +7 -0
  8. hud/{agent → agents}/misc/response_agent.py +80 -80
  9. hud/{mcp → agents}/openai.py +352 -334
  10. hud/agents/openai_chat_generic.py +154 -0
  11. hud/{mcp → agents}/tests/__init__.py +1 -1
  12. hud/agents/tests/test_base.py +742 -0
  13. hud/agents/tests/test_claude.py +324 -0
  14. hud/{mcp → agents}/tests/test_client.py +363 -324
  15. hud/{mcp → agents}/tests/test_openai.py +237 -238
  16. hud/cli/__init__.py +617 -0
  17. hud/cli/__main__.py +8 -0
  18. hud/cli/analyze.py +371 -0
  19. hud/cli/analyze_metadata.py +230 -0
  20. hud/cli/build.py +427 -0
  21. hud/cli/clone.py +185 -0
  22. hud/cli/cursor.py +92 -0
  23. hud/cli/debug.py +392 -0
  24. hud/cli/docker_utils.py +83 -0
  25. hud/cli/init.py +281 -0
  26. hud/cli/interactive.py +353 -0
  27. hud/cli/mcp_server.py +756 -0
  28. hud/cli/pull.py +336 -0
  29. hud/cli/push.py +370 -0
  30. hud/cli/remote_runner.py +311 -0
  31. hud/cli/runner.py +160 -0
  32. hud/cli/tests/__init__.py +3 -0
  33. hud/cli/tests/test_analyze.py +284 -0
  34. hud/cli/tests/test_cli_init.py +265 -0
  35. hud/cli/tests/test_cli_main.py +27 -0
  36. hud/cli/tests/test_clone.py +142 -0
  37. hud/cli/tests/test_cursor.py +253 -0
  38. hud/cli/tests/test_debug.py +453 -0
  39. hud/cli/tests/test_mcp_server.py +139 -0
  40. hud/cli/tests/test_utils.py +388 -0
  41. hud/cli/utils.py +263 -0
  42. hud/clients/README.md +143 -0
  43. hud/clients/__init__.py +16 -0
  44. hud/clients/base.py +379 -0
  45. hud/clients/fastmcp.py +222 -0
  46. hud/clients/mcp_use.py +278 -0
  47. hud/clients/tests/__init__.py +1 -0
  48. hud/clients/tests/test_client_integration.py +111 -0
  49. hud/clients/tests/test_fastmcp.py +342 -0
  50. hud/clients/tests/test_protocol.py +188 -0
  51. hud/clients/utils/__init__.py +1 -0
  52. hud/clients/utils/retry_transport.py +160 -0
  53. hud/datasets.py +322 -192
  54. hud/misc/__init__.py +1 -0
  55. hud/{agent → misc}/claude_plays_pokemon.py +292 -283
  56. hud/otel/__init__.py +35 -0
  57. hud/otel/collector.py +142 -0
  58. hud/otel/config.py +164 -0
  59. hud/otel/context.py +536 -0
  60. hud/otel/exporters.py +366 -0
  61. hud/otel/instrumentation.py +97 -0
  62. hud/otel/processors.py +118 -0
  63. hud/otel/tests/__init__.py +1 -0
  64. hud/otel/tests/test_processors.py +197 -0
  65. hud/server/__init__.py +5 -5
  66. hud/server/context.py +114 -0
  67. hud/server/helper/__init__.py +5 -0
  68. hud/server/low_level.py +132 -0
  69. hud/server/server.py +166 -0
  70. hud/server/tests/__init__.py +3 -0
  71. hud/settings.py +73 -79
  72. hud/shared/__init__.py +5 -0
  73. hud/{exceptions.py → shared/exceptions.py} +180 -180
  74. hud/{server → shared}/requests.py +264 -264
  75. hud/shared/tests/test_exceptions.py +157 -0
  76. hud/{server → shared}/tests/test_requests.py +275 -275
  77. hud/telemetry/__init__.py +25 -30
  78. hud/telemetry/instrument.py +379 -0
  79. hud/telemetry/job.py +309 -141
  80. hud/telemetry/replay.py +74 -0
  81. hud/telemetry/trace.py +83 -0
  82. hud/tools/__init__.py +33 -34
  83. hud/tools/base.py +365 -65
  84. hud/tools/bash.py +161 -137
  85. hud/tools/computer/__init__.py +15 -13
  86. hud/tools/computer/anthropic.py +437 -420
  87. hud/tools/computer/hud.py +376 -334
  88. hud/tools/computer/openai.py +295 -292
  89. hud/tools/computer/settings.py +82 -0
  90. hud/tools/edit.py +314 -290
  91. hud/tools/executors/__init__.py +30 -30
  92. hud/tools/executors/base.py +539 -532
  93. hud/tools/executors/pyautogui.py +621 -619
  94. hud/tools/executors/tests/__init__.py +1 -1
  95. hud/tools/executors/tests/test_base_executor.py +338 -338
  96. hud/tools/executors/tests/test_pyautogui_executor.py +165 -165
  97. hud/tools/executors/xdo.py +511 -503
  98. hud/tools/{playwright_tool.py → playwright.py} +412 -379
  99. hud/tools/tests/__init__.py +3 -3
  100. hud/tools/tests/test_base.py +282 -0
  101. hud/tools/tests/test_bash.py +158 -152
  102. hud/tools/tests/test_bash_extended.py +197 -0
  103. hud/tools/tests/test_computer.py +425 -52
  104. hud/tools/tests/test_computer_actions.py +34 -34
  105. hud/tools/tests/test_edit.py +259 -240
  106. hud/tools/tests/test_init.py +27 -27
  107. hud/tools/tests/test_playwright_tool.py +183 -183
  108. hud/tools/tests/test_tools.py +145 -157
  109. hud/tools/tests/test_utils.py +156 -156
  110. hud/tools/types.py +72 -0
  111. hud/tools/utils.py +50 -50
  112. hud/types.py +136 -89
  113. hud/utils/__init__.py +10 -16
  114. hud/utils/async_utils.py +65 -0
  115. hud/utils/design.py +168 -0
  116. hud/utils/mcp.py +55 -0
  117. hud/utils/progress.py +149 -149
  118. hud/utils/telemetry.py +66 -66
  119. hud/utils/tests/test_async_utils.py +173 -0
  120. hud/utils/tests/test_init.py +17 -21
  121. hud/utils/tests/test_progress.py +261 -225
  122. hud/utils/tests/test_telemetry.py +82 -37
  123. hud/utils/tests/test_version.py +8 -8
  124. hud/version.py +7 -7
  125. hud_python-0.4.1.dist-info/METADATA +476 -0
  126. hud_python-0.4.1.dist-info/RECORD +132 -0
  127. hud_python-0.4.1.dist-info/entry_points.txt +3 -0
  128. {hud_python-0.3.5.dist-info → hud_python-0.4.1.dist-info}/licenses/LICENSE +21 -21
  129. hud/adapters/__init__.py +0 -8
  130. hud/adapters/claude/__init__.py +0 -5
  131. hud/adapters/claude/adapter.py +0 -180
  132. hud/adapters/claude/tests/__init__.py +0 -1
  133. hud/adapters/claude/tests/test_adapter.py +0 -519
  134. hud/adapters/common/__init__.py +0 -6
  135. hud/adapters/common/adapter.py +0 -178
  136. hud/adapters/common/tests/test_adapter.py +0 -289
  137. hud/adapters/common/types.py +0 -446
  138. hud/adapters/operator/__init__.py +0 -5
  139. hud/adapters/operator/adapter.py +0 -108
  140. hud/adapters/operator/tests/__init__.py +0 -1
  141. hud/adapters/operator/tests/test_adapter.py +0 -370
  142. hud/agent/__init__.py +0 -19
  143. hud/agent/base.py +0 -126
  144. hud/agent/claude.py +0 -271
  145. hud/agent/langchain.py +0 -215
  146. hud/agent/misc/__init__.py +0 -3
  147. hud/agent/operator.py +0 -268
  148. hud/agent/tests/__init__.py +0 -1
  149. hud/agent/tests/test_base.py +0 -202
  150. hud/env/__init__.py +0 -11
  151. hud/env/client.py +0 -35
  152. hud/env/docker_client.py +0 -349
  153. hud/env/environment.py +0 -446
  154. hud/env/local_docker_client.py +0 -358
  155. hud/env/remote_client.py +0 -212
  156. hud/env/remote_docker_client.py +0 -292
  157. hud/gym.py +0 -130
  158. hud/job.py +0 -773
  159. hud/mcp/__init__.py +0 -17
  160. hud/mcp/base.py +0 -631
  161. hud/mcp/client.py +0 -312
  162. hud/mcp/tests/test_base.py +0 -512
  163. hud/mcp/tests/test_claude.py +0 -294
  164. hud/task.py +0 -149
  165. hud/taskset.py +0 -237
  166. hud/telemetry/_trace.py +0 -347
  167. hud/telemetry/context.py +0 -230
  168. hud/telemetry/exporter.py +0 -575
  169. hud/telemetry/instrumentation/__init__.py +0 -3
  170. hud/telemetry/instrumentation/mcp.py +0 -259
  171. hud/telemetry/instrumentation/registry.py +0 -59
  172. hud/telemetry/mcp_models.py +0 -270
  173. hud/telemetry/tests/__init__.py +0 -1
  174. hud/telemetry/tests/test_context.py +0 -210
  175. hud/telemetry/tests/test_trace.py +0 -312
  176. hud/tools/helper/README.md +0 -56
  177. hud/tools/helper/__init__.py +0 -9
  178. hud/tools/helper/mcp_server.py +0 -78
  179. hud/tools/helper/server_initialization.py +0 -115
  180. hud/tools/helper/utils.py +0 -58
  181. hud/trajectory.py +0 -94
  182. hud/utils/agent.py +0 -37
  183. hud/utils/common.py +0 -256
  184. hud/utils/config.py +0 -120
  185. hud/utils/deprecation.py +0 -115
  186. hud/utils/misc.py +0 -53
  187. hud/utils/tests/test_common.py +0 -277
  188. hud/utils/tests/test_config.py +0 -129
  189. hud_python-0.3.5.dist-info/METADATA +0 -284
  190. hud_python-0.3.5.dist-info/RECORD +0 -120
  191. /hud/{adapters/common → shared}/tests/__init__.py +0 -0
  192. {hud_python-0.3.5.dist-info → hud_python-0.4.1.dist-info}/WHEEL +0 -0
@@ -1,370 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import pytest
4
-
5
- from hud.adapters.common.types import (
6
- ClickAction,
7
- DragAction,
8
- MoveAction,
9
- PressAction,
10
- ResponseAction,
11
- ScreenshotFetch,
12
- ScrollAction,
13
- TypeAction,
14
- WaitAction,
15
- )
16
- from hud.adapters.operator import OperatorAdapter
17
-
18
-
19
- class TestOperatorAdapter:
20
- """Test the OperatorAdapter class."""
21
-
22
- @pytest.fixture
23
- def adapter(self):
24
- """Fixture providing a clean adapter instance."""
25
- return OperatorAdapter()
26
-
27
- def test_init(self, adapter):
28
- """Test adapter initialization."""
29
- assert adapter.agent_width == 1024
30
- assert adapter.agent_height == 768
31
- assert adapter.env_width == 1920 # Inherited from parent
32
- assert adapter.env_height == 1080 # Inherited from parent
33
-
34
- def test_key_map_constants(self, adapter):
35
- """Test KEY_MAP constants."""
36
- assert adapter.KEY_MAP["return"] == "enter"
37
- assert adapter.KEY_MAP["arrowup"] == "up"
38
- assert adapter.KEY_MAP["arrowdown"] == "down"
39
- assert adapter.KEY_MAP["arrowleft"] == "left"
40
- assert adapter.KEY_MAP["arrowright"] == "right"
41
-
42
- def test_button_map_constants(self, adapter):
43
- """Test BUTTON_MAP constants."""
44
- assert adapter.BUTTON_MAP["wheel"] == "middle"
45
-
46
- def test_map_key_mapped(self, adapter):
47
- """Test _map_key with mapped keys."""
48
- assert adapter._map_key("return") == "enter"
49
- assert adapter._map_key("RETURN") == "enter" # Test case insensitive
50
- assert adapter._map_key("arrowup") == "up"
51
- assert adapter._map_key("ArrowDown") == "down"
52
-
53
- def test_map_key_unmapped(self, adapter):
54
- """Test _map_key with unmapped keys."""
55
- assert adapter._map_key("space") == "space"
56
- assert adapter._map_key("CTRL") == "ctrl"
57
- assert adapter._map_key("Unknown") == "unknown"
58
-
59
-
60
- class TestOperatorAdapterConvert:
61
- """Test the convert method of OperatorAdapter."""
62
-
63
- @pytest.fixture
64
- def adapter(self):
65
- """Fixture providing a clean adapter instance."""
66
- return OperatorAdapter()
67
-
68
- def test_convert_click_action(self, adapter):
69
- """Test converting click action."""
70
- data = {"type": "click", "x": 100, "y": 200, "button": "left"}
71
- result = adapter.convert(data)
72
-
73
- assert isinstance(result, ClickAction)
74
- assert result.point is not None
75
- assert result.point.x == 100
76
- assert result.point.y == 200
77
- assert result.button == "left"
78
-
79
- def test_convert_click_action_default_values(self, adapter):
80
- """Test converting click action with default values."""
81
- data = {"type": "click"}
82
- result = adapter.convert(data)
83
-
84
- assert isinstance(result, ClickAction)
85
- assert result.point is not None
86
- assert result.point.x == 0
87
- assert result.point.y == 0
88
- assert result.button == "left"
89
-
90
- def test_convert_click_action_mapped_button(self, adapter):
91
- """Test converting click action with mapped button."""
92
- data = {"type": "click", "x": 100, "y": 200, "button": "wheel"}
93
- result = adapter.convert(data)
94
-
95
- assert isinstance(result, ClickAction)
96
- assert result.button == "middle"
97
-
98
- def test_convert_double_click_action(self, adapter):
99
- """Test converting double click action."""
100
- data = {"type": "double_click", "x": 150, "y": 250}
101
- result = adapter.convert(data)
102
-
103
- assert isinstance(result, ClickAction)
104
- assert result.point is not None
105
- assert result.point.x == 150
106
- assert result.point.y == 250
107
- assert result.button == "left"
108
- assert result.pattern == [100] # Double click pattern
109
-
110
- def test_convert_scroll_action(self, adapter):
111
- """Test converting scroll action."""
112
- data = {"type": "scroll", "x": 300, "y": 400, "scroll_x": 10, "scroll_y": -20}
113
- result = adapter.convert(data)
114
-
115
- assert isinstance(result, ScrollAction)
116
- assert result.point is not None
117
- assert result.scroll is not None
118
- assert result.point.x == 300
119
- assert result.point.y == 400
120
- assert result.scroll.x == 10
121
- assert result.scroll.y == -20
122
-
123
- def test_convert_scroll_action_default_values(self, adapter):
124
- """Test converting scroll action with default values."""
125
- data = {"type": "scroll"}
126
- result = adapter.convert(data)
127
-
128
- assert isinstance(result, ScrollAction)
129
- assert result.point is not None
130
- assert result.scroll is not None
131
- assert result.point.x == 0
132
- assert result.point.y == 0
133
- assert result.scroll.x == 0
134
- assert result.scroll.y == 0
135
-
136
- def test_convert_type_action(self, adapter):
137
- """Test converting type action."""
138
- data = {"type": "type", "text": "Hello, World!"}
139
- result = adapter.convert(data)
140
-
141
- assert isinstance(result, TypeAction)
142
- assert result.text == "Hello, World!"
143
- assert result.enter_after is False
144
-
145
- def test_convert_type_action_default_text(self, adapter):
146
- """Test converting type action with default text."""
147
- data = {"type": "type"}
148
- result = adapter.convert(data)
149
-
150
- assert isinstance(result, TypeAction)
151
- assert result.text == ""
152
- assert result.enter_after is False
153
-
154
- def test_convert_wait_action(self, adapter):
155
- """Test converting wait action."""
156
- data = {"type": "wait", "ms": 2000}
157
- result = adapter.convert(data)
158
-
159
- assert isinstance(result, WaitAction)
160
- assert result.time == 2000
161
-
162
- def test_convert_wait_action_default_time(self, adapter):
163
- """Test converting wait action with default time."""
164
- data = {"type": "wait"}
165
- result = adapter.convert(data)
166
-
167
- assert isinstance(result, WaitAction)
168
- assert result.time == 1000
169
-
170
- def test_convert_move_action(self, adapter):
171
- """Test converting move action."""
172
- data = {"type": "move", "x": 500, "y": 600}
173
- result = adapter.convert(data)
174
-
175
- assert isinstance(result, MoveAction)
176
- assert result.point is not None
177
- assert result.point.x == 500
178
- assert result.point.y == 600
179
-
180
- def test_convert_move_action_default_values(self, adapter):
181
- """Test converting move action with default values."""
182
- data = {"type": "move"}
183
- result = adapter.convert(data)
184
-
185
- assert isinstance(result, MoveAction)
186
- assert result.point is not None
187
- assert result.point.x == 0
188
- assert result.point.y == 0
189
-
190
- def test_convert_keypress_action(self, adapter):
191
- """Test converting keypress action."""
192
- data = {"type": "keypress", "keys": ["ctrl", "c"]}
193
- result = adapter.convert(data)
194
-
195
- assert isinstance(result, PressAction)
196
- assert result.keys == ["ctrl", "c"]
197
-
198
- def test_convert_keypress_action_mapped_keys(self, adapter):
199
- """Test converting keypress action with mapped keys."""
200
- data = {"type": "keypress", "keys": ["return", "arrowup"]}
201
- result = adapter.convert(data)
202
-
203
- assert isinstance(result, PressAction)
204
- assert result.keys == ["enter", "up"]
205
-
206
- def test_convert_keypress_action_default_keys(self, adapter):
207
- """Test converting keypress action with default keys."""
208
- data = {"type": "keypress"}
209
- result = adapter.convert(data)
210
-
211
- assert isinstance(result, PressAction)
212
- assert result.keys == []
213
-
214
- def test_convert_drag_action(self, adapter):
215
- """Test converting drag action."""
216
- data = {
217
- "type": "drag",
218
- "path": [{"x": 100, "y": 200}, {"x": 150, "y": 250}, {"x": 200, "y": 300}],
219
- }
220
- result = adapter.convert(data)
221
-
222
- assert isinstance(result, DragAction)
223
- assert len(result.path) == 3
224
- assert result.path[0].x == 100
225
- assert result.path[0].y == 200
226
- assert result.path[1].x == 150
227
- assert result.path[1].y == 250
228
- assert result.path[2].x == 200
229
- assert result.path[2].y == 300
230
-
231
- def test_convert_drag_action_default_path(self, adapter):
232
- """Test converting drag action with default path."""
233
- data = {"type": "drag"}
234
- result = adapter.convert(data)
235
-
236
- assert isinstance(result, DragAction)
237
- assert result.path == []
238
-
239
- def test_convert_drag_action_path_with_missing_coords(self, adapter):
240
- """Test converting drag action with missing coordinates."""
241
- data = {
242
- "type": "drag",
243
- "path": [
244
- {"x": 100}, # Missing y
245
- {"y": 200}, # Missing x
246
- {}, # Missing both
247
- ],
248
- }
249
- result = adapter.convert(data)
250
-
251
- assert isinstance(result, DragAction)
252
- assert len(result.path) == 3
253
- assert result.path[0].x == 100
254
- assert result.path[0].y == 0 # Default value
255
- assert result.path[1].x == 0 # Default value
256
- assert result.path[1].y == 200
257
- assert result.path[2].x == 0 # Default value
258
- assert result.path[2].y == 0 # Default value
259
-
260
- def test_convert_screenshot_action(self, adapter):
261
- """Test converting screenshot action."""
262
- data = {"type": "screenshot"}
263
- result = adapter.convert(data)
264
-
265
- assert isinstance(result, ScreenshotFetch)
266
-
267
- def test_convert_response_action(self, adapter):
268
- """Test converting response action."""
269
- data = {"type": "response", "text": "Task completed successfully"}
270
- result = adapter.convert(data)
271
-
272
- assert isinstance(result, ResponseAction)
273
- assert result.text == "Task completed successfully"
274
-
275
- def test_convert_response_action_default_text(self, adapter):
276
- """Test converting response action with default text."""
277
- data = {"type": "response"}
278
- result = adapter.convert(data)
279
-
280
- assert isinstance(result, ResponseAction)
281
- assert result.text == ""
282
-
283
- def test_convert_unsupported_action_type(self, adapter):
284
- """Test converting unsupported action type."""
285
- data = {"type": "unsupported_action"}
286
-
287
- with pytest.raises(ValueError) as exc_info:
288
- adapter.convert(data)
289
-
290
- assert "Unsupported action type: unsupported_action" in str(exc_info.value)
291
-
292
- def test_convert_invalid_data_structure(self, adapter):
293
- """Test converting invalid data structure."""
294
- # Test with non-dict data
295
- with pytest.raises(ValueError) as exc_info:
296
- adapter.convert("invalid_data")
297
-
298
- assert "Invalid action" in str(exc_info.value)
299
-
300
- def test_convert_missing_type_field(self, adapter):
301
- """Test converting data without type field."""
302
- data = {"x": 100, "y": 200} # Missing type
303
-
304
- with pytest.raises(ValueError) as exc_info:
305
- adapter.convert(data)
306
-
307
- assert "Unsupported action type: None" in str(exc_info.value)
308
-
309
- def test_convert_none_data(self, adapter):
310
- """Test converting None data."""
311
- with pytest.raises(ValueError) as exc_info:
312
- adapter.convert(None)
313
-
314
- assert "Invalid action" in str(exc_info.value)
315
-
316
-
317
- class TestOperatorAdapterIntegration:
318
- """Integration tests for OperatorAdapter."""
319
-
320
- @pytest.fixture
321
- def adapter(self):
322
- """Fixture providing a clean adapter instance."""
323
- return OperatorAdapter()
324
-
325
- def test_full_click_pipeline(self, adapter):
326
- """Test full click action processing pipeline."""
327
- # Set adapter dimensions to avoid scaling
328
- adapter.agent_width = 1920
329
- adapter.agent_height = 1080
330
- adapter.env_width = 1920
331
- adapter.env_height = 1080
332
-
333
- # Test the full adapt method
334
- raw_action = {"type": "click", "x": 100, "y": 200, "button": "right"}
335
-
336
- result = adapter.adapt(raw_action)
337
-
338
- assert isinstance(result, ClickAction)
339
- assert result.point is not None
340
- assert result.point.x == 100
341
- assert result.point.y == 200
342
- assert result.button == "right"
343
-
344
- # Check that it was added to memory
345
- assert len(adapter.memory) == 1
346
- assert adapter.memory[0] == result
347
-
348
- def test_multiple_actions_processing(self, adapter):
349
- """Test processing multiple actions."""
350
- # Set adapter dimensions to avoid scaling
351
- adapter.agent_width = 1920
352
- adapter.agent_height = 1080
353
- adapter.env_width = 1920
354
- adapter.env_height = 1080
355
-
356
- actions = [
357
- {"type": "click", "x": 100, "y": 200},
358
- {"type": "type", "text": "hello"},
359
- {"type": "keypress", "keys": ["return"]},
360
- ]
361
-
362
- results = adapter.adapt_list(actions)
363
-
364
- assert len(results) == 3
365
- assert isinstance(results[0], ClickAction)
366
- assert isinstance(results[1], TypeAction)
367
- assert isinstance(results[2], PressAction)
368
-
369
- # Check memory
370
- assert len(adapter.memory) == 3
hud/agent/__init__.py DELETED
@@ -1,19 +0,0 @@
1
- from .base import Agent
2
- from .claude import ClaudeAgent
3
- from .claude_plays_pokemon import ClaudePlaysPokemon
4
- from .operator import OperatorAgent
5
- from .langchain import LangchainAgent
6
- from .misc import ResponseAgent
7
-
8
- from hud.adapters import OperatorAdapter, ClaudeAdapter
9
-
10
- __all__ = [
11
- "Agent",
12
- "ClaudeAgent",
13
- "OperatorAgent",
14
- "OperatorAdapter",
15
- "ClaudeAdapter",
16
- "LangchainAgent",
17
- "ClaudePlaysPokemon",
18
- "ResponseAgent",
19
- ]
hud/agent/base.py DELETED
@@ -1,126 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import Any, Sequence, TypeVar, Generic
3
-
4
- from hud.adapters import Adapter, CLA
5
- from hud.types import Gym
6
- from hud.utils.common import Observation
7
- import logging
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
- # Generic type for different client types (Anthropic, OpenAI, etc.)
12
- ClientT = TypeVar("ClientT")
13
- ActionT = TypeVar("ActionT")
14
-
15
-
16
- class Agent(Generic[ClientT, ActionT], ABC):
17
- """
18
- Base class for all agents.
19
-
20
- Implements a three-stage prediction process:
21
- 1. preprocess - Prepare observation data (e.g., rescale screenshot)
22
- 2. fetch_response - Make API calls to get model response
23
- 3. postprocess - Convert model actions to HUD format
24
-
25
- Subclasses only need to implement the fetch_response method.
26
- """
27
-
28
- transfer_gyms: dict[Gym, Gym] = {}
29
-
30
- def __init__(
31
- self,
32
- client: ClientT | None = None,
33
- adapter: Adapter | None = None,
34
- name: str | None = None,
35
- ):
36
- """
37
- Initialize the agent.
38
-
39
- Args:
40
- client: The client to use for API calls
41
- adapter: The adapter to use for preprocessing and postprocessing
42
- """
43
- self.client = client
44
- self.adapter = adapter
45
- self.name = name
46
-
47
- def preprocess(self, observation: Observation) -> Observation:
48
- """
49
- Preprocess the observation before sending to the model.
50
-
51
- Args:
52
- observation: The raw observation from the environment
53
-
54
- Returns:
55
- Observation: The processed observation ready for the model
56
- """
57
- if not self.adapter or not observation.screenshot:
58
- return observation
59
-
60
- # Create a new observation with the rescaled screenshot
61
- processed_obs = Observation(
62
- text=observation.text, screenshot=self.adapter.rescale(observation.screenshot)
63
- )
64
- return processed_obs
65
-
66
- @abstractmethod
67
- async def fetch_response(self, observation: Observation) -> tuple[list[ActionT], bool]:
68
- """
69
- Fetch a response from the model based on the observation.
70
-
71
- Args:
72
- observation: The preprocessed observation
73
-
74
- Returns:
75
- tuple[list[ActionT], bool]: A tuple containing the list of raw actions,
76
- boolean indicating if the agent believes it has
77
- completed the task.
78
- """
79
- pass
80
-
81
- def postprocess(self, actions: list[ActionT]) -> list[CLA]:
82
- """
83
- Convert model actions to HUD actions.
84
-
85
- Args:
86
- actions: The raw actions from the model
87
- Returns:
88
- Sequence[CLA]: The actions converted to HUD format
89
- """
90
- if not self.adapter:
91
- raise ValueError("Cannot postprocess actions without an adapter")
92
-
93
- return self.adapter.adapt_list(actions)
94
-
95
- async def predict(
96
- self, observation: Observation, verbose: bool = False
97
- ) -> tuple[list[CLA] | list[ActionT], bool]:
98
- """
99
- Predict the next action based on the observation.
100
-
101
- Implements the full three-stage prediction process.
102
-
103
- Args:
104
- observation: The observation from the environment
105
-
106
- Returns:
107
- tuple[list[CLA] | list[ActionT], bool]: A tuple containing the list of actions and a boolean
108
- indicating if the agent believes it has completed the task
109
- """
110
- if verbose:
111
- logger.info("Predicting action...")
112
- # Stage 1: Preprocess the observation
113
- processed_obs = self.preprocess(observation)
114
-
115
- # Stage 2: Fetch response from the model
116
- actions, done = await self.fetch_response(processed_obs)
117
- if verbose:
118
- logger.info("Raw action: %s", actions)
119
-
120
- # Stage 3: Postprocess the actions if we have an adapter
121
- if self.adapter and actions:
122
- hud_actions = self.postprocess(actions)
123
- return hud_actions, done
124
-
125
- # If no adapter, return actions as is
126
- return actions, done