hud-python 0.4.30__tar.gz → 0.4.31__tar.gz
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_python-0.4.30 → hud_python-0.4.31}/PKG-INFO +26 -27
- {hud_python-0.4.30 → hud_python-0.4.31}/README.md +20 -7
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/openai_chat_generic.py +1 -1
- hud_python-0.4.31/hud/cli/flows/tasks.py +185 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/init.py +2 -2
- hud_python-0.4.31/hud/cli/rl/__init__.py +165 -0
- hud_python-0.4.30/hud/cli/rl/__init__.py → hud_python-0.4.31/hud/cli/rl/local_runner.py +188 -204
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/remote_runner.py +11 -1
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/docker.py +94 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/train.py +3 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/vllm_adapter.py +32 -14
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_version.py +1 -1
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/version.py +1 -1
- {hud_python-0.4.30 → hud_python-0.4.31}/pyproject.toml +9 -9
- hud_python-0.4.30/hud/cli/flows/tasks.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/.gitignore +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/LICENSE +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/apps/2048/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/apps/2048/backend/pyproject.toml +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/apps/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/apps/todo/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/apps/todo/backend/pyproject.toml +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/browser/pyproject.toml +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/remote_browser/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/remote_browser/pyproject.toml +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/remote_browser/src/hud_controller/providers/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/text_2048/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/environments/text_2048/pyproject.toml +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/examples/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/__main__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/claude.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/grounded_openai.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/langchain.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/misc/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/misc/response_agent.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/openai.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/test_base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/test_claude.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/test_client.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/test_grounded_openai_agent.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/agents/tests/test_openai.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/__main__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/analyze.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/build.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/clone.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/debug.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/dev.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/eval.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/flows/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/get.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/list_func.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/pull.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/push.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/remove.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/config.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/display.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/gpu.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/gpu_utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/presets.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/rl_api.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/rl/vllm.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_analyze.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_analyze_metadata.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_build.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_cli_init.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_cli_main.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_clone.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_cursor.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_debug.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_list_func.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_main_module.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_mcp_server.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_pull.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_push.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_registry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/tests/test_utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/cursor.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/environment.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/interactive.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/logging.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/metadata.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/registry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/remote_runner.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/runner.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/server.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/cli/utils/tasks.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/fastmcp.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/mcp_use.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/tests/test_client_integration.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/tests/test_fastmcp.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/tests/test_mcp_use_retry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/tests/test_protocol.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/utils/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/utils/mcp_use_retry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/utils/retry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/clients/utils/retry_transport.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/datasets/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/datasets/parallel.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/datasets/runner.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/datasets/utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/misc/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/misc/claude_plays_pokemon.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/native/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/native/comparator.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/native/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/native/tests/test_comparator.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/native/tests/test_native_init.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/collector.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/config.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/context.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/exporters.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/instrumentation.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/processors.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/otel/tests/test_processors.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/py.typed +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/README.md +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/actor.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/buffer.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/chat_template.jinja +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/config.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/distributed.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/learner.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/tests/test_learner.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/types.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/utils/start_vllm_server.sh +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/rl/utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/context.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/helper/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/low_level.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/server.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/server/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/settings.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/exceptions.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/hints.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/requests.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/tests/test_exceptions.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/shared/tests/test_requests.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/instrument.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/job.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/replay.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/tests/test_replay.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/tests/test_trace.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/telemetry/trace.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/bash.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/computer/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/computer/anthropic.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/computer/hud.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/computer/openai.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/computer/settings.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/edit.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/pyautogui.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/tests/test_base_executor.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/tests/test_pyautogui_executor.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/executors/xdo.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/config.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/grounded_tool.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/grounder.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/grounding/tests/test_grounded_tool.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/playwright.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/response.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/submit.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_base.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_bash.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_bash_extended.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_computer.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_computer_actions.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_edit.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_init.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_playwright_tool.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_response.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_tools.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_tools_init.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/tests/test_utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/types.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/tools/utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/types.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/agent_factories.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/async_utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/group_eval.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/hud_console.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/mcp.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/pretty_errors.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/progress.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tasks.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/telemetry.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/__init__.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_async_utils.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_init.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_mcp.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_progress.py +0 -0
- {hud_python-0.4.30 → hud_python-0.4.31}/hud/utils/tests/test_telemetry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hud-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.31
|
|
4
4
|
Summary: SDK for the HUD platform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hud-evals/hud-python
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/hud-evals/hud-python/issues
|
|
@@ -35,15 +35,20 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.12
|
|
36
36
|
Classifier: Programming Language :: Python :: 3.13
|
|
37
37
|
Requires-Python: <3.13,>=3.11
|
|
38
|
+
Requires-Dist: anthropic
|
|
39
|
+
Requires-Dist: datasets>=2.14.0
|
|
38
40
|
Requires-Dist: httpx<1,>=0.23.0
|
|
39
41
|
Requires-Dist: hud-fastmcp-python-sdk>=0.1.2
|
|
40
42
|
Requires-Dist: hud-mcp-python-sdk>=3.13.2
|
|
41
43
|
Requires-Dist: hud-mcp-use-python-sdk>=2.3.16
|
|
44
|
+
Requires-Dist: numpy>=1.24.0
|
|
45
|
+
Requires-Dist: openai
|
|
42
46
|
Requires-Dist: opentelemetry-api>=1.34.1
|
|
43
47
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.34.1
|
|
44
48
|
Requires-Dist: opentelemetry-instrumentation-mcp==0.47.0
|
|
45
49
|
Requires-Dist: opentelemetry-sdk>=1.34.1
|
|
46
50
|
Requires-Dist: pathspec>=0.12.1
|
|
51
|
+
Requires-Dist: pillow>=11.1.0
|
|
47
52
|
Requires-Dist: prompt-toolkit==3.0.51
|
|
48
53
|
Requires-Dist: pydantic-settings<3,>=2
|
|
49
54
|
Requires-Dist: pydantic<3,>=2
|
|
@@ -54,8 +59,6 @@ Requires-Dist: typer>=0.9.0
|
|
|
54
59
|
Requires-Dist: watchfiles>=0.21.0
|
|
55
60
|
Requires-Dist: wrapt>=1.14.0
|
|
56
61
|
Provides-Extra: agent
|
|
57
|
-
Requires-Dist: anthropic; extra == 'agent'
|
|
58
|
-
Requires-Dist: datasets>=2.14.0; extra == 'agent'
|
|
59
62
|
Requires-Dist: dotenv>=0.9.9; extra == 'agent'
|
|
60
63
|
Requires-Dist: ipykernel; extra == 'agent'
|
|
61
64
|
Requires-Dist: ipython<9; extra == 'agent'
|
|
@@ -64,12 +67,7 @@ Requires-Dist: jupyter-core; extra == 'agent'
|
|
|
64
67
|
Requires-Dist: langchain; extra == 'agent'
|
|
65
68
|
Requires-Dist: langchain-anthropic; extra == 'agent'
|
|
66
69
|
Requires-Dist: langchain-openai; extra == 'agent'
|
|
67
|
-
Requires-Dist: numpy>=1.24.0; extra == 'agent'
|
|
68
|
-
Requires-Dist: openai; extra == 'agent'
|
|
69
|
-
Requires-Dist: pillow>=11.1.0; extra == 'agent'
|
|
70
70
|
Provides-Extra: agents
|
|
71
|
-
Requires-Dist: anthropic; extra == 'agents'
|
|
72
|
-
Requires-Dist: datasets>=2.14.0; extra == 'agents'
|
|
73
71
|
Requires-Dist: dotenv>=0.9.9; extra == 'agents'
|
|
74
72
|
Requires-Dist: ipykernel; extra == 'agents'
|
|
75
73
|
Requires-Dist: ipython<9; extra == 'agents'
|
|
@@ -78,13 +76,8 @@ Requires-Dist: jupyter-core; extra == 'agents'
|
|
|
78
76
|
Requires-Dist: langchain; extra == 'agents'
|
|
79
77
|
Requires-Dist: langchain-anthropic; extra == 'agents'
|
|
80
78
|
Requires-Dist: langchain-openai; extra == 'agents'
|
|
81
|
-
Requires-Dist: numpy>=1.24.0; extra == 'agents'
|
|
82
|
-
Requires-Dist: openai; extra == 'agents'
|
|
83
|
-
Requires-Dist: pillow>=11.1.0; extra == 'agents'
|
|
84
79
|
Provides-Extra: dev
|
|
85
80
|
Requires-Dist: aiodocker>=0.24.0; extra == 'dev'
|
|
86
|
-
Requires-Dist: anthropic; extra == 'dev'
|
|
87
|
-
Requires-Dist: datasets>=2.14.0; extra == 'dev'
|
|
88
81
|
Requires-Dist: dotenv>=0.9.9; extra == 'dev'
|
|
89
82
|
Requires-Dist: inspect-ai>=0.3.80; extra == 'dev'
|
|
90
83
|
Requires-Dist: ipykernel; extra == 'dev'
|
|
@@ -94,8 +87,6 @@ Requires-Dist: jupyter-core; extra == 'dev'
|
|
|
94
87
|
Requires-Dist: langchain; extra == 'dev'
|
|
95
88
|
Requires-Dist: langchain-anthropic; extra == 'dev'
|
|
96
89
|
Requires-Dist: langchain-openai; extra == 'dev'
|
|
97
|
-
Requires-Dist: numpy>=1.24.0; extra == 'dev'
|
|
98
|
-
Requires-Dist: openai; extra == 'dev'
|
|
99
90
|
Requires-Dist: pillow>=11.1.0; extra == 'dev'
|
|
100
91
|
Requires-Dist: playwright; extra == 'dev'
|
|
101
92
|
Requires-Dist: pyautogui>=0.9.54; extra == 'dev'
|
|
@@ -108,9 +99,7 @@ Requires-Dist: ruff>=0.11.8; extra == 'dev'
|
|
|
108
99
|
Requires-Dist: setuptools; extra == 'dev'
|
|
109
100
|
Requires-Dist: textdistance<5,>=4.5.0; extra == 'dev'
|
|
110
101
|
Provides-Extra: rl
|
|
111
|
-
Requires-Dist: anthropic; extra == 'rl'
|
|
112
102
|
Requires-Dist: bitsandbytes>=0.41.0; (sys_platform == 'linux') and extra == 'rl'
|
|
113
|
-
Requires-Dist: datasets>=2.14.0; extra == 'rl'
|
|
114
103
|
Requires-Dist: dotenv>=0.9.9; extra == 'rl'
|
|
115
104
|
Requires-Dist: ipykernel; extra == 'rl'
|
|
116
105
|
Requires-Dist: ipython<9; extra == 'rl'
|
|
@@ -120,10 +109,7 @@ Requires-Dist: langchain; extra == 'rl'
|
|
|
120
109
|
Requires-Dist: langchain-anthropic; extra == 'rl'
|
|
121
110
|
Requires-Dist: langchain-openai; extra == 'rl'
|
|
122
111
|
Requires-Dist: liger-kernel>=0.5.0; (sys_platform == 'linux') and extra == 'rl'
|
|
123
|
-
Requires-Dist: numpy>=1.24.0; extra == 'rl'
|
|
124
|
-
Requires-Dist: openai; extra == 'rl'
|
|
125
112
|
Requires-Dist: peft>=0.17.1; extra == 'rl'
|
|
126
|
-
Requires-Dist: pillow>=11.1.0; extra == 'rl'
|
|
127
113
|
Requires-Dist: vllm==0.10.1.1; extra == 'rl'
|
|
128
114
|
Description-Content-Type: text/markdown
|
|
129
115
|
|
|
@@ -239,21 +225,34 @@ The above example let's the agent play 2048 ([See replay](https://app.hud.so/tra
|
|
|
239
225
|
|
|
240
226
|
## Reinforcement Learning with GRPO
|
|
241
227
|
|
|
242
|
-
This is a Qwen
|
|
228
|
+
This is a Qwen‑2.5‑VL‑3B agent training a policy on the 2048-basic browser environment:
|
|
243
229
|
|
|
244
230
|

