hud 0.6.16.dev4__tar.gz → 0.6.18.dev1__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.
Files changed (335) hide show
  1. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/.gitignore +2 -2
  2. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/PKG-INFO +6 -14
  3. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/README.md +3 -11
  4. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/__main__.py +1 -1
  5. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/__init__.py +35 -69
  6. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/agent.py +11 -7
  7. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/sdk/agent.py +18 -5
  8. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/agent.py +5 -11
  9. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/agent.py +43 -17
  10. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/computer.py +58 -41
  11. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/tests/test_computer.py +50 -10
  12. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/agent.py +1 -1
  13. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_base.py +28 -6
  14. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_claude_agent.py +44 -1
  15. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_claude_sdk_agent.py +27 -6
  16. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_openai_agent.py +158 -1
  17. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_tool_agent.py +106 -2
  18. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tool_agent.py +22 -6
  19. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/types.py +10 -1
  20. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/mcp.py +27 -2
  21. hud-0.6.18.dev1/hud/cli/__init__.py +425 -0
  22. hud-0.6.18.dev1/hud/cli/__main__.py +270 -0
  23. hud-0.6.18.dev1/hud/cli/deploy.py +541 -0
  24. hud-0.6.18.dev1/hud/cli/eval.py +564 -0
  25. hud-0.6.18.dev1/hud/cli/init.py +195 -0
  26. hud-0.6.18.dev1/hud/cli/jobs.py +280 -0
  27. hud-0.6.18.dev1/hud/cli/models.py +262 -0
  28. hud-0.6.18.dev1/hud/cli/project.py +247 -0
  29. hud-0.6.18.dev1/hud/cli/qa.py +574 -0
  30. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/cli/serve.py +23 -54
  31. hud-0.6.18.dev1/hud/cli/sync.py +434 -0
  32. hud-0.6.18.dev1/hud/cli/task.py +213 -0
  33. hud-0.6.18.dev1/hud/cli/tests/test_cli.py +853 -0
  34. hud-0.6.18.dev1/hud/cli/tests/test_deploy.py +850 -0
  35. hud-0.6.18.dev1/hud/cli/tests/test_eval.py +687 -0
  36. hud-0.6.18.dev1/hud/cli/tests/test_init.py +255 -0
  37. hud-0.6.18.dev1/hud/cli/tests/test_jobs.py +73 -0
  38. hud-0.6.18.dev1/hud/cli/tests/test_main.py +26 -0
  39. hud-0.6.18.dev1/hud/cli/tests/test_project.py +284 -0
  40. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/cli/tests/test_qa.py +117 -4
  41. hud-0.6.18.dev1/hud/cli/tests/test_sync.py +396 -0
  42. hud-0.6.18.dev1/hud/cli/tests/test_task.py +149 -0
  43. hud-0.6.18.dev1/hud/cli/tests/test_trace.py +76 -0
  44. hud-0.6.18.dev1/hud/cli/trace.py +158 -0
  45. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/clients/client.py +22 -12
  46. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/clients/tests/test_connect.py +17 -5
  47. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/conftest.py +4 -0
  48. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/file_tracker.py +1 -1
  49. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/server.py +54 -12
  50. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_server.py +81 -2
  51. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_sessions.py +23 -2
  52. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_tunnel.py +18 -1
  53. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_workspace.py +27 -0
  54. hud-0.6.18.dev1/hud/environment/utils.py +134 -0
  55. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/workspace.py +3 -1
  56. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/job.py +4 -2
  57. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/run.py +11 -7
  58. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/hosted.py +41 -10
  59. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/local.py +26 -8
  60. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/sync.py +7 -0
  61. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/task.py +9 -0
  62. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/taskset.py +39 -19
  63. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_hosted.py +97 -2
  64. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_job.py +2 -0
  65. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_local_runtime.py +81 -1
  66. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_rollout.py +120 -13
  67. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_sync.py +35 -0
  68. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/settings.py +16 -1
  69. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/context.py +21 -10
  70. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/exporter.py +4 -4
  71. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/robot/recorder.py +2 -2
  72. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/span.py +4 -9
  73. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/tests/test_exporter.py +10 -0
  74. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/base.py +15 -35
  75. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/tests/test_client.py +26 -0
  76. hud-0.6.18.dev1/hud/utils/gateway.py +202 -0
  77. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/hud_console.py +6 -9
  78. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/platform.py +9 -9
  79. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/requests.py +35 -90
  80. hud-0.6.18.dev1/hud/utils/tests/test_gateway.py +303 -0
  81. hud-0.6.18.dev1/hud/utils/tests/test_naming.py +13 -0
  82. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_platform.py +13 -13
  83. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_requests.py +45 -20
  84. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/version.py +1 -1
  85. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/pyproject.toml +5 -3
  86. hud-0.6.16.dev4/hud/cli/__init__.py +0 -175
  87. hud-0.6.16.dev4/hud/cli/__main__.py +0 -8
  88. hud-0.6.16.dev4/hud/cli/cancel.py +0 -111
  89. hud-0.6.16.dev4/hud/cli/client.py +0 -82
  90. hud-0.6.16.dev4/hud/cli/deploy.py +0 -881
  91. hud-0.6.16.dev4/hud/cli/eval.py +0 -1003
  92. hud-0.6.16.dev4/hud/cli/init.py +0 -187
  93. hud-0.6.16.dev4/hud/cli/jobs.py +0 -147
  94. hud-0.6.16.dev4/hud/cli/login.py +0 -238
  95. hud-0.6.16.dev4/hud/cli/models.py +0 -274
  96. hud-0.6.16.dev4/hud/cli/presets.py +0 -217
  97. hud-0.6.16.dev4/hud/cli/qa.py +0 -419
  98. hud-0.6.16.dev4/hud/cli/qa_analysis.py +0 -207
  99. hud-0.6.16.dev4/hud/cli/sync.py +0 -502
  100. hud-0.6.16.dev4/hud/cli/task.py +0 -210
  101. hud-0.6.16.dev4/hud/cli/templates.py +0 -141
  102. hud-0.6.16.dev4/hud/cli/tests/test_cli_init.py +0 -87
  103. hud-0.6.16.dev4/hud/cli/tests/test_cli_main.py +0 -27
  104. hud-0.6.16.dev4/hud/cli/tests/test_cli_more_wrappers.py +0 -7
  105. hud-0.6.16.dev4/hud/cli/tests/test_deploy.py +0 -543
  106. hud-0.6.16.dev4/hud/cli/tests/test_eval_bedrock.py +0 -51
  107. hud-0.6.16.dev4/hud/cli/tests/test_eval_config.py +0 -354
  108. hud-0.6.16.dev4/hud/cli/tests/test_init.py +0 -134
  109. hud-0.6.16.dev4/hud/cli/tests/test_jobs.py +0 -38
  110. hud-0.6.16.dev4/hud/cli/tests/test_main_module.py +0 -36
  111. hud-0.6.16.dev4/hud/cli/tests/test_qa_analysis.py +0 -87
  112. hud-0.6.16.dev4/hud/cli/tests/test_sync_export.py +0 -58
  113. hud-0.6.16.dev4/hud/cli/tests/test_trace.py +0 -26
  114. hud-0.6.16.dev4/hud/cli/tests/test_usage.py +0 -134
  115. hud-0.6.16.dev4/hud/cli/trace.py +0 -219
  116. hud-0.6.16.dev4/hud/cli/utils/__init__.py +0 -1
  117. hud-0.6.16.dev4/hud/cli/utils/api.py +0 -22
  118. hud-0.6.16.dev4/hud/cli/utils/build_display.py +0 -279
  119. hud-0.6.16.dev4/hud/cli/utils/build_logs.py +0 -230
  120. hud-0.6.16.dev4/hud/cli/utils/config.py +0 -115
  121. hud-0.6.16.dev4/hud/cli/utils/context.py +0 -282
  122. hud-0.6.16.dev4/hud/cli/utils/display.py +0 -100
  123. hud-0.6.16.dev4/hud/cli/utils/jobs.py +0 -38
  124. hud-0.6.16.dev4/hud/cli/utils/registry.py +0 -100
  125. hud-0.6.16.dev4/hud/cli/utils/source.py +0 -557
  126. hud-0.6.16.dev4/hud/cli/utils/tasks.py +0 -29
  127. hud-0.6.16.dev4/hud/cli/utils/tests/test_build_display.py +0 -49
  128. hud-0.6.16.dev4/hud/cli/utils/tests/test_config.py +0 -58
  129. hud-0.6.16.dev4/hud/cli/utils/tests/test_context.py +0 -92
  130. hud-0.6.16.dev4/hud/cli/utils/tests/test_registry.py +0 -76
  131. hud-0.6.16.dev4/hud/cli/utils/tests/test_source.py +0 -321
  132. hud-0.6.16.dev4/hud/cli/utils/tests/test_tasks.py +0 -80
  133. hud-0.6.16.dev4/hud/cli/utils/tests/test_version_check.py +0 -109
  134. hud-0.6.16.dev4/hud/cli/utils/usage.py +0 -179
  135. hud-0.6.16.dev4/hud/cli/utils/version_check.py +0 -237
  136. hud-0.6.16.dev4/hud/environment/utils.py +0 -84
  137. hud-0.6.16.dev4/hud/utils/gateway.py +0 -143
  138. hud-0.6.16.dev4/hud/utils/tests/__init__.py +0 -0
  139. hud-0.6.16.dev4/hud/utils/tests/test_gateway.py +0 -160
  140. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/LICENSE +0 -0
  141. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/__init__.py +0 -0
  142. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/base.py +0 -0
  143. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/browser_use/__init__.py +0 -0
  144. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/browser_use/agent.py +0 -0
  145. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/__init__.py +0 -0
  146. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/sdk/__init__.py +0 -0
  147. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/sdk/computer_mcp.py +0 -0
  148. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/__init__.py +0 -0
  149. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/base.py +0 -0
  150. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/coding.py +0 -0
  151. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/computer.py +0 -0
  152. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/hosted.py +0 -0
  153. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/mcp_proxy.py +0 -0
  154. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/settings.py +0 -0
  155. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/tests/__init__.py +0 -0
  156. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/claude/tools/tests/test_computer.py +0 -0
  157. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/__init__.py +0 -0
  158. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/settings.py +0 -0
  159. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/__init__.py +0 -0
  160. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/base.py +0 -0
  161. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/coding.py +0 -0
  162. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/computer.py +0 -0
  163. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/filesystem.py +0 -0
  164. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/hosted.py +0 -0
  165. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
  166. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/tests/__init__.py +0 -0
  167. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/gemini/tools/tests/test_computer.py +0 -0
  168. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/misc/__init__.py +0 -0
  169. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/misc/response_automation.py +0 -0
  170. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/__init__.py +0 -0
  171. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/__init__.py +0 -0
  172. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/apply_patch.py +0 -0
  173. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/base.py +0 -0
  174. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/coding.py +0 -0
  175. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/hosted.py +0 -0
  176. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/mcp_proxy.py +0 -0
  177. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/strict_schema.py +0 -0
  178. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/tests/__init__.py +0 -0
  179. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
  180. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/__init__.py +0 -0
  181. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/tools/__init__.py +0 -0
  182. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/tools/base.py +0 -0
  183. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/tools/filesystem.py +0 -0
  184. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/openai_compatible/tools/mcp_proxy.py +0 -0
  185. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/__init__.py +0 -0
  186. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/adapter.py +0 -0
  187. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/agent.py +0 -0
  188. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/batching.py +0 -0
  189. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/dataset.py +0 -0
  190. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/robot/model.py +0 -0
  191. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/__init__.py +0 -0
  192. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_apply_patch.py +0 -0
  193. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_gemini_agent.py +0 -0
  194. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_openai_compatible_agent.py +0 -0
  195. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_provider_native_tools.py +0 -0
  196. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_robot_dataset_writer.py +0 -0
  197. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tests/test_trace.py +0 -0
  198. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/__init__.py +0 -0
  199. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/base.py +0 -0
  200. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/hosted.py +0 -0
  201. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/mcp.py +0 -0
  202. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/rfb.py +0 -0
  203. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/agents/tools/ssh.py +0 -0
  204. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/__init__.py +0 -0
  205. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/base.py +0 -0
  206. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/cdp.py +0 -0
  207. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/rfb.py +0 -0
  208. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/robot.py +0 -0
  209. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/ssh.py +0 -0
  210. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/tests/__init__.py +0 -0
  211. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/tests/test_rfb.py +0 -0
  212. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/capabilities/tests/test_ssh.py +0 -0
  213. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/cli/tests/__init__.py +0 -0
  214. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/clients/__init__.py +0 -0
  215. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/clients/tests/__init__.py +0 -0
  216. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/__init__.py +0 -0
  217. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/arguments.py +0 -0
  218. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/egress.py +0 -0
  219. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/env.py +0 -0
  220. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/namespace.py +0 -0
  221. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/robot/__init__.py +0 -0
  222. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/robot/bridge.py +0 -0
  223. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/robot/endpoint.py +0 -0
  224. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/robot/gym.py +0 -0
  225. {hud-0.6.16.dev4/hud/cli/utils → hud-0.6.18.dev1/hud/environment}/tests/__init__.py +0 -0
  226. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/conftest.py +0 -0
  227. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_arguments.py +0 -0
  228. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_capability_backing.py +0 -0
  229. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_file_tracker.py +0 -0
  230. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_file_tracking.py +0 -0
  231. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_loader.py +0 -0
  232. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_manifest.py +0 -0
  233. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_platform.py +0 -0
  234. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/environment/tests/test_robot_regressions.py +0 -0
  235. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/__init__.py +0 -0
  236. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/chat.py +0 -0
  237. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/docker-seccomp.json +0 -0
  238. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/file_tracking.py +0 -0
  239. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/__init__.py +0 -0
  240. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/compose.py +0 -0
  241. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/core.py +0 -0
  242. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/daytona.py +0 -0
  243. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/docker.py +0 -0
  244. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/hud.py +0 -0
  245. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/runtime/modal.py +0 -0
  246. {hud-0.6.16.dev4/hud/environment → hud-0.6.18.dev1/hud/eval}/tests/__init__.py +0 -0
  247. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_chat.py +0 -0
  248. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_docker_provider.py +0 -0
  249. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_file_tracking_observer.py +0 -0
  250. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_shared.py +0 -0
  251. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/eval/tests/test_task.py +0 -0
  252. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/__init__.py +0 -0
  253. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/base.py +0 -0
  254. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/bash.py +0 -0
  255. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/combine.py +0 -0
  256. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/judge.py +0 -0
  257. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/results.py +0 -0
  258. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/graders/text.py +0 -0
  259. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/__init__.py +0 -0
  260. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/Dockerfile +0 -0
  261. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/__init__.py +0 -0
  262. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/adapt.py +0 -0
  263. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/env.py +0 -0
  264. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/export.py +0 -0
  265. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/install.sh +0 -0
  266. {hud-0.6.16.dev4/hud/eval → hud-0.6.18.dev1/hud/integrations/harbor}/tests/__init__.py +0 -0
  267. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/conftest.py +0 -0
  268. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +0 -0
  269. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +0 -0
  270. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +0 -0
  271. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +0 -0
  272. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +0 -0
  273. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +0 -0
  274. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/docker-compose.yaml +0 -0
  275. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +0 -0
  276. {hud-0.6.16.dev4/hud/integrations/harbor/tests → hud-0.6.18.dev1/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server}/__init__.py +0 -0
  277. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +0 -0
  278. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +0 -0
  279. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +0 -0
  280. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +0 -0
  281. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +0 -0
  282. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +0 -0
  283. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +0 -0
  284. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +0 -0
  285. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +0 -0
  286. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +0 -0
  287. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +0 -0
  288. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +0 -0
  289. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/docker-compose.yaml +0 -0
  290. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +0 -0
  291. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +0 -0
  292. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +0 -0
  293. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +0 -0
  294. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +0 -0
  295. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +0 -0
  296. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +0 -0
  297. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +0 -0
  298. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +0 -0
  299. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +0 -0
  300. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +0 -0
  301. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/test_contract.py +0 -0
  302. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/test_harbor.py +0 -0
  303. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/integrations/harbor/tests/test_integration.py +0 -0
  304. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/patches/__init__.py +0 -0
  305. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/patches/mcp_patches.py +0 -0
  306. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/patches/tests/__init__.py +0 -0
  307. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/patches/tests/test_warnings.py +0 -0
  308. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/patches/warnings.py +0 -0
  309. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/py.typed +0 -0
  310. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/__init__.py +0 -0
  311. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/instrument.py +0 -0
  312. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/robot/__init__.py +0 -0
  313. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/robot/video.py +0 -0
  314. {hud-0.6.16.dev4/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server → hud-0.6.18.dev1/hud/telemetry/tests}/__init__.py +0 -0
  315. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/telemetry/tests/test_instrument.py +0 -0
  316. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/__init__.py +0 -0
  317. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/client.py +0 -0
  318. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/tests/__init__.py +0 -0
  319. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/train/types.py +0 -0
  320. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/types.py +0 -0
  321. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/__init__.py +0 -0
  322. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/docker.py +0 -0
  323. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/exceptions.py +0 -0
  324. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/hints.py +0 -0
  325. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/modules.py +0 -0
  326. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/naming.py +0 -0
  327. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/process.py +0 -0
  328. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/serialization.py +0 -0
  329. {hud-0.6.16.dev4/hud/telemetry → hud-0.6.18.dev1/hud/utils}/tests/__init__.py +0 -0
  330. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_exceptions.py +0 -0
  331. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_hints.py +0 -0
  332. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_hud_console.py +0 -0
  333. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_process.py +0 -0
  334. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/tests/test_serialization.py +0 -0
  335. {hud-0.6.16.dev4 → hud-0.6.18.dev1}/hud/utils/time.py +0 -0
