hud-python 0.4.29__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.

Files changed (222) hide show
  1. {hud_python-0.4.29 → hud_python-0.4.31}/PKG-INFO +26 -27
  2. {hud_python-0.4.29 → hud_python-0.4.31}/README.md +20 -7
  3. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/base.py +12 -4
  4. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/openai_chat_generic.py +2 -1
  5. hud_python-0.4.31/hud/cli/flows/tasks.py +185 -0
  6. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/init.py +2 -2
  7. hud_python-0.4.31/hud/cli/rl/__init__.py +165 -0
  8. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/display.py +1 -1
  9. hud_python-0.4.29/hud/cli/rl/__init__.py → hud_python-0.4.31/hud/cli/rl/local_runner.py +188 -200
  10. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/remote_runner.py +11 -2
  11. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/docker.py +94 -0
  12. {hud_python-0.4.29 → hud_python-0.4.31}/hud/native/comparator.py +6 -6
  13. {hud_python-0.4.29 → hud_python-0.4.31}/hud/native/tests/test_comparator.py +8 -8
  14. {hud_python-0.4.29 → hud_python-0.4.31}/hud/native/tests/test_native_init.py +12 -10
  15. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/README.md +2 -3
  16. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/learner.py +3 -0
  17. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/train.py +3 -0
  18. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/vllm_adapter.py +32 -14
  19. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/test_version.py +1 -1
  20. {hud_python-0.4.29 → hud_python-0.4.31}/hud/version.py +1 -1
  21. {hud_python-0.4.29 → hud_python-0.4.31}/pyproject.toml +9 -9
  22. hud_python-0.4.29/hud/cli/flows/tasks.py +0 -0
  23. {hud_python-0.4.29 → hud_python-0.4.31}/.gitignore +0 -0
  24. {hud_python-0.4.29 → hud_python-0.4.31}/LICENSE +0 -0
  25. {hud_python-0.4.29 → hud_python-0.4.31}/environments/README.md +0 -0
  26. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/README.md +0 -0
  27. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/apps/2048/README.md +0 -0
  28. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/apps/2048/backend/pyproject.toml +0 -0
  29. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/apps/README.md +0 -0
  30. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/apps/todo/README.md +0 -0
  31. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/apps/todo/backend/pyproject.toml +0 -0
  32. {hud_python-0.4.29 → hud_python-0.4.31}/environments/browser/pyproject.toml +0 -0
  33. {hud_python-0.4.29 → hud_python-0.4.31}/environments/remote_browser/README.md +0 -0
  34. {hud_python-0.4.29 → hud_python-0.4.31}/environments/remote_browser/pyproject.toml +0 -0
  35. {hud_python-0.4.29 → hud_python-0.4.31}/environments/remote_browser/src/hud_controller/providers/README.md +0 -0
  36. {hud_python-0.4.29 → hud_python-0.4.31}/environments/text_2048/README.md +0 -0
  37. {hud_python-0.4.29 → hud_python-0.4.31}/environments/text_2048/pyproject.toml +0 -0
  38. {hud_python-0.4.29 → hud_python-0.4.31}/examples/README.md +0 -0
  39. {hud_python-0.4.29 → hud_python-0.4.31}/hud/__init__.py +0 -0
  40. {hud_python-0.4.29 → hud_python-0.4.31}/hud/__main__.py +0 -0
  41. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/__init__.py +0 -0
  42. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/claude.py +0 -0
  43. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/grounded_openai.py +0 -0
  44. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/langchain.py +0 -0
  45. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/misc/__init__.py +0 -0
  46. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/misc/response_agent.py +0 -0
  47. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/openai.py +0 -0
  48. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/__init__.py +0 -0
  49. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/test_base.py +0 -0
  50. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/test_claude.py +0 -0
  51. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/test_client.py +0 -0
  52. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/test_grounded_openai_agent.py +0 -0
  53. {hud_python-0.4.29 → hud_python-0.4.31}/hud/agents/tests/test_openai.py +0 -0
  54. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/__init__.py +0 -0
  55. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/__main__.py +0 -0
  56. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/analyze.py +0 -0
  57. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/build.py +0 -0
  58. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/clone.py +0 -0
  59. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/debug.py +0 -0
  60. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/dev.py +0 -0
  61. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/eval.py +0 -0
  62. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/flows/__init__.py +0 -0
  63. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/get.py +0 -0
  64. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/list_func.py +0 -0
  65. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/pull.py +0 -0
  66. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/push.py +0 -0
  67. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/remove.py +0 -0
  68. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/config.py +0 -0
  69. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/gpu.py +0 -0
  70. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/gpu_utils.py +0 -0
  71. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/presets.py +0 -0
  72. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/rl_api.py +0 -0
  73. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/rl/vllm.py +0 -0
  74. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/__init__.py +0 -0
  75. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_analyze.py +0 -0
  76. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_analyze_metadata.py +0 -0
  77. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_build.py +0 -0
  78. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_cli_init.py +0 -0
  79. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_cli_main.py +0 -0
  80. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_clone.py +0 -0
  81. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_cursor.py +0 -0
  82. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_debug.py +0 -0
  83. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_list_func.py +0 -0
  84. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_main_module.py +0 -0
  85. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_mcp_server.py +0 -0
  86. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_pull.py +0 -0
  87. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_push.py +0 -0
  88. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_registry.py +0 -0
  89. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/tests/test_utils.py +0 -0
  90. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/__init__.py +0 -0
  91. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/cursor.py +0 -0
  92. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/environment.py +0 -0
  93. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/interactive.py +0 -0
  94. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/logging.py +0 -0
  95. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/metadata.py +0 -0
  96. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/registry.py +0 -0
  97. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/remote_runner.py +0 -0
  98. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/runner.py +0 -0
  99. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/server.py +0 -0
  100. {hud_python-0.4.29 → hud_python-0.4.31}/hud/cli/utils/tasks.py +0 -0
  101. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/README.md +0 -0
  102. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/__init__.py +0 -0
  103. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/base.py +0 -0
  104. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/fastmcp.py +0 -0
  105. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/mcp_use.py +0 -0
  106. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/tests/__init__.py +0 -0
  107. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/tests/test_client_integration.py +0 -0
  108. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/tests/test_fastmcp.py +0 -0
  109. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/tests/test_mcp_use_retry.py +0 -0
  110. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/tests/test_protocol.py +0 -0
  111. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/utils/__init__.py +0 -0
  112. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/utils/mcp_use_retry.py +0 -0
  113. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/utils/retry.py +0 -0
  114. {hud_python-0.4.29 → hud_python-0.4.31}/hud/clients/utils/retry_transport.py +0 -0
  115. {hud_python-0.4.29 → hud_python-0.4.31}/hud/datasets/__init__.py +0 -0
  116. {hud_python-0.4.29 → hud_python-0.4.31}/hud/datasets/parallel.py +0 -0
  117. {hud_python-0.4.29 → hud_python-0.4.31}/hud/datasets/runner.py +0 -0
  118. {hud_python-0.4.29 → hud_python-0.4.31}/hud/datasets/utils.py +0 -0
  119. {hud_python-0.4.29 → hud_python-0.4.31}/hud/misc/__init__.py +0 -0
  120. {hud_python-0.4.29 → hud_python-0.4.31}/hud/misc/claude_plays_pokemon.py +0 -0
  121. {hud_python-0.4.29 → hud_python-0.4.31}/hud/native/__init__.py +0 -0
  122. {hud_python-0.4.29 → hud_python-0.4.31}/hud/native/tests/__init__.py +0 -0
  123. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/__init__.py +0 -0
  124. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/collector.py +0 -0
  125. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/config.py +0 -0
  126. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/context.py +0 -0
  127. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/exporters.py +0 -0
  128. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/instrumentation.py +0 -0
  129. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/processors.py +0 -0
  130. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/tests/__init__.py +0 -0
  131. {hud_python-0.4.29 → hud_python-0.4.31}/hud/otel/tests/test_processors.py +0 -0
  132. {hud_python-0.4.29 → hud_python-0.4.31}/hud/py.typed +0 -0
  133. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/__init__.py +0 -0
  134. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/actor.py +0 -0
  135. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/buffer.py +0 -0
  136. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/chat_template.jinja +0 -0
  137. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/config.py +0 -0
  138. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/distributed.py +0 -0
  139. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/tests/__init__.py +0 -0
  140. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/tests/test_learner.py +0 -0
  141. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/types.py +0 -0
  142. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/utils/start_vllm_server.sh +0 -0
  143. {hud_python-0.4.29 → hud_python-0.4.31}/hud/rl/utils.py +0 -0
  144. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/__init__.py +0 -0
  145. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/context.py +0 -0
  146. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/helper/__init__.py +0 -0
  147. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/low_level.py +0 -0
  148. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/server.py +0 -0
  149. {hud_python-0.4.29 → hud_python-0.4.31}/hud/server/tests/__init__.py +0 -0
  150. {hud_python-0.4.29 → hud_python-0.4.31}/hud/settings.py +0 -0
  151. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/__init__.py +0 -0
  152. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/exceptions.py +0 -0
  153. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/hints.py +0 -0
  154. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/requests.py +0 -0
  155. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/tests/__init__.py +0 -0
  156. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/tests/test_exceptions.py +0 -0
  157. {hud_python-0.4.29 → hud_python-0.4.31}/hud/shared/tests/test_requests.py +0 -0
  158. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/__init__.py +0 -0
  159. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/instrument.py +0 -0
  160. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/job.py +0 -0
  161. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/replay.py +0 -0
  162. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/tests/__init__.py +0 -0
  163. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/tests/test_replay.py +0 -0
  164. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/tests/test_trace.py +0 -0
  165. {hud_python-0.4.29 → hud_python-0.4.31}/hud/telemetry/trace.py +0 -0
  166. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/__init__.py +0 -0
  167. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/base.py +0 -0
  168. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/bash.py +0 -0
  169. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/computer/__init__.py +0 -0
  170. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/computer/anthropic.py +0 -0
  171. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/computer/hud.py +0 -0
  172. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/computer/openai.py +0 -0
  173. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/computer/settings.py +0 -0
  174. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/edit.py +0 -0
  175. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/__init__.py +0 -0
  176. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/base.py +0 -0
  177. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/pyautogui.py +0 -0
  178. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/tests/__init__.py +0 -0
  179. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/tests/test_base_executor.py +0 -0
  180. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/tests/test_pyautogui_executor.py +0 -0
  181. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/executors/xdo.py +0 -0
  182. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/__init__.py +0 -0
  183. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/config.py +0 -0
  184. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/grounded_tool.py +0 -0
  185. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/grounder.py +0 -0
  186. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/tests/__init__.py +0 -0
  187. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/grounding/tests/test_grounded_tool.py +0 -0
  188. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/playwright.py +0 -0
  189. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/response.py +0 -0
  190. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/submit.py +0 -0
  191. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/__init__.py +0 -0
  192. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_base.py +0 -0
  193. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_bash.py +0 -0
  194. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_bash_extended.py +0 -0
  195. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_computer.py +0 -0
  196. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_computer_actions.py +0 -0
  197. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_edit.py +0 -0
  198. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_init.py +0 -0
  199. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_playwright_tool.py +0 -0
  200. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_response.py +0 -0
  201. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_tools.py +0 -0
  202. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_tools_init.py +0 -0
  203. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/tests/test_utils.py +0 -0
  204. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/types.py +0 -0
  205. {hud_python-0.4.29 → hud_python-0.4.31}/hud/tools/utils.py +0 -0
  206. {hud_python-0.4.29 → hud_python-0.4.31}/hud/types.py +0 -0
  207. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/__init__.py +0 -0
  208. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/agent_factories.py +0 -0
  209. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/async_utils.py +0 -0
  210. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/group_eval.py +0 -0
  211. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/hud_console.py +0 -0
  212. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/mcp.py +0 -0
  213. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/pretty_errors.py +0 -0
  214. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/progress.py +0 -0
  215. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tasks.py +0 -0
  216. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/telemetry.py +0 -0
  217. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/__init__.py +0 -0
  218. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/test_async_utils.py +0 -0
  219. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/test_init.py +0 -0
  220. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/test_mcp.py +0 -0
  221. {hud_python-0.4.29 → hud_python-0.4.31}/hud/utils/tests/test_progress.py +0 -0
  222. {hud_python-0.4.29 → 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.29
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-2.5-3B agent training a policy on the [`text-2048`](environments/text_2048/) environment (see above) using [Verifiers](rl/):
228
+ This is a Qwen2.5‑VL‑3B agent training a policy on the 2048-basic browser environment:
243
229
 
244
230
  ![RL curve](https://raw.githubusercontent.com/hud-evals/hud-python/main/docs/src/images/rl_2.png)
245
231
 
246
- To start training, check out the [`rl/README.md`](rl/README.md) folder:
232
+ Train with the new interactive `hud rl` flow:
247
233
 
248
234
  ```bash
249
- git clone https://github.com/hud-evals/hud-python
250
- cd hud-python/rl
251
- python train_2048.py
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
- Any hud MCP environment and evaluation works with our RL pipeline. Even our remote configurations!
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
- > The [`rl/README.md`](rl/README.md) walks you through several examples of RL training and takes less than 15 minutes to set up for your custom agent!
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-2.5-3B agent training a policy on the [`text-2048`](environments/text_2048/) environment (see above) using [Verifiers](rl/):
113
+ This is a Qwen2.5‑VL‑3B agent training a policy on the 2048-basic browser environment:
114
114
 
115
115
  ![RL curve](https://raw.githubusercontent.com/hud-evals/hud-python/main/docs/src/images/rl_2.png)
116
116
 
117
- To start training, check out the [`rl/README.md`](rl/README.md) folder:
117
+ Train with the new interactive `hud rl` flow:
118
118
 
119
119
  ```bash
120
- git clone https://github.com/hud-evals/hud-python
121
- cd hud-python/rl
122
- python train_2048.py
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
- Any hud MCP environment and evaluation works with our RL pipeline. Even our remote configurations!
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
- > The [`rl/README.md`](rl/README.md) walks you through several examples of RL training and takes less than 15 minutes to set up for your custom agent!
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
 
@@ -153,16 +153,24 @@ class MCPAgent(ABC):
153
153
  if task.setup_tool:
154
154
  if isinstance(task.setup_tool, list):
155
155
  for tool in task.setup_tool:
156
- if self.agent_tools and tool.name not in self.agent_tools:
156
+ if not self.agent_tools or (
157
+ self.agent_tools and tool.name not in self.agent_tools
158
+ ):
157
159
  self.lifecycle_tools.append(tool.name)
158
- elif self.agent_tools and task.setup_tool.name not in self.agent_tools:
160
+ elif not self.agent_tools or (
161
+ self.agent_tools and task.setup_tool.name not in self.agent_tools
162
+ ):
159
163
  self.lifecycle_tools.append(task.setup_tool.name)
160
164
  if task.evaluate_tool:
161
165
  if isinstance(task.evaluate_tool, list):
162
166
  for tool in task.evaluate_tool:
163
- if self.agent_tools and tool.name not in self.agent_tools:
167
+ if not self.agent_tools or (
168
+ self.agent_tools and tool.name not in self.agent_tools
169
+ ):
164
170
  self.lifecycle_tools.append(tool.name)
165
- elif self.agent_tools and task.evaluate_tool.name not in self.agent_tools:
171
+ elif not self.agent_tools or (
172
+ self.agent_tools and task.evaluate_tool.name not in self.agent_tools
173
+ ):
166
174
  self.lifecycle_tools.append(task.evaluate_tool.name)
167
175
  if task.system_prompt:
168
176
  self.system_prompt += "\n\n" + task.system_prompt
@@ -230,7 +230,8 @@ class GenericOpenAIChatAgent(MCPAgent):
230
230
  if msg.tool_calls:
231
231
  for tc in msg.tool_calls:
232
232
  if tc.function.name is not None: # type: ignore
233
- tool_calls.extend(self._oai_to_mcp(tc))
233
+ # _oai_to_mcp returns a single MCPToolCall; append it
234
+ tool_calls.append(self._oai_to_mcp(tc)) # noqa: PERF401
234
235
 
235
236
  # Only stop on length (token limit), never on "stop"
236
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=your_hud_api_key_here
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=your_anthropic_api_key_here
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"]
@@ -42,7 +42,7 @@ def display_preset_table(presets: list[dict[str, Any]], gpu_memory_gb: float) ->
42
42
  # Add time columns for A100
43
43
  if gpu_memory_gb >= 40:
44
44
  preset_table.add_column("Tasks/hour", style="green")
45
- preset_table.add_column("Steps/hour", style="green")
45
+ preset_table.add_column("Updates/hour", style="green")
46
46
 
47
47
  for i, preset in enumerate(presets):
48
48
  row = [