|
|
245
231
|
|
|
246
|
-
|
|
232
|
+
Train with the new interactive `hud rl` flow:
|
|
247
233
|
|
|
248
234
|
```bash
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
235
|
+
# Install CLI with RL extras
|
|
236
|
+
uv tool install "hud-python[rl]"
|
|
237
|
+
|
|
238
|
+
# Option A: Run directly from a HuggingFace dataset
|
|
239
|
+
hud rl hud-evals/basic-2048
|
|
240
|
+
|
|
241
|
+
# Option B: Download first, modify, then train
|
|
242
|
+
hud get hud-evals/basic-2048
|
|
243
|
+
hud rl basic-2048.jsonl
|
|
244
|
+
|
|
245
|
+
# Optional: baseline evaluation
|
|
246
|
+
hud eval basic-2048.jsonl
|
|
252
247
|
```
|
|
253
248
|
|
|
254
|
-
|
|
249
|
+
Supports multi‑turn RL for both:
|
|
250
|
+
- Language‑only models (e.g., `Qwen/Qwen2.5-7B-Instruct`)
|
|
251
|
+
- Vision‑Language models (e.g., `Qwen/Qwen2.5-VL-3B-Instruct`)
|
|
252
|
+
|
|
253
|
+
By default, `hud rl` provisions a persistant server and trainer in the cloud, streams telemetry to `app.hud.so`, and lets you monitor/manage models at `app.hud.so/models`. Use `--local` to run entirely on your machines (typically 2+ GPUs: one for vLLM, the rest for training).
|
|
255
254
|
|
|
256
|
-
|
|
255
|
+
Any HUD MCP environment and evaluation works with our RL pipeline (including remote configurations). See the guided docs: `https://docs.hud.so/train-agents/quickstart`.
|
|
257
256
|
|
|
258
257
|
## Benchmarking Agents
|
|
259
258
|
|
|
@@ -110,21 +110,34 @@ The above example let's the agent play 2048 ([See replay](https://app.hud.so/tra
|
|
|
110
110
|
|
|
111
111
|
## Reinforcement Learning with GRPO
|
|
112
112
|
|
|
113
|
-
This is a Qwen
|
|
113
|
+
This is a Qwen‑2.5‑VL‑3B agent training a policy on the 2048-basic browser environment:
|
|
114
114
|
|
|
115
115
|