@@ -59,11 +59,11 @@ hud/rl/checkpoints_test/
59
59
  .hud/
60
60
  .hud_eval_config
61
61
  .hud_eval.toml
62
+ # The template hud init copies into new projects.
63
+ !environments/*/.hud_eval.toml
62
64
 
63
65
  docs/internal
64
66
 
65
- environments/
66
-
67
67
  experiments/
68
68
  .memories/
69
69
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hud
3
- Version: 0.6.16.dev4
3
+ Version: 0.6.18.dev1
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
@@ -34,7 +34,7 @@ Classifier: Programming Language :: Python :: 3
34
34
  Classifier: Programming Language :: Python :: 3.11
35
35
  Classifier: Programming Language :: Python :: 3.12
36
36
  Requires-Python: <3.13,>=3.11
37
- Requires-Dist: anthropic>=0.78.0
37
+ Requires-Dist: anthropic>=0.98.0
38
38
  Requires-Dist: asyncssh>=2.23.0
39
39
  Requires-Dist: asyncvnc>=1.3.0
40
40
  Requires-Dist: fastmcp==3.2.0
@@ -56,7 +56,7 @@ Requires-Dist: websockets>=15.0.1
56
56
  Provides-Extra: agent
57
57
  Provides-Extra: agents
58
58
  Provides-Extra: bedrock
59
- Requires-Dist: anthropic[bedrock]>=0.78.0; extra == 'bedrock'
59
+ Requires-Dist: anthropic[bedrock]>=0.98.0; extra == 'bedrock'
60
60
  Provides-Extra: browseruse
61
61
  Requires-Dist: browser-use>=0.11.13; extra == 'browseruse'
62
62
  Provides-Extra: daytona
@@ -123,10 +123,12 @@ hud set HUD_API_KEY=your-key-here
123
123
  # or: export HUD_API_KEY=your-key-here
124
124
  ```
125
125
 
126
- Then scaffold your first environment:
126
+ Then start from the coding environment, or choose another example environment:
127
127
 
128
128
  ```bash
129
129
  hud init my-env
130
+ hud init my-desktop-env --template cua
131
+ hud init my-custom-env --template blank
130
132
  ```
131
133
 
132
134
  ![Agent running on SheetBench](docs/src/images/trace_sheet.gif)
@@ -166,16 +168,6 @@ hud sync tasks my-taskset
166
168
  hud eval my-taskset --remote
167
169
  ```
168
170
 
169
- For local iteration, the same protocol works against a container on your laptop:
170
-
171
- ```bash
172
- docker build -f Dockerfile.hud -t my-env .
173
- docker run -d --name run1 -p 8765:8765 my-env
174
- hud task start fix_bug --url tcp://127.0.0.1:8765
175
- hud task grade fix_bug --url tcp://127.0.0.1:8765 --answer "..."
176
- docker rm -f run1
177
- ```
178
-
179
171
  → [Run & deploy](https://docs.hud.ai/v6/reference/runtime)
180
172
 
181
173
  ## Environments & templates
@@ -37,10 +37,12 @@ hud set HUD_API_KEY=your-key-here
37
37
  # or: export HUD_API_KEY=your-key-here
38
38
  ```
39
39
 
40
- Then scaffold your first environment:
40
+ Then start from the coding environment, or choose another example environment:
41
41
 
42
42
  ```bash
43
43
  hud init my-env
44
+ hud init my-desktop-env --template cua
45
+ hud init my-custom-env --template blank
44
46
  ```
45
47
 
46
48
  ![Agent running on SheetBench](docs/src/images/trace_sheet.gif)
@@ -80,16 +82,6 @@ hud sync tasks my-taskset
80
82
  hud eval my-taskset --remote
81
83
  ```
82
84
 
83
- For local iteration, the same protocol works against a container on your laptop:
84
-
85
- ```bash
86
- docker build -f Dockerfile.hud -t my-env .
87
- docker run -d --name run1 -p 8765:8765 my-env
88
- hud task start fix_bug --url tcp://127.0.0.1:8765
89
- hud task grade fix_bug --url tcp://127.0.0.1:8765 --answer "..."
90
- docker rm -f run1
91
- ```
92
-
93
85
  → [Run & deploy](https://docs.hud.ai/v6/reference/runtime)
94
86
 
95
87
  ## Environments & templates
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from hud.cli import main
5
+ from hud.cli.__main__ import main
6
6
 
7
7
  if __name__ == "__main__":
8
8
  main()
@@ -10,11 +10,7 @@ from typing import TYPE_CHECKING, Any, cast
10
10
  from hud.settings import settings
11
11
  from hud.types import AgentType
12
12
  from hud.utils.exceptions import HudAuthenticationError
13
- from hud.utils.gateway import (
14
- gateway_model_aliases,
15
- list_gateway_models,
16
- normalize_gateway_model_id,
17
- )
13
+ from hud.utils.gateway import resolve_gateway_model
18
14
 
19
15
  if TYPE_CHECKING:
20
16
  from typing import TypeAlias
@@ -31,10 +27,11 @@ if TYPE_CHECKING:
31
27
  def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
32
28
  """Create an agent routed through the HUD gateway.
33
29
 
34
- Leaves ``model_client`` unset so provider agent constructors build the HUD
35
- gateway client locally, while :class:`~hud.eval.runtime.HostedRuntime` can
36
- serialize the config and rebuild the client remotely. Explicitly supplied
37
- clients remain custom/BYOK and are not serializable.
30
+ Sets ``gateway=True`` on the config instead of attaching a client, so the
31
+ provider agent builds the gateway client locally and
32
+ :class:`~hud.eval.runtime.HostedRuntime` can serialize the config and rebuild
33
+ it remotely. Explicitly supplied clients remain custom/BYOK and are not
34
+ serializable.
38
35
 
39
36
  For direct API access with provider API keys, instantiate the agent classes
40
37
  directly.
@@ -49,72 +46,40 @@ def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
49
46
  if not settings.api_key:
50
47
  raise HudAuthenticationError("HUD_API_KEY is required to create a gateway agent")
51
48
 
52
- requested_model = model
53
- model = normalize_gateway_model_id(model)
54
- agent_type = next((candidate for candidate in AgentType if candidate.value == model), None)
55
- if agent_type is not None:
56
- model_id = model
57
- else:
58
- try:
59
- gateway_models = list_gateway_models()
60
- except Exception:
61
- gateway_models = []
62
- gateway_models = list(gateway_models)
63
- for gateway_model in gateway_models:
64
- if model in (
65
- gateway_model.id,
66
- gateway_model.name,
67
- gateway_model.model_name,
68
- ):
69
- agent_str = gateway_model.sdk_agent_type
70
- if agent_str == "operator":
71
- raise ValueError(
72
- "Operator agent is no longer supported; use openai with a supported "
73
- "OpenAI computer model."
74
- )
75
- if agent_str == "gemini_cua":
76
- raise ValueError(
77
- "Gemini CUA agent is no longer supported; use gemini with a supported "
78
- "Gemini computer-use model."
79
- )
80
- if not isinstance(agent_str, str):
81
- raise ValueError(f"Model '{model}' has invalid agent type metadata")
82
-
83
- try:
84
- agent_type = AgentType(agent_str)
85
- except ValueError as exc:
86
- raise ValueError(f"Model '{model}' has invalid agent type metadata") from exc
87
- model_id = gateway_model.model_name or model
88
- break
89
- else:
90
- import difflib
91
-
92
- known = [c.value for c in AgentType] + [
93
- n
94
- for gm in gateway_models
95
- for n in (gm.id, gm.name, gm.model_name)
96
- if isinstance(n, str)
97
- ]
98
- known.extend(gateway_model_aliases())
99
- near = difflib.get_close_matches(requested_model, known, n=3, cutoff=0.5)
100
- hint = (
101
- f" Did you mean: {', '.join(near)}?"
102
- if near
103
- else " Run `hud models` to list available models."
104
- )
105
- source = (
106
- "the HUD gateway registry"
107
- if gateway_models
108
- else "the HUD gateway registry (empty — is HUD_API_KEY set?)"
109
- )
110
- raise ValueError(f"Model {requested_model!r} not found in {source}.{hint}")
111
-
49
+ agent_type, model_id = resolve_agent_model(model)
112
50
  kwargs.setdefault("model", model_id)
51
+ kwargs["gateway"] = True
113
52
  # cls/config_cls are matched unions; the pairing is correct by construction.
114
53
  config = agent_type.config_cls(**kwargs)
115
54
  return agent_type.cls(cast("Any", config))
116
55
 
117
56
 
57
+ def resolve_agent_model(model: str) -> tuple[AgentType, str]:
58
+ """Resolve a catalog id/name/slug or an agent type without constructing a client."""
59
+ agent_type = next((candidate for candidate in AgentType if candidate.value == model), None)
60
+ if agent_type is not None:
61
+ return agent_type, model
62
+ try:
63
+ entry = resolve_gateway_model(model)
64
+ except HudAuthenticationError:
65
+ types = ", ".join(candidate.value for candidate in AgentType)
66
+ raise ValueError(
67
+ f"Resolving {model!r} needs the HUD model catalog; set HUD_API_KEY, or pass an "
68
+ f"agent type ({types}) and choose the model with its config."
69
+ ) from None
70
+ if entry.sdk_agent_type in ("operator", "gemini_cua"):
71
+ replacement = "openai" if entry.sdk_agent_type == "operator" else "gemini"
72
+ raise ValueError(
73
+ f"The {entry.sdk_agent_type} agent is no longer supported; use {replacement} with a "
74
+ "supported computer-use model."
75
+ )
76
+ try:
77
+ agent_type = AgentType(entry.sdk_agent_type)
78
+ except ValueError as exc:
79
+ raise ValueError(f"Model {model!r} has invalid agent type metadata") from exc
80
+ return agent_type, entry.model_name or model
81
+
82
+
118
83
  _LAZY_EXPORTS = {
119
84
  "ClaudeAgent": ("hud.agents.claude", "ClaudeAgent"),
120
85
  "ClaudeSDKAgent": ("hud.agents.claude", "ClaudeSDKAgent"),
@@ -134,6 +99,7 @@ __all__ = [
134
99
  "OpenAIAgent",
135
100
  "OpenAIChatAgent",
136
101
  "create_agent",
102
+ "resolve_agent_model",
137
103
  ]
138
104
 
139
105
 
@@ -38,7 +38,6 @@ from anthropic.types.beta import (
38
38
 
39
39
  from hud.agents.tool_agent import RunState, ToolAgent
40
40
  from hud.agents.types import AgentStep, Citation, ClaudeConfig, Usage
41
- from hud.settings import settings
42
41
  from hud.types import MCPToolCall, MCPToolResult
43
42
  from hud.utils import gateway
44
43
 
@@ -108,12 +107,11 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
108
107
  def _resolve_client(self) -> AsyncAnthropic | AsyncAnthropicBedrock:
109
108
  if self.config.model_client is not None:
110
109
  return cast("AsyncAnthropic | AsyncAnthropicBedrock", self.config.model_client)
111
- if settings.api_key:
112
- return cast("AsyncAnthropic", gateway.build_gateway_client("anthropic"))
113
- if settings.anthropic_api_key:
114
- return AsyncAnthropic(api_key=settings.anthropic_api_key)
115
- raise ValueError(
116
- "No API key found for Claude. Set HUD_API_KEY (gateway) or ANTHROPIC_API_KEY.",
110
+ return cast(
111
+ "AsyncAnthropic | AsyncAnthropicBedrock",
112
+ gateway.build_model_client(
113
+ "anthropic", model=self.config.model, gateway=self.config.gateway
114
+ ),
117
115
  )
118
116
 
119
117
  # ─── ToolAgent hooks ──────────────────────────────────────────────
@@ -403,6 +401,12 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
403
401
  if thinking_parts:
404
402
  result.reasoning = "\n".join(thinking_parts)
405
403
  result.finish_reason = response.stop_reason
404
+ if response.stop_reason == "refusal" and response.stop_details is not None:
405
+ explanation = response.stop_details.explanation
406
+ if explanation:
407
+ result.refusal = explanation
408
+ elif response.stop_details.category is not None:
409
+ result.refusal = f"This request was refused ({response.stop_details.category})."
406
410
  return result
407
411
 
408
412
  @staticmethod
@@ -10,6 +10,7 @@ Inspired by harbor-framework/harbor's ClaudeCode agent.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import base64
13
14
  import json
14
15
  import logging
15
16
  import shlex
@@ -20,6 +21,7 @@ from typing import TYPE_CHECKING, Any, cast
20
21
  from hud.agents.base import Agent
21
22
  from hud.agents.types import AgentStep, ClaudeSDKConfig, Usage
22
23
  from hud.settings import settings
24
+ from hud.telemetry.context import get_current_trace_id, get_trace_headers
23
25
  from hud.types import Step
24
26
 
25
27
  if TYPE_CHECKING:
@@ -83,6 +85,7 @@ class ClaudeSDKAgent(Agent):
83
85
 
84
86
  async def __call__(self, run: Run) -> None:
85
87
  mcp_servers: dict[str, dict[str, Any]] = {}
88
+ trace_id = get_current_trace_id()
86
89
  manifest = run.client.manifest
87
90
  bindings = manifest.bindings if manifest is not None else []
88
91
  families = {c.protocol.split("/", 1)[0] for c in bindings}
@@ -100,8 +103,11 @@ class ClaudeSDKAgent(Agent):
100
103
  token = cap.params.get("auth_token")
101
104
  transport = "http" if cap.params["transport"] == "streamable-http" else "sse"
102
105
  server_config: dict[str, Any] = {"type": transport, "url": cap.url}
106
+ headers = {"Trace-Id": trace_id} if trace_id is not None else {}
103
107
  if token:
104
- server_config["headers"] = {"Authorization": f"Bearer {token}"}
108
+ headers["Authorization"] = f"Bearer {token}"
109
+ if headers:
110
+ server_config["headers"] = headers
105
111
  if cap.name in mcp_servers:
106
112
  raise RuntimeError(f"duplicate MCP server name {cap.name!r}")
107
113
  mcp_servers[cap.name] = server_config
@@ -188,6 +194,11 @@ class ClaudeSDKAgent(Agent):
188
194
  if settings.api_key:
189
195
  env["ANTHROPIC_BASE_URL"] = settings.hud_gateway_url
190
196
  env["ANTHROPIC_API_KEY"] = settings.api_key
197
+ trace_headers = get_trace_headers()
198
+ if trace_headers:
199
+ env["ANTHROPIC_CUSTOM_HEADERS"] = "\n".join(
200
+ f"{name}: {value}" for name, value in trace_headers.items()
201
+ )
191
202
  elif settings.anthropic_api_key:
192
203
  env["ANTHROPIC_API_KEY"] = settings.anthropic_api_key
193
204
 
@@ -259,16 +270,18 @@ class ClaudeSDKAgent(Agent):
259
270
  # Solution: use `cmd /c claude [args]` (no inline prompt) and feed the
260
271
  # prompt via stdin from .hud_prompt.txt. claude --print reads stdin as
261
272
  # the initial message when no -- argument is provided.
262
- set_parts = [f"set {k}={v}" for k, v in env_vars.items()]
263
273
  cmd_args = ["cmd", "/c", "claude"] + base_args[1:] # noqa: RUF005
264
274
  py_args_repr = "[" + ",".join(f"'{a}'" for a in cmd_args) + "]"
275
+ encoded_env = base64.b64encode(json.dumps(env_vars).encode()).decode()
265
276
  python_launcher = (
266
277
  'python -c "'
267
- "import subprocess,sys;"
268
- f"r=subprocess.run({py_args_repr},stdin=open('.hud_prompt.txt','rb'));"
278
+ "import base64,json,os,subprocess,sys;"
279
+ "env=os.environ.copy();"
280
+ f"env.update(json.loads(base64.b64decode('{encoded_env}')));"
281
+ f"r=subprocess.run({py_args_repr},stdin=open('.hud_prompt.txt','rb'),env=env);"
269
282
  'sys.exit(r.returncode)"'
270
283
  )
271
- return " && ".join([*set_parts, python_launcher])
284
+ return python_launcher
272
285
 
273
286
  # POSIX path: shell-quote everything and embed prompt inline.
274
287
  cli_parts = [shlex.quote(a) for a in base_args]
@@ -4,18 +4,19 @@ from __future__ import annotations
4
4
 
5
5
  import base64
6
6
  import logging
7
- from typing import Any, cast
7
+ from typing import TYPE_CHECKING, Any, cast
8
8
 
9
9
  import mcp.types as mcp_types
10
- from google import genai
11
10
  from google.genai import types as genai_types
12
11
 
13
12
  from hud.agents.tool_agent import RunState, ToolAgent
14
13
  from hud.agents.types import AgentStep, Citation, GeminiConfig, Usage
15
- from hud.settings import settings
16
14
  from hud.types import MCPToolCall, MCPToolResult
17
15
  from hud.utils import gateway
18
16
 
17
+ if TYPE_CHECKING:
18
+ from google import genai
19
+
19
20
  from .settings import gemini_agent_settings
20
21
  from .tools import (
21
22
  PREDEFINED_COMPUTER_USE_FUNCTIONS,
@@ -54,14 +55,7 @@ class GeminiAgent(ToolAgent[genai_types.Content, GeminiConfig]):
54
55
 
55
56
  model_client = config.model_client
56
57
  if model_client is None:
57
- if settings.api_key:
58
- model_client = gateway.build_gateway_client("gemini")
59
- elif settings.gemini_api_key:
60
- model_client = genai.Client(api_key=settings.gemini_api_key)
61
- else:
62
- raise ValueError(
63
- "No API key for Gemini. Set HUD_API_KEY or GEMINI_API_KEY.",
64
- )
58
+ model_client = gateway.build_model_client("gemini", gateway=config.gateway)
65
59
 
66
60
  self.gemini_client: genai.Client = cast("genai.Client", model_client)
67
61
  self.temperature = config.temperature
@@ -24,9 +24,9 @@ from openai.types.responses.response_input_param import (
24
24
  )
25
25
  from openai.types.shared_params.reasoning import Reasoning # noqa: TC002
26
26
 
27
- from hud.agents.tool_agent import RunState, ToolAgent
27
+ from hud.agents.tool_agent import DegenerateTurnError, RunState, ToolAgent
28
+ from hud.agents.tools.base import result_text
28
29
  from hud.agents.types import AgentStep, Citation, OpenAIConfig, Usage
29
- from hud.settings import settings
30
30
  from hud.types import MCPToolCall, MCPToolResult
31
31
  from hud.utils import gateway
32
32
 
@@ -41,6 +41,16 @@ if TYPE_CHECKING:
41
41
  logger = logging.getLogger(__name__)
42
42
 
43
43
 
44
+ class EmptyShellCallError(DegenerateTurnError):
45
+ """The model emitted a shell_call with an empty ``commands`` array.
46
+
47
+ OpenAI stores such a turn but returns 500 for every request that continues
48
+ from it via ``previous_response_id``. The turn is rejected before its
49
+ response id is committed, so the run state still points at the last
50
+ healthy response and the next sample continues from there.
51
+ """
52
+
53
+
44
54
  @dataclass
45
55
  class OpenAIRunState(RunState[ResponseInputItemParam]):
46
56
  last_response_id: str | None = None
@@ -62,14 +72,7 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
62
72
 
63
73
  model_client = config.model_client
64
74
  if model_client is None:
65
- if settings.api_key:
66
- model_client = gateway.build_gateway_client("openai")
67
- elif settings.openai_api_key:
68
- model_client = AsyncOpenAI(api_key=settings.openai_api_key)
69
- else:
70
- raise ValueError(
71
- "No API key for OpenAI. Set HUD_API_KEY or OPENAI_API_KEY.",
72
- )
75
+ model_client = gateway.build_model_client("openai", gateway=config.gateway)
73
76
 
74
77
  self.openai_client: AsyncOpenAI = cast("AsyncOpenAI", model_client)
75
78
  self._model = config.model
@@ -106,8 +109,10 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
106
109
  if isinstance(tool, OpenAIComputerTool):
107
110
  screenshot = last_image_content(result)
108
111
  if screenshot is None:
109
- logger.warning("Computer tool result missing screenshot for call %s", call.name)
110
- return None
112
+ raise RuntimeError(
113
+ f"Computer tool result missing screenshot for call {call.id}: "
114
+ f"{result_text(result)}"
115
+ )
111
116
  output = ComputerCallOutput(
112
117
  type="computer_call_output",
113
118
  call_id=call.id,
@@ -132,7 +137,17 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
132
137
  acknowledged.append(raw_check)
133
138
  if acknowledged:
134
139
  output["acknowledged_safety_checks"] = acknowledged
135
- return cast("ResponseInputItemParam", output)
140
+ if result.isError:
141
+ return [
142
+ output,
143
+ self._format_message(
144
+ "user",
145
+ f"Computer call {call.id} stopped with an error. "
146
+ "Remaining actions in this call were not executed.\n"
147
+ f"{result_text(result)}",
148
+ ),
149
+ ]
150
+ return output
136
151
 
137
152
  if isinstance(tool, OpenAIShellTool):
138
153
  structured = (
@@ -140,8 +155,6 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
140
155
  )
141
156
  output_list = structured.get("output")
142
157
  if not isinstance(output_list, list):
143
- from hud.agents.tools.base import result_text
144
-
145
158
  text = result_text(result)
146
159
  output_list = [shell_output("", text, 1 if result.isError else 0)]
147
160
  response: dict[str, Any] = {
@@ -223,10 +236,23 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
223
236
  previous_response_id=(
224
237
  oai_state.last_response_id if oai_state.last_response_id is not None else Omit()
225
238
  ),
239
+ prompt_cache_key=self.config.prompt_cache_key,
226
240
  truncation=self.truncation if self.truncation is not None else Omit(),
227
241
  include=include_param,
228
242
  )
229
243
 
244
+ empty_shell_calls = [
245
+ item.call_id
246
+ for item in response.output
247
+ if item.type == "shell_call" and item.action.to_dict().get("commands") == []
248
+ ]
249
+ if empty_shell_calls:
250
+ raise EmptyShellCallError(
251
+ f"Model emitted shell_call(s) with an empty commands array "
252
+ f"({', '.join(empty_shell_calls)}); continuing from response {response.id} "
253
+ "would fail with OpenAI 500s, so it was not committed to the run state."
254
+ )
255
+
230
256
  oai_state.last_response_id = response.id
231
257
  oai_state.message_cursor = len(messages)
232
258
 
@@ -290,7 +316,7 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
290
316
  elif item.action is not None:
291
317
  arguments = item.action.to_dict()
292
318
  else:
293
- raise ValueError("OpenAI computer_call missing action")
319
+ arguments = {"actions": []}
294
320
  call_dict: dict[str, Any] = {
295
321
  "name": "computer",
296
322
  "arguments": arguments,
@@ -335,4 +361,4 @@ class OpenAIAgent(ToolAgent[ResponseInputItemParam, OpenAIConfig]):
335
361
  )
336
362
 
337
363
 
338
- __all__ = ["OpenAIAgent"]
364
+ __all__ = ["EmptyShellCallError", "OpenAIAgent"]