hud-python 0.4.22__py3-none-any.whl → 0.4.23__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/agents/base.py +37 -39
- hud/agents/grounded_openai.py +3 -1
- hud/agents/misc/response_agent.py +3 -2
- hud/agents/openai.py +2 -2
- hud/agents/openai_chat_generic.py +3 -1
- hud/cli/__init__.py +34 -24
- hud/cli/analyze.py +27 -26
- hud/cli/build.py +50 -46
- hud/cli/debug.py +7 -7
- hud/cli/dev.py +107 -99
- hud/cli/eval.py +31 -29
- hud/cli/hf.py +53 -53
- hud/cli/init.py +28 -28
- hud/cli/list_func.py +22 -22
- hud/cli/pull.py +36 -36
- hud/cli/push.py +76 -74
- hud/cli/remove.py +42 -40
- hud/cli/rl/__init__.py +2 -2
- hud/cli/rl/init.py +41 -41
- hud/cli/rl/pod.py +97 -91
- hud/cli/rl/ssh.py +42 -40
- hud/cli/rl/train.py +75 -73
- hud/cli/rl/utils.py +10 -10
- hud/cli/tests/test_analyze.py +1 -1
- hud/cli/tests/test_analyze_metadata.py +2 -2
- hud/cli/tests/test_pull.py +45 -45
- hud/cli/tests/test_push.py +31 -29
- hud/cli/tests/test_registry.py +15 -15
- hud/cli/utils/environment.py +11 -11
- hud/cli/utils/interactive.py +17 -17
- hud/cli/utils/logging.py +12 -12
- hud/cli/utils/metadata.py +12 -12
- hud/cli/utils/registry.py +5 -5
- hud/cli/utils/runner.py +23 -23
- hud/cli/utils/server.py +16 -16
- hud/shared/hints.py +7 -7
- hud/tools/grounding/grounder.py +2 -1
- hud/types.py +4 -4
- hud/utils/__init__.py +3 -3
- hud/utils/{design.py → hud_console.py} +39 -33
- hud/utils/pretty_errors.py +6 -6
- hud/utils/tests/test_version.py +1 -1
- hud/version.py +1 -1
- {hud_python-0.4.22.dist-info → hud_python-0.4.23.dist-info}/METADATA +3 -1
- {hud_python-0.4.22.dist-info → hud_python-0.4.23.dist-info}/RECORD +48 -48
- {hud_python-0.4.22.dist-info → hud_python-0.4.23.dist-info}/WHEEL +0 -0
- {hud_python-0.4.22.dist-info → hud_python-0.4.23.dist-info}/entry_points.txt +0 -0
- {hud_python-0.4.22.dist-info → hud_python-0.4.23.dist-info}/licenses/LICENSE +0 -0
hud/cli/build.py
CHANGED
|
@@ -14,7 +14,7 @@ import typer
|
|
|
14
14
|
import yaml
|
|
15
15
|
|
|
16
16
|
from hud.clients import MCPClient
|
|
17
|
-
from hud.utils.
|
|
17
|
+
from hud.utils.hud_console import HUDConsole
|
|
18
18
|
from hud.version import __version__ as hud_version
|
|
19
19
|
|
|
20
20
|
from .utils.registry import save_to_registry
|
|
@@ -156,7 +156,7 @@ async def analyze_mcp_environment(
|
|
|
156
156
|
image: str, verbose: bool = False, env_vars: dict[str, str] | None = None
|
|
157
157
|
) -> dict[str, Any]:
|
|
158
158
|
"""Analyze an MCP environment to extract metadata."""
|
|
159
|
-
|
|
159
|
+
hud_console = HUDConsole()
|
|
160
160
|
env_vars = env_vars or {}
|
|
161
161
|
|
|
162
162
|
# Build Docker command to run the image
|
|
@@ -180,7 +180,7 @@ async def analyze_mcp_environment(
|
|
|
180
180
|
|
|
181
181
|
try:
|
|
182
182
|
if verbose:
|
|
183
|
-
|
|
183
|
+
hud_console.info(f"Initializing MCP client with command: {' '.join(docker_cmd)}")
|
|
184
184
|
|
|
185
185
|
await client.initialize()
|
|
186
186
|
initialized = True
|
|
@@ -215,7 +215,7 @@ async def analyze_mcp_environment(
|
|
|
215
215
|
await client.shutdown()
|
|
216
216
|
except Exception:
|
|
217
217
|
# Ignore shutdown errors
|
|
218
|
-
|
|
218
|
+
hud_console.warning("Failed to shutdown MCP client")
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
def build_docker_image(
|
|
@@ -226,13 +226,13 @@ def build_docker_image(
|
|
|
226
226
|
build_args: dict[str, str] | None = None,
|
|
227
227
|
) -> bool:
|
|
228
228
|
"""Build a Docker image from a directory."""
|
|
229
|
-
|
|
229
|
+
hud_console = HUDConsole()
|
|
230
230
|
build_args = build_args or {}
|
|
231
231
|
|
|
232
232
|
# Check if Dockerfile exists
|
|
233
233
|
dockerfile = directory / "Dockerfile"
|
|
234
234
|
if not dockerfile.exists():
|
|
235
|
-
|
|
235
|
+
hud_console.error(f"No Dockerfile found in {directory}")
|
|
236
236
|
return False
|
|
237
237
|
|
|
238
238
|
# Build command
|
|
@@ -247,14 +247,14 @@ def build_docker_image(
|
|
|
247
247
|
cmd.append(str(directory))
|
|
248
248
|
|
|
249
249
|
# Always show build output
|
|
250
|
-
|
|
250
|
+
hud_console.info(f"Running: {' '.join(cmd)}")
|
|
251
251
|
|
|
252
252
|
try:
|
|
253
253
|
# Use Docker's native output formatting - no capture, let Docker handle display
|
|
254
254
|
result = subprocess.run(cmd, check=False) # noqa: S603
|
|
255
255
|
return result.returncode == 0
|
|
256
256
|
except Exception as e:
|
|
257
|
-
|
|
257
|
+
hud_console.error(f"Build error: {e}")
|
|
258
258
|
return False
|
|
259
259
|
|
|
260
260
|
|
|
@@ -266,20 +266,20 @@ def build_environment(
|
|
|
266
266
|
env_vars: dict[str, str] | None = None,
|
|
267
267
|
) -> None:
|
|
268
268
|
"""Build a HUD environment and generate lock file."""
|
|
269
|
-
|
|
269
|
+
hud_console = HUDConsole()
|
|
270
270
|
env_vars = env_vars or {}
|
|
271
|
-
|
|
271
|
+
hud_console.header("HUD Environment Build")
|
|
272
272
|
|
|
273
273
|
# Resolve directory
|
|
274
274
|
env_dir = Path(directory).resolve()
|
|
275
275
|
if not env_dir.exists():
|
|
276
|
-
|
|
276
|
+
hud_console.error(f"Directory not found: {directory}")
|
|
277
277
|
raise typer.Exit(1)
|
|
278
278
|
|
|
279
279
|
# Check for pyproject.toml
|
|
280
280
|
pyproject_path = env_dir / "pyproject.toml"
|
|
281
281
|
if not pyproject_path.exists():
|
|
282
|
-
|
|
282
|
+
hud_console.error(f"No pyproject.toml found in {directory}")
|
|
283
283
|
raise typer.Exit(1)
|
|
284
284
|
|
|
285
285
|
# Read pyproject.toml to get image name
|
|
@@ -301,17 +301,17 @@ def build_environment(
|
|
|
301
301
|
# Build temporary image first
|
|
302
302
|
temp_tag = f"hud-build-temp:{int(time.time())}"
|
|
303
303
|
|
|
304
|
-
|
|
304
|
+
hud_console.progress_message(f"Building Docker image: {temp_tag}")
|
|
305
305
|
|
|
306
306
|
# Build the image (env vars are for runtime, not build time)
|
|
307
307
|
if not build_docker_image(env_dir, temp_tag, no_cache, verbose):
|
|
308
|
-
|
|
308
|
+
hud_console.error("Docker build failed")
|
|
309
309
|
raise typer.Exit(1)
|
|
310
310
|
|
|
311
|
-
|
|
311
|
+
hud_console.success(f"Built temporary image: {temp_tag}")
|
|
312
312
|
|
|
313
313
|
# Analyze the environment
|
|
314
|
-
|
|
314
|
+
hud_console.progress_message("Analyzing MCP environment...")
|
|
315
315
|
|
|
316
316
|
loop = asyncio.new_event_loop()
|
|
317
317
|
asyncio.set_event_loop(loop)
|
|
@@ -320,7 +320,7 @@ def build_environment(
|
|
|
320
320
|
finally:
|
|
321
321
|
loop.close()
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
hud_console.success(f"Analyzed environment: {analysis['toolCount']} tools found")
|
|
324
324
|
|
|
325
325
|
# Extract environment variables from Dockerfile
|
|
326
326
|
dockerfile_path = env_dir / "Dockerfile"
|
|
@@ -335,14 +335,18 @@ def build_environment(
|
|
|
335
335
|
missing_required = [e for e in required_env if e not in env_vars]
|
|
336
336
|
|
|
337
337
|
# Show what env vars were provided
|
|
338
|
-
|
|
338
|
+
hud_console.success(f"Using provided environment variables: {', '.join(env_vars.keys())}")
|
|
339
339
|
else:
|
|
340
340
|
missing_required = required_env[:]
|
|
341
341
|
|
|
342
342
|
# Warn about missing required variables
|
|
343
343
|
if missing_required:
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
hud_console.warning(
|
|
345
|
+
f"Missing required environment variables: {', '.join(missing_required)}"
|
|
346
|
+
)
|
|
347
|
+
hud_console.info(
|
|
348
|
+
"These can be added to the lock file after build or provided with -e flags"
|
|
349
|
+
)
|
|
346
350
|
|
|
347
351
|
# Check for existing version and increment
|
|
348
352
|
lock_path = env_dir / "hud.lock.yaml"
|
|
@@ -351,11 +355,11 @@ def build_environment(
|
|
|
351
355
|
if existing_version:
|
|
352
356
|
# Increment existing version
|
|
353
357
|
new_version = increment_version(existing_version)
|
|
354
|
-
|
|
358
|
+
hud_console.info(f"Incrementing version: {existing_version} → {new_version}")
|
|
355
359
|
else:
|
|
356
360
|
# Start with 0.1.0 for new environments
|
|
357
361
|
new_version = "0.1.0"
|
|
358
|
-
|
|
362
|
+
hud_console.info(f"Setting initial version: {new_version}")
|
|
359
363
|
|
|
360
364
|
# Create lock file content - minimal and useful
|
|
361
365
|
lock_content = {
|
|
@@ -406,7 +410,7 @@ def build_environment(
|
|
|
406
410
|
with open(lock_path, "w") as f:
|
|
407
411
|
yaml.dump(lock_content, f, default_flow_style=False, sort_keys=False)
|
|
408
412
|
|
|
409
|
-
|
|
413
|
+
hud_console.success("Created lock file: hud.lock.yaml")
|
|
410
414
|
|
|
411
415
|
# Calculate lock file hash
|
|
412
416
|
lock_content_str = yaml.dump(lock_content, default_flow_style=False, sort_keys=True)
|
|
@@ -414,7 +418,7 @@ def build_environment(
|
|
|
414
418
|
lock_size = len(lock_content_str)
|
|
415
419
|
|
|
416
420
|
# Rebuild with label containing lock file hash
|
|
417
|
-
|
|
421
|
+
hud_console.progress_message("Rebuilding with lock file metadata...")
|
|
418
422
|
|
|
419
423
|
# Build final image with label (uses cache from first build)
|
|
420
424
|
# Also tag with version
|
|
@@ -447,10 +451,10 @@ def build_environment(
|
|
|
447
451
|
)
|
|
448
452
|
|
|
449
453
|
if result.returncode != 0:
|
|
450
|
-
|
|
454
|
+
hud_console.error("Failed to rebuild with label")
|
|
451
455
|
raise typer.Exit(1)
|
|
452
456
|
|
|
453
|
-
|
|
457
|
+
hud_console.success("Built final image with lock file metadata")
|
|
454
458
|
|
|
455
459
|
# NOW get the image ID after the final build
|
|
456
460
|
image_id = get_docker_image_id(tag) # type: ignore
|
|
@@ -466,9 +470,9 @@ def build_environment(
|
|
|
466
470
|
with open(lock_path, "w") as f:
|
|
467
471
|
yaml.dump(lock_content, f, default_flow_style=False, sort_keys=False)
|
|
468
472
|
|
|
469
|
-
|
|
473
|
+
hud_console.success("Updated lock file with image ID")
|
|
470
474
|
else:
|
|
471
|
-
|
|
475
|
+
hud_console.warning("Could not retrieve image ID for lock file")
|
|
472
476
|
|
|
473
477
|
# Remove temp image after we're done
|
|
474
478
|
subprocess.run(["docker", "rmi", temp_tag], capture_output=True) # noqa: S603, S607
|
|
@@ -479,30 +483,30 @@ def build_environment(
|
|
|
479
483
|
save_to_registry(lock_content, lock_content.get("image", tag), verbose)
|
|
480
484
|
|
|
481
485
|
# Print summary
|
|
482
|
-
|
|
486
|
+
hud_console.section_title("Build Complete")
|
|
483
487
|
|
|
484
488
|
# Show the version tag as primary since that's what will be pushed
|
|
485
|
-
|
|
489
|
+
hud_console.status_item("Built image", version_tag, primary=True)
|
|
486
490
|
if tag:
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
+
hud_console.status_item("Also tagged", tag)
|
|
492
|
+
hud_console.status_item("Version", new_version)
|
|
493
|
+
hud_console.status_item("Lock file", "hud.lock.yaml")
|
|
494
|
+
hud_console.status_item("Tools found", str(analysis["toolCount"]))
|
|
491
495
|
|
|
492
496
|
# Show the digest info separately if we have it
|
|
493
497
|
if image_id:
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
498
|
+
hud_console.dim_info("\nImage digest", image_id)
|
|
499
|
+
|
|
500
|
+
hud_console.section_title("Next Steps")
|
|
501
|
+
hud_console.info("Test locally:")
|
|
502
|
+
hud_console.command_example("hud dev", "Hot-reload development")
|
|
503
|
+
hud_console.command_example(f"hud run {tag}", "Run the built image")
|
|
504
|
+
hud_console.info("")
|
|
505
|
+
hud_console.info("Publish to registry:")
|
|
506
|
+
hud_console.command_example("hud push", f"Push as {version_tag}")
|
|
507
|
+
hud_console.command_example("hud push --tag latest", "Push with custom tag")
|
|
508
|
+
hud_console.info("")
|
|
509
|
+
hud_console.info("The lock file can be used to reproduce this exact environment.")
|
|
506
510
|
|
|
507
511
|
|
|
508
512
|
def build_command(
|
hud/cli/debug.py
CHANGED
|
@@ -12,7 +12,7 @@ import time
|
|
|
12
12
|
from rich.console import Console
|
|
13
13
|
|
|
14
14
|
from hud.clients import MCPClient
|
|
15
|
-
from hud.utils.
|
|
15
|
+
from hud.utils.hud_console import HUDConsole
|
|
16
16
|
|
|
17
17
|
from .utils.logging import CaptureLogger, Colors, analyze_error_for_hints
|
|
18
18
|
|
|
@@ -31,15 +31,15 @@ async def debug_mcp_stdio(command: list[str], logger: CaptureLogger, max_phase:
|
|
|
31
31
|
Returns:
|
|
32
32
|
Number of phases completed (0-5)
|
|
33
33
|
"""
|
|
34
|
-
# Create
|
|
34
|
+
# Create hud_console instance for initial output (before logger takes over)
|
|
35
35
|
if logger.print_output:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
hud_console = HUDConsole()
|
|
37
|
+
hud_console.header("MCP Server Debugger", icon="🔍")
|
|
38
|
+
hud_console.dim_info("Command:", " ".join(command))
|
|
39
|
+
hud_console.dim_info("Time:", time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
40
40
|
|
|
41
41
|
# Explain color coding using Rich formatting
|
|
42
|
-
|
|
42
|
+
hud_console.info("\nColor Key:")
|
|
43
43
|
console.print(" [bold]■[/bold] Commands (bold)")
|
|
44
44
|
console.print(" [rgb(192,150,12)]■[/rgb(192,150,12)] STDIO (MCP protocol)")
|
|
45
45
|
console.print(" [dim]■[/dim] STDERR (server logs)")
|