|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
Train with the new interactive `hud rl` flow:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
# Install CLI with RL extras
|
|
121
|
+
uv tool install "hud-python[rl]"
|
|
122
|
+
|
|
123
|
+
# Option A: Run directly from a HuggingFace dataset
|
|
124
|
+
hud rl hud-evals/basic-2048
|
|
125
|
+
|
|
126
|
+
# Option B: Download first, modify, then train
|
|
127
|
+
hud get hud-evals/basic-2048
|
|
128
|
+
hud rl basic-2048.jsonl
|
|
129
|
+
|
|
130
|
+
# Optional: baseline evaluation
|
|
131
|
+
hud eval basic-2048.jsonl
|
|
123
132
|
```
|
|
124
133
|
|
|
125
|
-
|
|
134
|
+
Supports multi‑turn RL for both:
|
|
135
|
+
- Language‑only models (e.g., `Qwen/Qwen2.5-7B-Instruct`)
|
|
136
|
+
- Vision‑Language models (e.g., `Qwen/Qwen2.5-VL-3B-Instruct`)
|
|
137
|
+
|
|
138
|
+
By default, `hud rl` provisions a persistant server and trainer in the cloud, streams telemetry to `app.hud.so`, and lets you monitor/manage models at `app.hud.so/models`. Use `--local` to run entirely on your machines (typically 2+ GPUs: one for vLLM, the rest for training).
|
|
126
139
|
|
|
127
|
-
|
|
140
|
+
Any HUD MCP environment and evaluation works with our RL pipeline (including remote configurations). See the guided docs: `https://docs.hud.so/train-agents/quickstart`.
|
|
128
141
|
|
|
129
142
|
## Benchmarking Agents
|
|
130
143
|
|
|
@@ -231,7 +231,7 @@ class GenericOpenAIChatAgent(MCPAgent):
|
|
|
231
231
|
for tc in msg.tool_calls:
|
|
232
232
|
if tc.function.name is not None: # type: ignore
|
|
233
233
|
# _oai_to_mcp returns a single MCPToolCall; append it
|
|
234
|
-
tool_calls.append(self._oai_to_mcp(tc))
|
|
234
|
+
tool_calls.append(self._oai_to_mcp(tc)) # noqa: PERF401
|
|
235
235
|
|
|
236
236
|
# Only stop on length (token limit), never on "stop"
|
|
237
237
|
done = choice.finish_reason == "length"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from hud.cli.build import build_environment
|
|
12
|
+
from hud.cli.push import push_environment
|
|
13
|
+
from hud.cli.utils.docker import require_docker_running
|
|
14
|
+
from hud.cli.utils.environment import is_environment_directory
|
|
15
|
+
from hud.cli.utils.registry import extract_name_and_tag
|
|
16
|
+
from hud.utils.hud_console import hud_console
|
|
17
|
+
from hud.utils.tasks import load_tasks
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from hud.types import Task
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_remote_url(url: str) -> bool:
|
|
24
|
+
"""Match the remote url."""
|
|
25
|
+
# See if a url is a remote url
|
|
26
|
+
return bool(re.match(r"^(https?:\/\/)?(www\.)?[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}(\/\S*)?$", url))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _validate_tasks(tasks: list[Task]) -> bool:
|
|
30
|
+
"""Validate the tasks file."""
|
|
31
|
+
for task in tasks:
|
|
32
|
+
if not task.mcp_config or (not _is_remote_url(task.mcp_config.get("url", ""))):
|
|
33
|
+
return False
|
|
34
|
+
return True
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _find_environment_dir(tasks_path: Path) -> Path | None:
|
|
38
|
+
"""Find the environment directory related to a tasks file.
|
|
39
|
+
|
|
40
|
+
Strategy:
|
|
41
|
+
- Prefer a directory containing hud.lock.yaml
|
|
42
|
+
- Fallback to a directory that looks like an environment (Dockerfile + pyproject.toml)
|
|
43
|
+
- Search the tasks file directory, CWD, and a couple of parents
|
|
44
|
+
"""
|
|
45
|
+
candidates: list[Path] = []
|
|
46
|
+
cwd = Path.cwd()
|
|
47
|
+
candidates.extend([tasks_path.parent, cwd])
|
|
48
|
+
|
|
49
|
+
# Add parents (up to 2 levels for each)
|
|
50
|
+
for base in list(candidates):
|
|
51
|
+
p = base
|
|
52
|
+
for _ in range(2):
|
|
53
|
+
p = p.parent
|
|
54
|
+
if p not in candidates:
|
|
55
|
+
candidates.append(p)
|
|
56
|
+
|
|
57
|
+
# Prefer those with hud.lock.yaml
|
|
58
|
+
for d in candidates:
|
|
59
|
+
if (d / "hud.lock.yaml").exists():
|
|
60
|
+
return d
|
|
61
|
+
|
|
62
|
+
# Otherwise, find a plausible environment dir
|
|
63
|
+
for d in candidates:
|
|
64
|
+
try:
|
|
65
|
+
if is_environment_directory(d):
|
|
66
|
+
return d
|
|
67
|
+
except Exception as e:
|
|
68
|
+
hud_console.debug(f"Skipping path {d}: {e}")
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _ensure_built(env_dir: Path) -> dict[str, Any]:
|
|
75
|
+
"""Ensure the environment is built and a lock file exists; return lock data."""
|
|
76
|
+
lock_path = env_dir / "hud.lock.yaml"
|
|
77
|
+
if not lock_path.exists():
|
|
78
|
+
hud_console.warning("No hud.lock.yaml found. The environment hasn't been built.")
|
|
79
|
+
if not hud_console.confirm("Build the environment now (runs 'hud build')?", default=True):
|
|
80
|
+
raise typer.Exit(1)
|
|
81
|
+
# Check Docker availability before attempting a build
|
|
82
|
+
require_docker_running()
|
|
83
|
+
# Run build (non-interactive). If Docker isn't running, this will raise and stop the flow.
|
|
84
|
+
build_environment(str(env_dir))
|
|
85
|
+
|
|
86
|
+
# Load lock file
|
|
87
|
+
with open(lock_path) as f:
|
|
88
|
+
lock_data = yaml.safe_load(f) or {}
|
|
89
|
+
return lock_data
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _ensure_pushed(env_dir: Path, lock_data: dict[str, Any]) -> dict[str, Any]:
|
|
93
|
+
"""Ensure the environment is pushed to a registry; return updated lock data."""
|
|
94
|
+
pushed = bool(lock_data.get("push"))
|
|
95
|
+
if not pushed:
|
|
96
|
+
hud_console.warning("Environment not pushed to a registry yet.")
|
|
97
|
+
if not hud_console.confirm("Push to a registry now (runs 'hud push')?", default=True):
|
|
98
|
+
raise typer.Exit(1)
|
|
99
|
+
# Check Docker availability before attempting a push
|
|
100
|
+
require_docker_running()
|
|
101
|
+
|
|
102
|
+
# If Docker or login is not configured, the push function will fail and halt.
|
|
103
|
+
push_environment(str(env_dir))
|
|
104
|
+
|
|
105
|
+
# Reload lock after push
|
|
106
|
+
lock_path = env_dir / "hud.lock.yaml"
|
|
107
|
+
with open(lock_path) as f:
|
|
108
|
+
lock_data = yaml.safe_load(f) or {}
|
|
109
|
+
|
|
110
|
+
return lock_data
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _derive_remote_image(lock_data: dict[str, Any]) -> str:
|
|
114
|
+
"""Derive org/name:tag from lock file image field for MCP header."""
|
|
115
|
+
image_ref = str(lock_data.get("image", "")).strip()
|
|
116
|
+
if not image_ref:
|
|
117
|
+
raise typer.Exit("Lock file missing image reference")
|
|
118
|
+
name, tag = extract_name_and_tag(image_ref)
|
|
119
|
+
return f"{name}:{tag}"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def convert_tasks_to_remote(tasks_file: str) -> str:
|
|
123
|
+
"""Convert a local tasks file to remote MCP tasks and return new filename.
|
|
124
|
+
|
|
125
|
+
Steps:
|
|
126
|
+
1) Find env dir; ensure built (hud.lock.yaml), otherwise build
|
|
127
|
+
2) Ensure pushed to registry, otherwise push
|
|
128
|
+
3) Create remote_[tasks].json with mcp_config pointing to mcp.hud.so and Mcp-Image
|
|
129
|
+
4) Return the new tasks file path
|
|
130
|
+
"""
|
|
131
|
+
tasks_path = Path(tasks_file).resolve()
|
|
132
|
+
|
|
133
|
+
tasks = load_tasks(str(tasks_path))
|
|
134
|
+
|
|
135
|
+
# Ensure HUD_API_KEY is available: prefer process env, else load from env_dir/.env
|
|
136
|
+
from hud.settings import settings
|
|
137
|
+
|
|
138
|
+
if not settings.api_key or not settings.api_key.strip():
|
|
139
|
+
hud_console.error("HUD_API_KEY is not set")
|
|
140
|
+
raise typer.Exit(1)
|
|
141
|
+
|
|
142
|
+
# Load tasks (supports .json and .jsonl)
|
|
143
|
+
if _validate_tasks(tasks):
|
|
144
|
+
return str(tasks_path)
|
|
145
|
+
|
|
146
|
+
# Locate environment
|
|
147
|
+
env_dir = _find_environment_dir(tasks_path)
|
|
148
|
+
if not env_dir:
|
|
149
|
+
hud_console.error("Could not locate an environment directory (Dockerfile + pyproject.toml)")
|
|
150
|
+
hud_console.hint("Ensure you're in or near your environment folder before running 'hud rl'")
|
|
151
|
+
raise typer.Exit(1)
|
|
152
|
+
|
|
153
|
+
# Ensure built and pushed
|
|
154
|
+
lock_data = _ensure_built(env_dir)
|
|
155
|
+
lock_data = _ensure_pushed(env_dir, lock_data)
|
|
156
|
+
|
|
157
|
+
# Derive remote image name org/name:tag
|
|
158
|
+
remote_image = _derive_remote_image(lock_data)
|
|
159
|
+
|
|
160
|
+
# Convert to list[dict]
|
|
161
|
+
tasks_payload: list[dict[str, Any]] = []
|
|
162
|
+
for t in tasks:
|
|
163
|
+
item = t.model_dump()
|
|
164
|
+
item["mcp_config"] = {
|
|
165
|
+
"hud": {
|
|
166
|
+
"url": "https://mcp.hud.so/v3/mcp",
|
|
167
|
+
"headers": {
|
|
168
|
+
"Authorization": "Bearer ${HUD_API_KEY}",
|
|
169
|
+
"Mcp-Image": remote_image,
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
tasks_payload.append(item)
|
|
174
|
+
|
|
175
|
+
# Write new file: remote_<name>.json (always JSON array)
|
|
176
|
+
remote_name = f"remote_{tasks_path.stem}.json"
|
|
177
|
+
remote_path = tasks_path.parent / remote_name
|
|
178
|
+
with open(remote_path, "w", encoding="utf-8") as f:
|
|
179
|
+
json.dump(tasks_payload, f, ensure_ascii=False, indent=2)
|
|
180
|
+
f.write("\n")
|
|
181
|
+
|
|
182
|
+
hud_console.success(f"Created remote tasks file: {remote_path.name}")
|
|
183
|
+
hud_console.hint("Proceeding with RL training on the remote environment")
|
|
184
|
+
|
|
185
|
+
return str(remote_path)
|
|
@@ -433,11 +433,11 @@ NOTEBOOK_TEMPLATE = """{{
|
|
|
433
433
|
|
|
434
434
|
ENV_FILE_TEMPLATE = """# HUD API Configuration
|
|
435
435
|
# Get your API key from https://app.hud.so/account
|
|
436
|
-
HUD_API_KEY=
|
|
436
|
+
HUD_API_KEY=""
|
|
437
437
|
|
|
438
438
|
# Anthropic API Configuration (optional)
|
|
439
439
|
# Required for using Claude agents - get from https://console.anthropic.com/
|
|
440
|
-
ANTHROPIC_API_KEY=
|
|
440
|
+
ANTHROPIC_API_KEY=""
|
|
441
441
|
"""
|
|
442
442
|
|
|
443
443
|
README_TEMPLATE = """# {title}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""RL training command for HUD CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from hud.cli.utils.tasks import find_tasks_file
|
|
13
|
+
from hud.utils.hud_console import hud_console
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def rl_command(
|
|
22
|
+
tasks_file: str | None = typer.Argument(
|
|
23
|
+
None,
|
|
24
|
+
help="Path to tasks file (JSON/JSONL) or HuggingFace dataset name",
|
|
25
|
+
),
|
|
26
|
+
model: str | None = typer.Argument(
|
|
27
|
+
None,
|
|
28
|
+
help="Model to train (default: interactive selection)",
|
|
29
|
+
),
|
|
30
|
+
config_file: Path | None = typer.Option( # noqa: B008
|
|
31
|
+
None,
|
|
32
|
+
"--config",
|
|
33
|
+
"-c",
|
|
34
|
+
help="Path to existing configuration file",
|
|
35
|
+
),
|
|
36
|
+
output_dir: str = typer.Option(
|
|
37
|
+
"/checkpoints",
|
|
38
|
+
"--output-dir",
|
|
39
|
+
"-o",
|
|
40
|
+
help="Output directory for checkpoints",
|
|
41
|
+
),
|
|
42
|
+
restart: bool = typer.Option(
|
|
43
|
+
False,
|
|
44
|
+
"--restart",
|
|
45
|
+
help="Restart the vLLM server before training",
|
|
46
|
+
),
|
|
47
|
+
verbose: bool = typer.Option(
|
|
48
|
+
False,
|
|
49
|
+
"--verbose",
|
|
50
|
+
"-v",
|
|
51
|
+
help="Enable verbose output",
|
|
52
|
+
),
|
|
53
|
+
# DDP options
|
|
54
|
+
no_ddp: bool = typer.Option(
|
|
55
|
+
False,
|
|
56
|
+
"--no-ddp",
|
|
57
|
+
help="Disable DDP even with multiple GPUs",
|
|
58
|
+
),
|
|
59
|
+
ddp_gpus: str | None = typer.Option(
|
|
60
|
+
None,
|
|
61
|
+
"--ddp-gpus",
|
|
62
|
+
help="Specific GPUs for DDP (e.g., '0,1,2,3')",
|
|
63
|
+
),
|
|
64
|
+
vllm_gpu: int | None = typer.Option(
|
|
65
|
+
None,
|
|
66
|
+
"--vllm-gpu",
|
|
67
|
+
help="Specific GPU for vLLM server",
|
|
68
|
+
),
|
|
69
|
+
# Execution mode options
|
|
70
|
+
local: bool = typer.Option(
|
|
71
|
+
False,
|
|
72
|
+
"--local",
|
|
73
|
+
help="Run training locally instead of using remote API server",
|
|
74
|
+
),
|
|
75
|
+
# Internal flag
|
|
76
|
+
skip_vllm_startup: bool = typer.Option(
|
|
77
|
+
False,
|
|
78
|
+
hidden=True,
|
|
79
|
+
help="Skip local vLLM server startup (for internal use)",
|
|
80
|
+
),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Run GRPO reinforcement learning training on tasks."""
|
|
83
|
+
# Configure logging based on verbose flag BEFORE any output
|
|
84
|
+
if not verbose:
|
|
85
|
+
os.environ["HUD_LOG_LEVEL"] = "WARNING"
|
|
86
|
+
logging.basicConfig(level=logging.WARNING, force=True)
|
|
87
|
+
root_logger = logging.getLogger()
|
|
88
|
+
root_logger.setLevel(logging.WARNING)
|
|
89
|
+
|
|
90
|
+
# Suppress INFO logs from various components
|
|
91
|
+
for logger_name in [
|
|
92
|
+
"httpx",
|
|
93
|
+
"hud.agents",
|
|
94
|
+
"hud.utils.design",
|
|
95
|
+
"hud",
|
|
96
|
+
"asyncio",
|
|
97
|
+
"transformers",
|
|
98
|
+
]:
|
|
99
|
+
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
|
100
|
+
logging.getLogger("hud.agents.base").setLevel(logging.WARNING)
|
|
101
|
+
else:
|
|
102
|
+
logging.basicConfig(level=logging.INFO)
|
|
103
|
+
|
|
104
|
+
hud_console.header("HUD RL Training")
|
|
105
|
+
|
|
106
|
+
# Determine execution mode
|
|
107
|
+
use_remote = not local
|
|
108
|
+
|
|
109
|
+
if not tasks_file:
|
|
110
|
+
tasks_file = find_tasks_file(tasks_file)
|
|
111
|
+
if not tasks_file:
|
|
112
|
+
hud_console.warning("No tasks file found in current directory")
|
|
113
|
+
hud_console.hint(
|
|
114
|
+
"Download a HF dataset using `hud get <dataset_name>` (e.g., `hud get hud-evals/2048-basic`)" # noqa: E501
|
|
115
|
+
)
|
|
116
|
+
hud_console.hint("or create a tasks file manually.")
|
|
117
|
+
raise typer.Exit(1)
|
|
118
|
+
|
|
119
|
+
# If user ran bare `hud rl`, guide them through remote task conversion flow
|
|
120
|
+
# before proceeding (remote only)
|
|
121
|
+
if use_remote:
|
|
122
|
+
try:
|
|
123
|
+
from hud.cli.flows.tasks import convert_tasks_to_remote
|
|
124
|
+
|
|
125
|
+
console.print("\n[cyan]Preparing remote training tasks...[/cyan]")
|
|
126
|
+
console.print("[cyan](build/push if needed)[/cyan]")
|
|
127
|
+
tasks_file = convert_tasks_to_remote(tasks_file)
|
|
128
|
+
except typer.Exit:
|
|
129
|
+
raise
|
|
130
|
+
except Exception as e:
|
|
131
|
+
hud_console.warning(f"[red]Tasks file is not valid for remote training: {e!s}[/red]")
|
|
132
|
+
hud_console.hint("Either ensure the tasks file has remote urls")
|
|
133
|
+
hud_console.hint("Or rerun `hud rl` within an environment directory")
|
|
134
|
+
raise typer.Exit(1) from e
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
from .remote_runner import run_remote_training
|
|
138
|
+
|
|
139
|
+
run_remote_training(
|
|
140
|
+
tasks_file=tasks_file, model=model, config_file=config_file, output_dir=output_dir
|
|
141
|
+
)
|
|
142
|
+
return
|
|
143
|
+
except Exception as e:
|
|
144
|
+
console.print(f"[red]❌ Remote training failed: {e!s}[/red]")
|
|
145
|
+
raise typer.Exit(1) from e
|
|
146
|
+
|
|
147
|
+
# Local execution flow delegated to local_runner (imports heavy deps lazily)
|
|
148
|
+
from .local_runner import run_local_training
|
|
149
|
+
|
|
150
|
+
run_local_training(
|
|
151
|
+
tasks_file=tasks_file,
|
|
152
|
+
model=model,
|
|
153
|
+
config_file=config_file,
|
|
154
|
+
output_dir=output_dir,
|
|
155
|
+
restart=restart,
|
|
156
|
+
verbose=verbose,
|
|
157
|
+
no_ddp=no_ddp,
|
|
158
|
+
ddp_gpus=ddp_gpus,
|
|
159
|
+
vllm_gpu=vllm_gpu,
|
|
160
|
+
skip_vllm_startup=skip_vllm_startup,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# Export the command function
|
|
165
|
+
__all__ = ["rl_command"]
|