hud-python 0.4.56__py3-none-any.whl → 0.4.58__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/cli/__init__.py +20 -7
- hud/cli/dev.py +135 -5
- hud/cli/eval.py +2 -2
- hud/cli/flows/dev.py +10 -19
- hud/cli/init.py +14 -18
- hud/cli/push.py +2 -2
- hud/cli/rl/__init__.py +1 -1
- hud/cli/rl/celebrate.py +1 -1
- hud/cli/rl/remote_runner.py +3 -3
- hud/cli/tests/test_convert.py +367 -0
- hud/cli/utils/version_check.py +7 -6
- hud/clients/base.py +29 -3
- hud/clients/fastmcp.py +3 -3
- hud/clients/mcp_use.py +2 -2
- hud/clients/tests/test_protocol.py +9 -3
- hud/otel/config.py +1 -1
- hud/otel/context.py +2 -2
- hud/server/server.py +306 -0
- hud/shared/hints.py +3 -3
- hud/telemetry/job.py +2 -2
- hud/tools/playwright.py +8 -1
- hud/types.py +1 -1
- hud/utils/tests/test_version.py +1 -1
- hud/version.py +1 -1
- {hud_python-0.4.56.dist-info → hud_python-0.4.58.dist-info}/METADATA +1 -1
- {hud_python-0.4.56.dist-info → hud_python-0.4.58.dist-info}/RECORD +29 -28
- {hud_python-0.4.56.dist-info → hud_python-0.4.58.dist-info}/WHEEL +0 -0
- {hud_python-0.4.56.dist-info → hud_python-0.4.58.dist-info}/entry_points.txt +0 -0
- {hud_python-0.4.56.dist-info → hud_python-0.4.58.dist-info}/licenses/LICENSE +0 -0
hud/cli/__init__.py
CHANGED
|
@@ -253,10 +253,23 @@ def debug(
|
|
|
253
253
|
else:
|
|
254
254
|
# Assume it's an image name
|
|
255
255
|
image = first_param
|
|
256
|
-
from .utils.docker import
|
|
256
|
+
from .utils.docker import create_docker_run_command
|
|
257
|
+
|
|
258
|
+
# For image mode, check if there's a .env file in current directory
|
|
259
|
+
# and use it if available (similar to hud dev behavior)
|
|
260
|
+
cwd = Path.cwd()
|
|
261
|
+
if (cwd / ".env").exists():
|
|
262
|
+
# Use create_docker_run_command to load .env from current directory
|
|
263
|
+
command = create_docker_run_command(
|
|
264
|
+
image,
|
|
265
|
+
docker_args=docker_args,
|
|
266
|
+
env_dir=cwd, # Load .env from current directory
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
# No .env file, use basic command without env loading
|
|
270
|
+
from .utils.docker import build_run_command
|
|
257
271
|
|
|
258
|
-
|
|
259
|
-
command = build_run_command(image, docker_args)
|
|
272
|
+
command = build_run_command(image, docker_args)
|
|
260
273
|
else:
|
|
261
274
|
console.print(
|
|
262
275
|
"[red]Error: Must specify a directory, Docker image, --config, or --cursor[/red]"
|
|
@@ -741,14 +754,14 @@ def remove(
|
|
|
741
754
|
|
|
742
755
|
@app.command()
|
|
743
756
|
def init(
|
|
744
|
-
name: str = typer.Argument(None, help="Environment name (default:
|
|
757
|
+
name: str = typer.Argument(None, help="Environment name (default: chosen preset name)"),
|
|
745
758
|
preset: str | None = typer.Option(
|
|
746
759
|
None,
|
|
747
760
|
"--preset",
|
|
748
761
|
"-p",
|
|
749
762
|
help="Preset to use: blank, deep-research, browser, rubrics. If omitted, you'll choose interactively.", # noqa: E501
|
|
750
763
|
),
|
|
751
|
-
directory: str = typer.Option(".", "--dir", "-d", help="
|
|
764
|
+
directory: str = typer.Option(".", "--dir", "-d", help="Parent directory for the environment"),
|
|
752
765
|
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing files"),
|
|
753
766
|
) -> None:
|
|
754
767
|
"""🚀 Initialize a new HUD environment with minimal boilerplate.
|
|
@@ -760,8 +773,8 @@ def init(
|
|
|
760
773
|
- Required setup/evaluate tools
|
|
761
774
|
|
|
762
775
|
Examples:
|
|
763
|
-
hud init #
|
|
764
|
-
hud init my-env # Create
|
|
776
|
+
hud init # Choose preset interactively, create ./preset-name/
|
|
777
|
+
hud init my-env # Create new directory ./my-env/
|
|
765
778
|
hud init my-env --dir /tmp # Create in /tmp/my-env/
|
|
766
779
|
"""
|
|
767
780
|
create_environment(name, directory, force, preset)
|
hud/cli/dev.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
+
import contextlib
|
|
6
7
|
import importlib
|
|
7
8
|
import importlib.util
|
|
8
9
|
import logging
|
|
@@ -13,6 +14,8 @@ import threading
|
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
17
|
+
import typer
|
|
18
|
+
|
|
16
19
|
from hud.utils.hud_console import HUDConsole
|
|
17
20
|
|
|
18
21
|
hud_console = HUDConsole()
|
|
@@ -26,6 +29,7 @@ def show_dev_server_info(
|
|
|
26
29
|
interactive: bool,
|
|
27
30
|
env_dir: Path | None = None,
|
|
28
31
|
new: bool = False,
|
|
32
|
+
docker_mode: bool = False,
|
|
29
33
|
) -> str:
|
|
30
34
|
"""Show consistent server info for both Python and Docker modes.
|
|
31
35
|
|
|
@@ -54,7 +58,15 @@ def show_dev_server_info(
|
|
|
54
58
|
if transport == "http":
|
|
55
59
|
hud_console.section_title("Quick Links")
|
|
56
60
|
hud_console.info(f"{hud_console.sym.ITEM} Docs: http://localhost:{port}/docs")
|
|
57
|
-
hud_console.info(f"{hud_console.sym.ITEM} Cursor:
|
|
61
|
+
hud_console.info(f"{hud_console.sym.ITEM} Cursor:")
|
|
62
|
+
# Display the Cursor link on its own line to prevent wrapping
|
|
63
|
+
hud_console.link(cursor_deeplink)
|
|
64
|
+
|
|
65
|
+
# Show eval endpoint if in Docker mode
|
|
66
|
+
if docker_mode:
|
|
67
|
+
hud_console.info(
|
|
68
|
+
f"{hud_console.sym.ITEM} Eval API: http://localhost:{port}/eval (POST)"
|
|
69
|
+
)
|
|
58
70
|
|
|
59
71
|
# Check for VNC (browser environment)
|
|
60
72
|
if env_dir and (env_dir / "environment" / "server.py").exists():
|
|
@@ -237,7 +249,7 @@ async def run_mcp_module(
|
|
|
237
249
|
|
|
238
250
|
from hud.cli.flows.dev import create_dynamic_trace
|
|
239
251
|
|
|
240
|
-
live_trace_url = await create_dynamic_trace(
|
|
252
|
+
_, live_trace_url = await create_dynamic_trace(
|
|
241
253
|
mcp_config=local_mcp_config,
|
|
242
254
|
build_status=False,
|
|
243
255
|
environment_name=mcp_server.name or "mcp-server",
|
|
@@ -510,6 +522,9 @@ def run_docker_dev_server(
|
|
|
510
522
|
new: bool = False,
|
|
511
523
|
) -> None:
|
|
512
524
|
"""Run MCP server in Docker with volume mounts, expose via local HTTP proxy."""
|
|
525
|
+
import atexit
|
|
526
|
+
import signal
|
|
527
|
+
|
|
513
528
|
import typer
|
|
514
529
|
import yaml
|
|
515
530
|
|
|
@@ -522,6 +537,69 @@ def run_docker_dev_server(
|
|
|
522
537
|
|
|
523
538
|
cwd = Path.cwd()
|
|
524
539
|
|
|
540
|
+
# Container name will be set later and used for cleanup
|
|
541
|
+
container_name: str | None = None
|
|
542
|
+
cleanup_done = False
|
|
543
|
+
|
|
544
|
+
def cleanup_container() -> None:
|
|
545
|
+
"""Clean up Docker container on exit."""
|
|
546
|
+
nonlocal cleanup_done
|
|
547
|
+
if cleanup_done or not container_name:
|
|
548
|
+
return
|
|
549
|
+
|
|
550
|
+
cleanup_done = True
|
|
551
|
+
hud_console.debug(f"Cleaning up container: {container_name}")
|
|
552
|
+
|
|
553
|
+
# Check if container is still running
|
|
554
|
+
try:
|
|
555
|
+
result = subprocess.run( # noqa: S603
|
|
556
|
+
["docker", "ps", "-q", "-f", f"name={container_name}"], # noqa: S607
|
|
557
|
+
stdout=subprocess.PIPE,
|
|
558
|
+
stderr=subprocess.DEVNULL,
|
|
559
|
+
text=True,
|
|
560
|
+
timeout=5,
|
|
561
|
+
)
|
|
562
|
+
if not result.stdout.strip():
|
|
563
|
+
# Container is not running, just try to remove it
|
|
564
|
+
subprocess.run( # noqa: S603
|
|
565
|
+
["docker", "rm", "-f", container_name], # noqa: S607
|
|
566
|
+
stdout=subprocess.DEVNULL,
|
|
567
|
+
stderr=subprocess.DEVNULL,
|
|
568
|
+
timeout=5,
|
|
569
|
+
)
|
|
570
|
+
return
|
|
571
|
+
except Exception: # noqa: S110
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
try:
|
|
575
|
+
# First try to stop gracefully
|
|
576
|
+
subprocess.run( # noqa: S603
|
|
577
|
+
["docker", "stop", container_name], # noqa: S607
|
|
578
|
+
stdout=subprocess.DEVNULL,
|
|
579
|
+
stderr=subprocess.DEVNULL,
|
|
580
|
+
timeout=10,
|
|
581
|
+
)
|
|
582
|
+
hud_console.debug(f"Container {container_name} stopped successfully")
|
|
583
|
+
except subprocess.TimeoutExpired:
|
|
584
|
+
# Force kill if stop times out
|
|
585
|
+
hud_console.debug(f"Container {container_name} stop timeout, forcing kill")
|
|
586
|
+
with contextlib.suppress(Exception):
|
|
587
|
+
subprocess.run( # noqa: S603
|
|
588
|
+
["docker", "kill", container_name], # noqa: S607
|
|
589
|
+
stdout=subprocess.DEVNULL,
|
|
590
|
+
stderr=subprocess.DEVNULL,
|
|
591
|
+
timeout=5,
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
# Set up signal handlers for cleanup
|
|
595
|
+
def signal_handler(signum: int, frame: Any) -> None:
|
|
596
|
+
cleanup_container()
|
|
597
|
+
sys.exit(0)
|
|
598
|
+
|
|
599
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
|
600
|
+
if sys.platform != "win32":
|
|
601
|
+
signal.signal(signal.SIGHUP, signal_handler)
|
|
602
|
+
|
|
525
603
|
# Find environment directory (current or parent with hud.lock.yaml)
|
|
526
604
|
env_dir = cwd
|
|
527
605
|
lock_path = env_dir / "hud.lock.yaml"
|
|
@@ -562,10 +640,14 @@ def run_docker_dev_server(
|
|
|
562
640
|
base_name = image_name.replace(":", "-").replace("/", "-")
|
|
563
641
|
container_name = f"{base_name}-dev-{pid}"
|
|
564
642
|
|
|
643
|
+
# Register cleanup function with atexit
|
|
644
|
+
atexit.register(cleanup_container)
|
|
645
|
+
|
|
565
646
|
# Build docker run command with volume mounts and folder-mode envs
|
|
566
647
|
from .utils.docker import create_docker_run_command
|
|
567
648
|
|
|
568
649
|
base_args = [
|
|
650
|
+
"--rm", # Automatically remove container when it stops
|
|
569
651
|
"--name",
|
|
570
652
|
container_name,
|
|
571
653
|
"-v",
|
|
@@ -608,7 +690,7 @@ def run_docker_dev_server(
|
|
|
608
690
|
"headers": {},
|
|
609
691
|
}
|
|
610
692
|
}
|
|
611
|
-
live_trace_url = _asy.run(
|
|
693
|
+
_, live_trace_url = _asy.run(
|
|
612
694
|
create_dynamic_trace(
|
|
613
695
|
mcp_config=local_mcp_config,
|
|
614
696
|
build_status=True,
|
|
@@ -643,6 +725,7 @@ def run_docker_dev_server(
|
|
|
643
725
|
interactive=interactive,
|
|
644
726
|
env_dir=env_dir,
|
|
645
727
|
new=new,
|
|
728
|
+
docker_mode=True,
|
|
646
729
|
)
|
|
647
730
|
hud_console.dim_info(
|
|
648
731
|
"",
|
|
@@ -661,13 +744,38 @@ def run_docker_dev_server(
|
|
|
661
744
|
# Create and run proxy with HUD helpers
|
|
662
745
|
async def run_proxy() -> None:
|
|
663
746
|
from fastmcp import FastMCP
|
|
747
|
+
from fastmcp.server.proxy import ProxyClient
|
|
748
|
+
|
|
749
|
+
# Create ProxyClient without custom log handler since we capture Docker logs directly
|
|
750
|
+
proxy_client = ProxyClient(mcp_config, name="HUD Docker Dev Proxy")
|
|
751
|
+
|
|
752
|
+
# Extract container name from docker args and store for logs endpoint
|
|
753
|
+
docker_cmd = mcp_config["docker"]["args"]
|
|
754
|
+
container_name = None
|
|
755
|
+
for i, arg in enumerate(docker_cmd):
|
|
756
|
+
if arg == "--name" and i + 1 < len(docker_cmd):
|
|
757
|
+
container_name = docker_cmd[i + 1]
|
|
758
|
+
break
|
|
664
759
|
|
|
665
|
-
|
|
666
|
-
|
|
760
|
+
if container_name:
|
|
761
|
+
# Store container name for logs endpoint to use
|
|
762
|
+
os.environ["_HUD_DEV_DOCKER_CONTAINER"] = container_name
|
|
763
|
+
hud_console.debug(f"Docker container: {container_name}")
|
|
764
|
+
|
|
765
|
+
# Store the docker mcp_config for the eval endpoint
|
|
766
|
+
import json
|
|
767
|
+
|
|
768
|
+
os.environ["_HUD_DEV_DOCKER_MCP_CONFIG"] = json.dumps(mcp_config)
|
|
769
|
+
|
|
770
|
+
# Create FastMCP proxy using the ProxyClient
|
|
771
|
+
fastmcp_proxy = FastMCP.as_proxy(proxy_client)
|
|
667
772
|
|
|
668
773
|
# Wrap in MCPServer to get /docs and REST wrappers
|
|
669
774
|
proxy = MCPServer(name="HUD Docker Dev Proxy")
|
|
670
775
|
|
|
776
|
+
# Enable logs endpoint on HTTP server
|
|
777
|
+
os.environ["_HUD_DEV_LOGS_PROVIDER"] = "enabled"
|
|
778
|
+
|
|
671
779
|
# Import all tools from the FastMCP proxy
|
|
672
780
|
await proxy.import_server(fastmcp_proxy)
|
|
673
781
|
|
|
@@ -693,7 +801,15 @@ def run_docker_dev_server(
|
|
|
693
801
|
asyncio.run(run_proxy())
|
|
694
802
|
except KeyboardInterrupt:
|
|
695
803
|
hud_console.info("\n\nStopping...")
|
|
804
|
+
cleanup_container()
|
|
696
805
|
raise typer.Exit(0) from None
|
|
806
|
+
except Exception:
|
|
807
|
+
# Ensure cleanup happens on any exception
|
|
808
|
+
cleanup_container()
|
|
809
|
+
raise
|
|
810
|
+
finally:
|
|
811
|
+
# Final cleanup attempt
|
|
812
|
+
cleanup_container()
|
|
697
813
|
|
|
698
814
|
|
|
699
815
|
def run_mcp_dev_server(
|
|
@@ -712,6 +828,20 @@ def run_mcp_dev_server(
|
|
|
712
828
|
docker_args = docker_args or []
|
|
713
829
|
cwd = Path.cwd()
|
|
714
830
|
|
|
831
|
+
# Find an available port if not using stdio transport
|
|
832
|
+
if not stdio:
|
|
833
|
+
from hud.cli.utils.logging import find_free_port
|
|
834
|
+
|
|
835
|
+
actual_port = find_free_port(port)
|
|
836
|
+
if actual_port is None:
|
|
837
|
+
hud_console.error(f"No available ports found starting from {port}")
|
|
838
|
+
raise typer.Exit(1)
|
|
839
|
+
|
|
840
|
+
if actual_port != port:
|
|
841
|
+
hud_console.info(f"Port {port} is in use, using port {actual_port} instead")
|
|
842
|
+
|
|
843
|
+
port = actual_port
|
|
844
|
+
|
|
715
845
|
# Auto-detect Docker mode if Dockerfile present and no module specified
|
|
716
846
|
if not docker and module is None and should_use_docker_mode(cwd):
|
|
717
847
|
hud_console.note("Detected Dockerfile - using Docker mode with volume mounts")
|
hud/cli/eval.py
CHANGED
|
@@ -53,7 +53,7 @@ def get_available_models() -> list[dict[str, str | None]]:
|
|
|
53
53
|
try:
|
|
54
54
|
from hud.cli.rl import rl_api
|
|
55
55
|
|
|
56
|
-
hud_console.info("Fetching your models from https://hud.
|
|
56
|
+
hud_console.info("Fetching your models from https://hud.ai/models")
|
|
57
57
|
models = rl_api.list_models()
|
|
58
58
|
|
|
59
59
|
# Filter for ready models only and sort by recency
|
|
@@ -771,7 +771,7 @@ def eval_command(
|
|
|
771
771
|
# Check for HUD_API_KEY if using HUD services
|
|
772
772
|
if not settings.api_key:
|
|
773
773
|
hud_console.warning("HUD_API_KEY not set. Some features may be limited.")
|
|
774
|
-
hud_console.info("Get your API key at: https://hud.
|
|
774
|
+
hud_console.info("Get your API key at: https://hud.ai")
|
|
775
775
|
hud_console.info("Set it in your environment or run: hud set HUD_API_KEY=your-key-here")
|
|
776
776
|
|
|
777
777
|
# Parse allowed tools
|
hud/cli/flows/dev.py
CHANGED
|
@@ -18,7 +18,7 @@ async def create_dynamic_trace(
|
|
|
18
18
|
mcp_config: dict[str, dict[str, Any]],
|
|
19
19
|
build_status: bool,
|
|
20
20
|
environment_name: str,
|
|
21
|
-
) -> str | None:
|
|
21
|
+
) -> tuple[str | None, str | None]:
|
|
22
22
|
"""
|
|
23
23
|
Create a dynamic trace for HUD dev sessions when running in HTTP mode.
|
|
24
24
|
|
|
@@ -43,27 +43,16 @@ async def create_dynamic_trace(
|
|
|
43
43
|
api_key = settings.api_key
|
|
44
44
|
if not api_key:
|
|
45
45
|
logger.warning("Skipping dynamic trace creation; missing HUD_API_KEY")
|
|
46
|
-
return None
|
|
46
|
+
return None, None
|
|
47
47
|
|
|
48
48
|
try:
|
|
49
49
|
resp = await make_request("POST", url=url, json=payload, api_key=api_key)
|
|
50
|
-
# New API returns an id; construct the URL as https://hud.
|
|
51
|
-
trace_id =
|
|
52
|
-
if isinstance(resp, dict):
|
|
53
|
-
trace_id = resp.get("id")
|
|
54
|
-
if trace_id is None:
|
|
55
|
-
data = resp.get("data", {}) or {}
|
|
56
|
-
if isinstance(data, dict):
|
|
57
|
-
trace_id = data.get("id")
|
|
58
|
-
# Backcompat: if url is provided directly
|
|
59
|
-
if not trace_id:
|
|
60
|
-
direct_url = resp.get("url") or (resp.get("data", {}) or {}).get("url")
|
|
61
|
-
if isinstance(direct_url, str) and direct_url:
|
|
62
|
-
return direct_url
|
|
50
|
+
# New API returns an id; construct the URL as https://hud.ai/trace/{id}
|
|
51
|
+
trace_id = resp.get("id")
|
|
63
52
|
|
|
64
53
|
if isinstance(trace_id, str) and trace_id:
|
|
65
|
-
return f"https://hud.
|
|
66
|
-
return None
|
|
54
|
+
return trace_id, f"https://hud.ai/trace/{trace_id}"
|
|
55
|
+
return None, None
|
|
67
56
|
except Exception as e:
|
|
68
57
|
# Do not interrupt dev flow
|
|
69
58
|
try:
|
|
@@ -71,7 +60,7 @@ async def create_dynamic_trace(
|
|
|
71
60
|
logger.warning("Failed to create dynamic dev trace: %s | payload=%s", e, preview)
|
|
72
61
|
except Exception:
|
|
73
62
|
logger.warning("Failed to create dynamic dev trace: %s", e)
|
|
74
|
-
return None
|
|
63
|
+
return None, None
|
|
75
64
|
|
|
76
65
|
|
|
77
66
|
def show_dev_ui(
|
|
@@ -125,7 +114,9 @@ def show_dev_ui(
|
|
|
125
114
|
label = "Base image" if is_docker else "Server"
|
|
126
115
|
hud_console.info("")
|
|
127
116
|
hud_console.info(f"{hud_console.sym.ITEM} {label}: {server_name}")
|
|
128
|
-
hud_console.info(f"{hud_console.sym.ITEM} Cursor:
|
|
117
|
+
hud_console.info(f"{hud_console.sym.ITEM} Cursor:")
|
|
118
|
+
# Display the Cursor link on its own line to prevent wrapping
|
|
119
|
+
hud_console.link(cursor_deeplink)
|
|
129
120
|
hud_console.info("")
|
|
130
121
|
hud_console.info(f"{hud_console.sym.SUCCESS} Hot-reload enabled")
|
|
131
122
|
if is_docker:
|
hud/cli/init.py
CHANGED
|
@@ -182,17 +182,17 @@ def create_environment(
|
|
|
182
182
|
|
|
183
183
|
hud_console = HUDConsole()
|
|
184
184
|
|
|
185
|
-
# Determine environment name/target directory
|
|
186
|
-
if name is None:
|
|
187
|
-
current_dir = Path.cwd()
|
|
188
|
-
name = current_dir.name
|
|
189
|
-
target_dir = current_dir
|
|
190
|
-
hud_console.info(f"Using current directory name: {name}")
|
|
191
|
-
else:
|
|
192
|
-
target_dir = Path(directory) / name
|
|
193
|
-
|
|
194
185
|
# Choose preset
|
|
195
186
|
preset_normalized = (preset or "").strip().lower() if preset else _prompt_for_preset()
|
|
187
|
+
|
|
188
|
+
# If no name is provided, use the preset name as the environment name
|
|
189
|
+
if name is None:
|
|
190
|
+
name = preset_normalized
|
|
191
|
+
hud_console.info(f"Using preset name as environment name: {name}")
|
|
192
|
+
|
|
193
|
+
# Always create a new directory based on the name
|
|
194
|
+
target_dir = Path.cwd() / name if directory == "." else Path(directory) / name
|
|
195
|
+
|
|
196
196
|
if preset_normalized not in PRESET_MAP:
|
|
197
197
|
hud_console.warning(
|
|
198
198
|
f"Unknown preset '{preset_normalized}', defaulting to 'blank' "
|
|
@@ -263,14 +263,10 @@ def create_environment(
|
|
|
263
263
|
hud_console.status_item(entry, "added")
|
|
264
264
|
|
|
265
265
|
hud_console.section_title("Next steps")
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
hud_console.command_example(f"cd {target_dir}")
|
|
272
|
-
hud_console.info("\n2. Start development server (with MCP inspector):")
|
|
273
|
-
hud_console.command_example("hud dev --inspector")
|
|
274
|
-
|
|
266
|
+
# Since we now almost always create a new directory, show cd command
|
|
267
|
+
hud_console.info("1. Enter the directory:")
|
|
268
|
+
hud_console.command_example(f"cd {target_dir.name}")
|
|
269
|
+
hud_console.info("\n2. Start development server (with MCP inspector):")
|
|
270
|
+
hud_console.command_example("hud dev --inspector")
|
|
275
271
|
hud_console.info("\n3. Review the README in this preset for specific instructions.")
|
|
276
272
|
hud_console.info("\n4. Customize as needed.")
|
hud/cli/push.py
CHANGED
|
@@ -152,7 +152,7 @@ def push_environment(
|
|
|
152
152
|
hud_console.error("No HUD API key found")
|
|
153
153
|
hud_console.warning("A HUD API key is required to push environments.")
|
|
154
154
|
hud_console.info("\nTo get started:")
|
|
155
|
-
hud_console.info("1. Get your API key at: https://hud.
|
|
155
|
+
hud_console.info("1. Get your API key at: https://hud.ai/settings")
|
|
156
156
|
hud_console.info("Set it in your environment or run: hud set HUD_API_KEY=your-key-here")
|
|
157
157
|
hud_console.command_example("hud push", "Try again")
|
|
158
158
|
hud_console.info("")
|
|
@@ -440,7 +440,7 @@ def push_environment(
|
|
|
440
440
|
elif response.status_code == 401:
|
|
441
441
|
hud_console.error("Authentication failed")
|
|
442
442
|
hud_console.info("Check your HUD_API_KEY is valid")
|
|
443
|
-
hud_console.info("Get a new key at: https://hud.
|
|
443
|
+
hud_console.info("Get a new key at: https://hud.ai/settings")
|
|
444
444
|
hud_console.info("Set it in your environment or run: hud set HUD_API_KEY=your-key-here")
|
|
445
445
|
elif response.status_code == 403:
|
|
446
446
|
hud_console.error("Permission denied")
|
hud/cli/rl/__init__.py
CHANGED
|
@@ -25,7 +25,7 @@ def rl_command(
|
|
|
25
25
|
),
|
|
26
26
|
model: str | None = typer.Argument(
|
|
27
27
|
None,
|
|
28
|
-
help="Model to train from https://hud.
|
|
28
|
+
help="Model to train from https://hud.ai/models (default: interactive selection)",
|
|
29
29
|
),
|
|
30
30
|
config_file: Path | None = typer.Option( # noqa: B008
|
|
31
31
|
None,
|
hud/cli/rl/celebrate.py
CHANGED
|
@@ -133,7 +133,7 @@ def show_confetti(console: Console, seconds: float = 2.5) -> None:
|
|
|
133
133
|
"""
|
|
134
134
|
# Show celebratory message first
|
|
135
135
|
console.print(
|
|
136
|
-
"[bold green]🎉 Starting training! See your model on https://hud.
|
|
136
|
+
"[bold green]🎉 Starting training! See your model on https://hud.ai/models[/bold green]"
|
|
137
137
|
)
|
|
138
138
|
time.sleep(0.3) # Brief pause to see the message
|
|
139
139
|
|
hud/cli/rl/remote_runner.py
CHANGED
|
@@ -55,7 +55,7 @@ def ensure_vllm_deployed(
|
|
|
55
55
|
hud_console.info("Waiting for vLLM server to be ready...")
|
|
56
56
|
start_time = time.time()
|
|
57
57
|
with hud_console.progress() as progress:
|
|
58
|
-
progress.update("Checking deployment status (see live status on https://hud.
|
|
58
|
+
progress.update("Checking deployment status (see live status on https://hud.ai/models)")
|
|
59
59
|
while True:
|
|
60
60
|
if time.time() - start_time > timeout:
|
|
61
61
|
hud_console.error("Timeout waiting for vLLM deployment")
|
|
@@ -139,7 +139,7 @@ def run_remote_training(
|
|
|
139
139
|
hud_console.section_title("Model Selection")
|
|
140
140
|
|
|
141
141
|
# Fetch existing models
|
|
142
|
-
hud_console.info("Fetching your models from https://hud.
|
|
142
|
+
hud_console.info("Fetching your models from https://hud.ai/models")
|
|
143
143
|
|
|
144
144
|
try:
|
|
145
145
|
models = rl_api.list_models()
|
|
@@ -312,7 +312,7 @@ def run_remote_training(
|
|
|
312
312
|
# gpu_table.add_column("Price/hr", style="yellow")
|
|
313
313
|
|
|
314
314
|
# for gpu, info in GPU_PRICING.items():
|
|
315
|
-
# gpu_table.add_row(gpu, info["memory"], "see pricing on hud.
|
|
315
|
+
# gpu_table.add_row(gpu, info["memory"], "see pricing on hud.ai")
|
|
316
316
|
|
|
317
317
|
# console.print(gpu_table)
|
|
318
318
|
|