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,160 +1,160 @@
|
|
|
1
|
-
"""Custom HTTPX transport with retry logic for HTTP errors."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
import logging
|
|
7
|
-
from typing import TYPE_CHECKING, Any
|
|
8
|
-
|
|
9
|
-
import httpx
|
|
10
|
-
from httpx._transports.default import AsyncHTTPTransport
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from httpx._models import Request, Response
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class RetryTransport(AsyncHTTPTransport):
|
|
19
|
-
"""
|
|
20
|
-
Custom HTTPX transport that retries on specific HTTP status codes.
|
|
21
|
-
|
|
22
|
-
This transport wraps the standard AsyncHTTPTransport and adds
|
|
23
|
-
retry logic with exponential backoff for gateway errors (502, 503, 504).
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
*args: Any,
|
|
29
|
-
max_retries: int = 3,
|
|
30
|
-
retry_status_codes: set[int] | None = None,
|
|
31
|
-
retry_delay: float = 1.0,
|
|
32
|
-
backoff_factor: float = 2.0,
|
|
33
|
-
**kwargs: Any,
|
|
34
|
-
) -> None:
|
|
35
|
-
"""
|
|
36
|
-
Initialize retry transport.
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
max_retries: Maximum number of retry attempts
|
|
40
|
-
retry_status_codes: HTTP status codes to retry (default: 502, 503, 504)
|
|
41
|
-
retry_delay: Initial delay between retries in seconds
|
|
42
|
-
backoff_factor: Multiplier for exponential backoff
|
|
43
|
-
*args, **kwargs: Passed to AsyncHTTPTransport
|
|
44
|
-
"""
|
|
45
|
-
super().__init__(*args, **kwargs)
|
|
46
|
-
self.max_retries = max_retries
|
|
47
|
-
self.retry_status_codes = retry_status_codes or {502, 503, 504}
|
|
48
|
-
self.retry_delay = retry_delay
|
|
49
|
-
self.backoff_factor = backoff_factor
|
|
50
|
-
|
|
51
|
-
async def handle_async_request(self, request: Request) -> Response:
|
|
52
|
-
"""
|
|
53
|
-
Handle request with retry logic.
|
|
54
|
-
|
|
55
|
-
Retries the request if it fails with a retryable status code,
|
|
56
|
-
using exponential backoff between attempts.
|
|
57
|
-
"""
|
|
58
|
-
last_exception = None
|
|
59
|
-
|
|
60
|
-
for attempt in range(self.max_retries + 1):
|
|
61
|
-
try:
|
|
62
|
-
response = await super().handle_async_request(request)
|
|
63
|
-
|
|
64
|
-
# Check if we should retry based on status code
|
|
65
|
-
if response.status_code in self.retry_status_codes and attempt < self.max_retries:
|
|
66
|
-
delay = self.retry_delay * (self.backoff_factor**attempt)
|
|
67
|
-
logger.warning(
|
|
68
|
-
"Got %d from %s, retrying in %.1fs (attempt %d/%d)",
|
|
69
|
-
response.status_code,
|
|
70
|
-
request.url,
|
|
71
|
-
delay,
|
|
72
|
-
attempt + 1,
|
|
73
|
-
self.max_retries,
|
|
74
|
-
)
|
|
75
|
-
# Important: Close the response to free resources
|
|
76
|
-
await response.aclose()
|
|
77
|
-
await asyncio.sleep(delay)
|
|
78
|
-
continue
|
|
79
|
-
|
|
80
|
-
return response
|
|
81
|
-
|
|
82
|
-
except (httpx.ConnectError, httpx.TimeoutException) as e:
|
|
83
|
-
last_exception = e
|
|
84
|
-
if attempt < self.max_retries:
|
|
85
|
-
delay = self.retry_delay * (self.backoff_factor**attempt)
|
|
86
|
-
logger.warning(
|
|
87
|
-
"%s for %s, retrying in %.1fs (attempt %d/%d)",
|
|
88
|
-
type(e).__name__,
|
|
89
|
-
request.url,
|
|
90
|
-
delay,
|
|
91
|
-
attempt + 1,
|
|
92
|
-
self.max_retries,
|
|
93
|
-
)
|
|
94
|
-
await asyncio.sleep(delay)
|
|
95
|
-
continue
|
|
96
|
-
raise
|
|
97
|
-
|
|
98
|
-
# If we get here, we've exhausted retries
|
|
99
|
-
if last_exception:
|
|
100
|
-
raise last_exception
|
|
101
|
-
else:
|
|
102
|
-
# This shouldn't happen, but just in case
|
|
103
|
-
raise httpx.HTTPStatusError(
|
|
104
|
-
"Max retries exceeded",
|
|
105
|
-
request=request,
|
|
106
|
-
response=response,
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def create_retry_httpx_client(
|
|
111
|
-
headers: dict[str, str] | None = None,
|
|
112
|
-
timeout: httpx.Timeout | None = None,
|
|
113
|
-
auth: httpx.Auth | None = None,
|
|
114
|
-
max_retries: int = 3,
|
|
115
|
-
retry_status_codes: set[int] | None = None,
|
|
116
|
-
) -> httpx.AsyncClient:
|
|
117
|
-
"""
|
|
118
|
-
Create an HTTPX AsyncClient with HTTP error retry support.
|
|
119
|
-
|
|
120
|
-
This factory creates an HTTPX client with a custom transport that
|
|
121
|
-
retries on specific HTTP status codes (502, 503, 504 by default).
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
headers: Optional headers to include with all requests
|
|
125
|
-
timeout: Request timeout (defaults to 600s)
|
|
126
|
-
auth: Optional authentication handler
|
|
127
|
-
max_retries: Maximum retry attempts (default: 3)
|
|
128
|
-
retry_status_codes: Status codes to retry (default: {502, 503, 504})
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
Configured httpx.AsyncClient with retry transport
|
|
132
|
-
"""
|
|
133
|
-
if timeout is None:
|
|
134
|
-
timeout = httpx.Timeout(600.0) # 10 minutes
|
|
135
|
-
|
|
136
|
-
# Use higher connection limits for concurrent operations
|
|
137
|
-
# These match HUD server's configuration for consistency
|
|
138
|
-
limits = httpx.Limits(
|
|
139
|
-
max_connections=1000,
|
|
140
|
-
max_keepalive_connections=1000,
|
|
141
|
-
keepalive_expiry=20.0,
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
# Create our custom retry transport
|
|
145
|
-
transport = RetryTransport(
|
|
146
|
-
max_retries=max_retries,
|
|
147
|
-
retry_status_codes=retry_status_codes,
|
|
148
|
-
# Connection-level retries (in addition to HTTP retries)
|
|
149
|
-
retries=3,
|
|
150
|
-
limits=limits,
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
return httpx.AsyncClient(
|
|
154
|
-
transport=transport,
|
|
155
|
-
headers=headers,
|
|
156
|
-
timeout=timeout,
|
|
157
|
-
auth=auth,
|
|
158
|
-
follow_redirects=True,
|
|
159
|
-
limits=limits,
|
|
160
|
-
)
|
|
1
|
+
"""Custom HTTPX transport with retry logic for HTTP errors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
from httpx._transports.default import AsyncHTTPTransport
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from httpx._models import Request, Response
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RetryTransport(AsyncHTTPTransport):
|
|
19
|
+
"""
|
|
20
|
+
Custom HTTPX transport that retries on specific HTTP status codes.
|
|
21
|
+
|
|
22
|
+
This transport wraps the standard AsyncHTTPTransport and adds
|
|
23
|
+
retry logic with exponential backoff for gateway errors (502, 503, 504).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
*args: Any,
|
|
29
|
+
max_retries: int = 3,
|
|
30
|
+
retry_status_codes: set[int] | None = None,
|
|
31
|
+
retry_delay: float = 1.0,
|
|
32
|
+
backoff_factor: float = 2.0,
|
|
33
|
+
**kwargs: Any,
|
|
34
|
+
) -> None:
|
|
35
|
+
"""
|
|
36
|
+
Initialize retry transport.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
max_retries: Maximum number of retry attempts
|
|
40
|
+
retry_status_codes: HTTP status codes to retry (default: 502, 503, 504)
|
|
41
|
+
retry_delay: Initial delay between retries in seconds
|
|
42
|
+
backoff_factor: Multiplier for exponential backoff
|
|
43
|
+
*args, **kwargs: Passed to AsyncHTTPTransport
|
|
44
|
+
"""
|
|
45
|
+
super().__init__(*args, **kwargs)
|
|
46
|
+
self.max_retries = max_retries
|
|
47
|
+
self.retry_status_codes = retry_status_codes or {502, 503, 504}
|
|
48
|
+
self.retry_delay = retry_delay
|
|
49
|
+
self.backoff_factor = backoff_factor
|
|
50
|
+
|
|
51
|
+
async def handle_async_request(self, request: Request) -> Response:
|
|
52
|
+
"""
|
|
53
|
+
Handle request with retry logic.
|
|
54
|
+
|
|
55
|
+
Retries the request if it fails with a retryable status code,
|
|
56
|
+
using exponential backoff between attempts.
|
|
57
|
+
"""
|
|
58
|
+
last_exception = None
|
|
59
|
+
|
|
60
|
+
for attempt in range(self.max_retries + 1):
|
|
61
|
+
try:
|
|
62
|
+
response = await super().handle_async_request(request)
|
|
63
|
+
|
|
64
|
+
# Check if we should retry based on status code
|
|
65
|
+
if response.status_code in self.retry_status_codes and attempt < self.max_retries:
|
|
66
|
+
delay = self.retry_delay * (self.backoff_factor**attempt)
|
|
67
|
+
logger.warning(
|
|
68
|
+
"Got %d from %s, retrying in %.1fs (attempt %d/%d)",
|
|
69
|
+
response.status_code,
|
|
70
|
+
request.url,
|
|
71
|
+
delay,
|
|
72
|
+
attempt + 1,
|
|
73
|
+
self.max_retries,
|
|
74
|
+
)
|
|
75
|
+
# Important: Close the response to free resources
|
|
76
|
+
await response.aclose()
|
|
77
|
+
await asyncio.sleep(delay)
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
return response
|
|
81
|
+
|
|
82
|
+
except (httpx.ConnectError, httpx.TimeoutException) as e:
|
|
83
|
+
last_exception = e
|
|
84
|
+
if attempt < self.max_retries:
|
|
85
|
+
delay = self.retry_delay * (self.backoff_factor**attempt)
|
|
86
|
+
logger.warning(
|
|
87
|
+
"%s for %s, retrying in %.1fs (attempt %d/%d)",
|
|
88
|
+
type(e).__name__,
|
|
89
|
+
request.url,
|
|
90
|
+
delay,
|
|
91
|
+
attempt + 1,
|
|
92
|
+
self.max_retries,
|
|
93
|
+
)
|
|
94
|
+
await asyncio.sleep(delay)
|
|
95
|
+
continue
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
# If we get here, we've exhausted retries
|
|
99
|
+
if last_exception:
|
|
100
|
+
raise last_exception
|
|
101
|
+
else:
|
|
102
|
+
# This shouldn't happen, but just in case
|
|
103
|
+
raise httpx.HTTPStatusError(
|
|
104
|
+
"Max retries exceeded",
|
|
105
|
+
request=request,
|
|
106
|
+
response=response,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def create_retry_httpx_client(
|
|
111
|
+
headers: dict[str, str] | None = None,
|
|
112
|
+
timeout: httpx.Timeout | None = None,
|
|
113
|
+
auth: httpx.Auth | None = None,
|
|
114
|
+
max_retries: int = 3,
|
|
115
|
+
retry_status_codes: set[int] | None = None,
|
|
116
|
+
) -> httpx.AsyncClient:
|
|
117
|
+
"""
|
|
118
|
+
Create an HTTPX AsyncClient with HTTP error retry support.
|
|
119
|
+
|
|
120
|
+
This factory creates an HTTPX client with a custom transport that
|
|
121
|
+
retries on specific HTTP status codes (502, 503, 504 by default).
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
headers: Optional headers to include with all requests
|
|
125
|
+
timeout: Request timeout (defaults to 600s)
|
|
126
|
+
auth: Optional authentication handler
|
|
127
|
+
max_retries: Maximum retry attempts (default: 3)
|
|
128
|
+
retry_status_codes: Status codes to retry (default: {502, 503, 504})
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Configured httpx.AsyncClient with retry transport
|
|
132
|
+
"""
|
|
133
|
+
if timeout is None:
|
|
134
|
+
timeout = httpx.Timeout(600.0) # 10 minutes
|
|
135
|
+
|
|
136
|
+
# Use higher connection limits for concurrent operations
|
|
137
|
+
# These match HUD server's configuration for consistency
|
|
138
|
+
limits = httpx.Limits(
|
|
139
|
+
max_connections=1000,
|
|
140
|
+
max_keepalive_connections=1000,
|
|
141
|
+
keepalive_expiry=20.0,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Create our custom retry transport
|
|
145
|
+
transport = RetryTransport(
|
|
146
|
+
max_retries=max_retries,
|
|
147
|
+
retry_status_codes=retry_status_codes,
|
|
148
|
+
# Connection-level retries (in addition to HTTP retries)
|
|
149
|
+
retries=3,
|
|
150
|
+
limits=limits,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
return httpx.AsyncClient(
|
|
154
|
+
transport=transport,
|
|
155
|
+
headers=headers,
|
|
156
|
+
timeout=timeout,
|
|
157
|
+
auth=auth,
|
|
158
|
+
follow_redirects=True,
|
|
159
|
+
limits=limits,
|
|
160
|
+
)
|