hud 0.6.12.dev0__tar.gz → 0.6.13.dev2__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 (311) hide show
  1. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/.gitignore +1 -0
  2. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/PKG-INFO +27 -7
  3. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/README.md +16 -1
  4. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/__init__.py +2 -8
  5. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/__init__.py +19 -5
  6. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/browser_use/agent.py +49 -11
  7. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/agent.py +2 -2
  8. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/agent.py +2 -2
  9. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/computer_mcp.py +15 -4
  10. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/computer.py +14 -6
  11. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/tests/test_computer.py +73 -9
  12. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/tests/test_computer.py +28 -9
  13. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/misc/response_automation.py +0 -1
  14. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/agent.py +6 -4
  15. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/apply_patch.py +0 -1
  16. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/base.py +1 -2
  17. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/coding.py +60 -17
  18. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/computer.py +9 -3
  19. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/test_computer.py +33 -9
  20. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/base.py +1 -12
  21. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/filesystem.py +2 -9
  22. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/mcp_proxy.py +1 -1
  23. hud-0.6.13.dev2/hud/agents/robot/__init__.py +39 -0
  24. hud-0.6.13.dev2/hud/agents/robot/adapter.py +132 -0
  25. hud-0.6.13.dev2/hud/agents/robot/agent.py +174 -0
  26. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/robot/batching.py +23 -26
  27. hud-0.6.13.dev2/hud/agents/robot/dataset.py +243 -0
  28. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/robot/model.py +1 -1
  29. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_apply_patch.py +0 -1
  30. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_base.py +43 -7
  31. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_claude_agent.py +0 -1
  32. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_claude_sdk_agent.py +92 -3
  33. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_gemini_agent.py +0 -1
  34. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_openai_agent.py +37 -1
  35. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_openai_compatible_agent.py +0 -1
  36. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_provider_native_tools.py +164 -41
  37. hud-0.6.13.dev2/hud/agents/tests/test_robot_dataset_writer.py +162 -0
  38. hud-0.6.13.dev2/hud/agents/tests/test_tool_agent.py +513 -0
  39. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tool_agent.py +47 -14
  40. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/base.py +21 -1
  41. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/mcp.py +5 -3
  42. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/rfb.py +17 -5
  43. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/ssh.py +22 -6
  44. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/types.py +16 -4
  45. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/base.py +38 -12
  46. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/mcp.py +9 -4
  47. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/rfb.py +45 -7
  48. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/robot.py +44 -19
  49. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/ssh.py +7 -32
  50. hud-0.6.13.dev2/hud/capabilities/tests/test_rfb.py +76 -0
  51. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/__init__.py +5 -12
  52. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/cancel.py +4 -2
  53. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/deploy.py +16 -19
  54. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/eval.py +3 -2
  55. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/serve.py +17 -23
  56. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_init.py +0 -11
  57. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_deploy.py +24 -10
  58. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_eval_config.py +20 -1
  59. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/trace.py +11 -8
  60. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/source.py +36 -46
  61. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_registry.py +3 -3
  62. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_source.py +29 -12
  63. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_tasks.py +5 -5
  64. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_version_check.py +3 -15
  65. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/version_check.py +2 -34
  66. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/client.py +176 -105
  67. hud-0.6.13.dev2/hud/clients/tests/test_connect.py +213 -0
  68. hud-0.6.13.dev2/hud/environment/__init__.py +98 -0
  69. hud-0.6.13.dev2/hud/environment/egress.py +653 -0
  70. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/env.py +50 -26
  71. hud-0.6.13.dev2/hud/environment/namespace.py +605 -0
  72. hud-0.6.13.dev2/hud/environment/robot/__init__.py +38 -0
  73. hud-0.6.13.dev2/hud/environment/robot/bridge.py +620 -0
  74. hud-0.6.13.dev2/hud/environment/robot/endpoint.py +350 -0
  75. hud-0.6.13.dev2/hud/environment/robot/gym.py +726 -0
  76. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/server.py +184 -89
  77. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_capability_backing.py +185 -9
  78. hud-0.6.13.dev2/hud/environment/tests/test_loader.py +169 -0
  79. hud-0.6.13.dev2/hud/environment/tests/test_robot_regressions.py +505 -0
  80. hud-0.6.13.dev2/hud/environment/tests/test_sessions.py +89 -0
  81. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_tunnel.py +23 -11
  82. hud-0.6.13.dev2/hud/environment/tests/test_workspace.py +1391 -0
  83. hud-0.6.13.dev2/hud/environment/workspace.py +1696 -0
  84. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/__init__.py +2 -0
  85. hud-0.6.13.dev2/hud/eval/_runtime_protocols.py +212 -0
  86. hud-0.6.13.dev2/hud/eval/compose.py +172 -0
  87. hud-0.6.13.dev2/hud/eval/docker-seccomp.json +21 -0
  88. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/job.py +37 -6
  89. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/run.py +234 -89
  90. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/runtime.py +572 -125
  91. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/sync.py +6 -1
  92. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/task.py +30 -12
  93. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/taskset.py +58 -30
  94. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_chat.py +0 -4
  95. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_docker_provider.py +569 -26
  96. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_file_tracking_observer.py +8 -6
  97. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_hosted.py +159 -9
  98. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_job.py +48 -0
  99. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_local_runtime.py +42 -0
  100. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_rollout.py +475 -9
  101. hud-0.6.13.dev2/hud/eval/tests/test_shared.py +178 -0
  102. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_sync.py +28 -4
  103. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_task.py +98 -9
  104. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/bash.py +17 -15
  105. hud-0.6.13.dev2/hud/integrations/__init__.py +1 -0
  106. hud-0.6.13.dev2/hud/integrations/harbor/Dockerfile +25 -0
  107. hud-0.6.13.dev2/hud/integrations/harbor/__init__.py +12 -0
  108. hud-0.6.13.dev2/hud/integrations/harbor/adapt.py +734 -0
  109. hud-0.6.13.dev2/hud/integrations/harbor/env.py +678 -0
  110. hud-0.6.13.dev2/hud/integrations/harbor/export.py +233 -0
  111. hud-0.6.13.dev2/hud/integrations/harbor/install.sh +32 -0
  112. hud-0.6.13.dev2/hud/integrations/harbor/tests/conftest.py +135 -0
  113. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +5 -0
  114. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +1 -0
  115. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +6 -0
  116. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +10 -0
  117. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +15 -0
  118. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +9 -0
  119. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/compose.yaml +17 -0
  120. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +6 -0
  121. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +13 -0
  122. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +1 -0
  123. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +3 -0
  124. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +10 -0
  125. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +9 -0
  126. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +6 -0
  127. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +7 -0
  128. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +13 -0
  129. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +49 -0
  130. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +31 -0
  131. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +33 -0
  132. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +5 -0
  133. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/compose.yaml +11 -0
  134. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +1 -0
  135. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +26 -0
  136. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +26 -0
  137. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +14 -0
  138. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +19 -0
  139. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +5 -0
  140. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +7 -0
  141. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +1 -0
  142. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +4 -0
  143. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +17 -0
  144. hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +20 -0
  145. hud-0.6.13.dev2/hud/integrations/harbor/tests/test_contract.py +896 -0
  146. hud-0.6.13.dev2/hud/integrations/harbor/tests/test_harbor.py +267 -0
  147. hud-0.6.13.dev2/hud/integrations/harbor/tests/test_integration.py +339 -0
  148. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/mcp_patches.py +4 -4
  149. hud-0.6.13.dev2/hud/py.typed +0 -0
  150. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/instrument.py +11 -3
  151. hud-0.6.13.dev2/hud/telemetry/robot/__init__.py +12 -0
  152. hud-0.6.13.dev2/hud/telemetry/robot/recorder.py +313 -0
  153. hud-0.6.13.dev2/hud/telemetry/tests/__init__.py +0 -0
  154. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/tests/test_instrument.py +2 -2
  155. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/client.py +49 -6
  156. hud-0.6.13.dev2/hud/train/tests/__init__.py +1 -0
  157. hud-0.6.13.dev2/hud/train/tests/test_client.py +86 -0
  158. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/types.py +2 -2
  159. hud-0.6.13.dev2/hud/utils/docker.py +32 -0
  160. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/gateway.py +33 -3
  161. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/hints.py +2 -1
  162. hud-0.6.13.dev2/hud/utils/naming.py +19 -0
  163. hud-0.6.13.dev2/hud/utils/process.py +224 -0
  164. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/serialization.py +1 -1
  165. hud-0.6.13.dev2/hud/utils/tests/__init__.py +0 -0
  166. hud-0.6.13.dev2/hud/utils/tests/test_gateway.py +160 -0
  167. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_platform.py +5 -1
  168. hud-0.6.13.dev2/hud/utils/tests/test_process.py +110 -0
  169. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/version.py +1 -1
  170. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/pyproject.toml +32 -25
  171. hud-0.6.12.dev0/hud/_legacy.py +0 -300
  172. hud-0.6.12.dev0/hud/agents/robot/__init__.py +0 -41
  173. hud-0.6.12.dev0/hud/agents/robot/_types.py +0 -12
  174. hud-0.6.12.dev0/hud/agents/robot/adapter.py +0 -105
  175. hud-0.6.12.dev0/hud/agents/robot/agent.py +0 -169
  176. hud-0.6.12.dev0/hud/agents/robot/record.py +0 -230
  177. hud-0.6.12.dev0/hud/agents/tests/test_tool_agent.py +0 -242
  178. hud-0.6.12.dev0/hud/clients/tests/test_connect.py +0 -111
  179. hud-0.6.12.dev0/hud/environment/__init__.py +0 -58
  180. hud-0.6.12.dev0/hud/environment/legacy.py +0 -364
  181. hud-0.6.12.dev0/hud/environment/robot/__init__.py +0 -29
  182. hud-0.6.12.dev0/hud/environment/robot/bridge.py +0 -176
  183. hud-0.6.12.dev0/hud/environment/robot/endpoint.py +0 -210
  184. hud-0.6.12.dev0/hud/environment/robot/sim_runner.py +0 -111
  185. hud-0.6.12.dev0/hud/environment/tests/test_legacy.py +0 -273
  186. hud-0.6.12.dev0/hud/environment/tests/test_loader.py +0 -31
  187. hud-0.6.12.dev0/hud/environment/tests/test_workspace.py +0 -244
  188. hud-0.6.12.dev0/hud/environment/workspace.py +0 -724
  189. hud-0.6.12.dev0/hud/server.py +0 -32
  190. hud-0.6.12.dev0/hud/utils/process.py +0 -130
  191. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/LICENSE +0 -0
  192. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/__main__.py +0 -0
  193. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/base.py +0 -0
  194. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/browser_use/__init__.py +0 -0
  195. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/__init__.py +0 -0
  196. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/__init__.py +0 -0
  197. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/__init__.py +0 -0
  198. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/base.py +0 -0
  199. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/coding.py +0 -0
  200. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/hosted.py +0 -0
  201. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/mcp_proxy.py +0 -0
  202. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/settings.py +0 -0
  203. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/tests/__init__.py +0 -0
  204. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/__init__.py +0 -0
  205. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/agent.py +0 -0
  206. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/settings.py +0 -0
  207. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/__init__.py +0 -0
  208. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/base.py +0 -0
  209. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/coding.py +0 -0
  210. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/computer.py +0 -0
  211. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/filesystem.py +0 -0
  212. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/hosted.py +0 -0
  213. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
  214. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/tests/__init__.py +0 -0
  215. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/misc/__init__.py +0 -0
  216. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/__init__.py +0 -0
  217. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/__init__.py +0 -0
  218. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/hosted.py +0 -0
  219. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/mcp_proxy.py +0 -0
  220. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/strict_schema.py +0 -0
  221. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/__init__.py +0 -0
  222. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
  223. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/__init__.py +0 -0
  224. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/agent.py +0 -0
  225. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/__init__.py +0 -0
  226. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/__init__.py +0 -0
  227. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_trace.py +0 -0
  228. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/__init__.py +0 -0
  229. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/hosted.py +0 -0
  230. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/__init__.py +0 -0
  231. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/cdp.py +0 -0
  232. {hud-0.6.12.dev0/hud/cli/utils → hud-0.6.13.dev2/hud/capabilities}/tests/__init__.py +0 -0
  233. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/__main__.py +0 -0
  234. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/client.py +0 -0
  235. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/init.py +0 -0
  236. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/jobs.py +0 -0
  237. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/login.py +0 -0
  238. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/models.py +0 -0
  239. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/presets.py +0 -0
  240. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/sync.py +0 -0
  241. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/task.py +0 -0
  242. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/templates.py +0 -0
  243. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/__init__.py +0 -0
  244. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_main.py +0 -0
  245. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
  246. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_eval_bedrock.py +0 -0
  247. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_init.py +0 -0
  248. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_main_module.py +0 -0
  249. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_sync_export.py +0 -0
  250. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/__init__.py +0 -0
  251. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/api.py +0 -0
  252. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/build_display.py +0 -0
  253. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/build_logs.py +0 -0
  254. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/config.py +0 -0
  255. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/context.py +0 -0
  256. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/display.py +0 -0
  257. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/jobs.py +0 -0
  258. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/registry.py +0 -0
  259. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tasks.py +0 -0
  260. {hud-0.6.12.dev0/hud/environment → hud-0.6.13.dev2/hud/cli/utils}/tests/__init__.py +0 -0
  261. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_build_display.py +0 -0
  262. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_config.py +0 -0
  263. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_context.py +0 -0
  264. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/__init__.py +0 -0
  265. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/tests/__init__.py +0 -0
  266. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/conftest.py +0 -0
  267. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/file_tracker.py +0 -0
  268. {hud-0.6.12.dev0/hud/eval → hud-0.6.13.dev2/hud/environment}/tests/__init__.py +0 -0
  269. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/conftest.py +0 -0
  270. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_file_tracker.py +0 -0
  271. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_file_tracking.py +0 -0
  272. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_manifest.py +0 -0
  273. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_server.py +0 -0
  274. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/utils.py +0 -0
  275. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/chat.py +0 -0
  276. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/file_tracking.py +0 -0
  277. {hud-0.6.12.dev0/hud/telemetry → hud-0.6.13.dev2/hud/eval}/tests/__init__.py +0 -0
  278. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/__init__.py +0 -0
  279. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/base.py +0 -0
  280. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/combine.py +0 -0
  281. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/judge.py +0 -0
  282. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/results.py +0 -0
  283. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/text.py +0 -0
  284. {hud-0.6.12.dev0/hud/utils → hud-0.6.13.dev2/hud/integrations/harbor}/tests/__init__.py +0 -0
  285. /hud-0.6.12.dev0/hud/py.typed → /hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/__init__.py +0 -0
  286. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/__init__.py +0 -0
  287. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/tests/__init__.py +0 -0
  288. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/tests/test_warnings.py +0 -0
  289. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/warnings.py +0 -0
  290. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/settings.py +0 -0
  291. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/__init__.py +0 -0
  292. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/context.py +0 -0
  293. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/exporter.py +0 -0
  294. {hud-0.6.12.dev0/hud/agents → hud-0.6.13.dev2/hud/telemetry}/robot/video.py +0 -0
  295. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/span.py +0 -0
  296. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/tests/test_exporter.py +0 -0
  297. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/__init__.py +0 -0
  298. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/base.py +0 -0
  299. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/types.py +0 -0
  300. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/__init__.py +0 -0
  301. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/exceptions.py +0 -0
  302. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/hud_console.py +0 -0
  303. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/modules.py +0 -0
  304. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/platform.py +0 -0
  305. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/requests.py +0 -0
  306. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_exceptions.py +0 -0
  307. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_hints.py +0 -0
  308. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_hud_console.py +0 -0
  309. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_requests.py +0 -0
  310. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_serialization.py +0 -0
  311. {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/time.py +0 -0
@@ -56,6 +56,7 @@ hud/rl/checkpoints_test/
56
56
 
57
57
  .ck/
58
58
 
59
+ .hud/
59
60
  .hud_eval_config
60
61
  .hud_eval.toml
61
62
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hud
3
- Version: 0.6.12.dev0
3
+ Version: 0.6.13.dev2
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
@@ -37,16 +37,16 @@ Requires-Python: <3.13,>=3.11
37
37
  Requires-Dist: anthropic>=0.78.0
38
38
  Requires-Dist: asyncssh>=2.23.0
39
39
  Requires-Dist: asyncvnc>=1.3.0
40
- Requires-Dist: fastmcp==3.0.2
40
+ Requires-Dist: fastmcp==3.2.0
41
41
  Requires-Dist: google-genai
42
42
  Requires-Dist: httpx<1,>=0.23.0
43
43
  Requires-Dist: mcp<2.0,>=1.24.0
44
- Requires-Dist: openai==2.44.0
44
+ Requires-Dist: openai>=2.45.0
45
45
  Requires-Dist: packaging>=21.0
46
46
  Requires-Dist: pillow>=11.0.0
47
47
  Requires-Dist: prompt-toolkit==3.0.51
48
48
  Requires-Dist: pydantic-settings<3,>=2.2
49
- Requires-Dist: pydantic<3,>=2.6
49
+ Requires-Dist: pydantic<3,>=2.10
50
50
  Requires-Dist: questionary==2.1.0
51
51
  Requires-Dist: rich>=13.0.0
52
52
  Requires-Dist: typer>=0.9.0
@@ -60,17 +60,22 @@ Requires-Dist: browser-use>=0.11.13; extra == 'browseruse'
60
60
  Provides-Extra: daytona
61
61
  Requires-Dist: daytona>=0.100; extra == 'daytona'
62
62
  Provides-Extra: dev
63
+ Requires-Dist: av>=12; extra == 'dev'
63
64
  Requires-Dist: dotenv>=0.9.9; extra == 'dev'
64
- Requires-Dist: pyright==1.1.407; extra == 'dev'
65
+ Requires-Dist: gymnasium>=1.0; extra == 'dev'
66
+ Requires-Dist: numpy>=1.24; extra == 'dev'
67
+ Requires-Dist: openpi-client>=0.1.2; extra == 'dev'
65
68
  Requires-Dist: pytest-asyncio; extra == 'dev'
66
69
  Requires-Dist: pytest-cov; extra == 'dev'
67
70
  Requires-Dist: pytest-mock; extra == 'dev'
68
71
  Requires-Dist: pytest>=8.1.1; extra == 'dev'
69
- Requires-Dist: ruff<0.15.0,>=0.11.8; extra == 'dev'
72
+ Requires-Dist: ruff==0.16.1; extra == 'dev'
73
+ Requires-Dist: ty==0.0.67; extra == 'dev'
70
74
  Provides-Extra: modal
71
75
  Requires-Dist: modal>=1.0; extra == 'modal'
72
76
  Provides-Extra: robot
73
77
  Requires-Dist: av>=12; extra == 'robot'
78
+ Requires-Dist: gymnasium>=1.0; extra == 'robot'
74
79
  Requires-Dist: numpy>=1.24; extra == 'robot'
75
80
  Requires-Dist: openpi-client>=0.1.2; extra == 'robot'
76
81
  Provides-Extra: train
@@ -180,11 +185,13 @@ from hud import Environment
180
185
 
181
186
  env = Environment(name="letter-count")
182
187
 
188
+
183
189
  @env.template()
184
190
  async def count_letter(word: str = "strawberry", letter: str = "r"):
185
191
  answer = yield f"How many '{letter}'s are in '{word}'? Reply with just the number."
186
192
  yield 1.0 if answer and str(word.count(letter)) in answer else 0.0
187
193
 
194
+
188
195
  tasks = [count_letter(word=w) for w in ("strawberry", "raspberry", "blueberry")]
189
196
  ```
190
197
 
@@ -198,6 +205,19 @@ Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `
198
205
 
199
206
  → [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/reference/tasks)
200
207
 
208
+ ## Existing benchmarks
209
+
210
+ The experimental `hud.integrations.harbor` adapter turns Harbor task directories into runnable HUD
211
+ tasksets and can export authored HUD tasks back to Harbor folders.
212
+
213
+ ```python
214
+ from hud.integrations import harbor
215
+
216
+ taskset = await harbor.adapt("./benchmark")
217
+ ```
218
+
219
+ → [Harbor interop](https://docs.hud.ai/v6/advanced/harbor-convert)
220
+
201
221
  ## Capabilities & harnesses
202
222
 
203
223
  A **capability** is a connection the environment exposes; a **harness** attaches its own tools to it. The same environment serves a one-shot Q&A or a full computer-use rollout, depending on which capabilities the harness opens.
@@ -264,7 +284,7 @@ Building agents at scale? We work with teams on custom environments, benchmarks,
264
284
 
265
285
  We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md).
266
286
 
267
- Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabilities](hud/capabilities/) · [Eval](hud/eval/)
287
+ Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabilities](hud/capabilities/) · [Eval](hud/eval/) · [Integrations](hud/integrations/)
268
288
 
269
289
  <a href="https://github.com/hud-evals/hud-python/graphs/contributors">
270
290
  <img src="https://contrib.rocks/image?repo=hud-evals/hud-python&max=50" />
@@ -101,11 +101,13 @@ from hud import Environment
101
101
 
102
102
  env = Environment(name="letter-count")
103
103
 
104
+
104
105
  @env.template()
105
106
  async def count_letter(word: str = "strawberry", letter: str = "r"):
106
107
  answer = yield f"How many '{letter}'s are in '{word}'? Reply with just the number."
107
108
  yield 1.0 if answer and str(word.count(letter)) in answer else 0.0
108
109
 
110
+
109
111
  tasks = [count_letter(word=w) for w in ("strawberry", "raspberry", "blueberry")]
110
112
  ```
111
113
 
@@ -119,6 +121,19 @@ Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `
119
121
 
120
122
  → [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/reference/tasks)
121
123
 
124
+ ## Existing benchmarks
125
+
126
+ The experimental `hud.integrations.harbor` adapter turns Harbor task directories into runnable HUD
127
+ tasksets and can export authored HUD tasks back to Harbor folders.
128
+
129
+ ```python
130
+ from hud.integrations import harbor
131
+
132
+ taskset = await harbor.adapt("./benchmark")
133
+ ```
134
+
135
+ → [Harbor interop](https://docs.hud.ai/v6/advanced/harbor-convert)
136
+
122
137
  ## Capabilities & harnesses
123
138
 
124
139
  A **capability** is a connection the environment exposes; a **harness** attaches its own tools to it. The same environment serves a one-shot Q&A or a full computer-use rollout, depending on which capabilities the harness opens.
@@ -185,7 +200,7 @@ Building agents at scale? We work with teams on custom environments, benchmarks,
185
200
 
186
201
  We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md).
187
202
 
188
- Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabilities](hud/capabilities/) · [Eval](hud/eval/)
203
+ Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabilities](hud/capabilities/) · [Eval](hud/eval/) · [Integrations](hud/integrations/)
189
204
 
190
205
  <a href="https://github.com/hud-evals/hud-python/graphs/contributors">
191
206
  <img src="https://contrib.rocks/image?repo=hud-evals/hud-python&max=50" />
@@ -7,7 +7,6 @@ from __future__ import annotations
7
7
 
8
8
  # Apply patches to third-party libraries early, before other imports
9
9
  from . import patches as _patches # noqa: F401
10
- from ._legacy import install as _install_v5_compat
11
10
  from .clients import connect
12
11
  from .environment import Environment
13
12
  from .eval import (
@@ -32,8 +31,7 @@ from .eval import (
32
31
  from .telemetry.instrument import instrument
33
32
  from .train import TrainingClient
34
33
  from .types import Trace
35
-
36
- _install_v5_compat()
34
+ from .version import __version__
37
35
 
38
36
  __all__ = [
39
37
  "Chat",
@@ -56,11 +54,7 @@ __all__ = [
56
54
  "Taskset",
57
55
  "Trace",
58
56
  "TrainingClient",
57
+ "__version__",
59
58
  "connect",
60
59
  "instrument",
61
60
  ]
62
-
63
- try:
64
- from .version import __version__
65
- except ImportError:
66
- __version__ = "unknown"
@@ -7,9 +7,10 @@ from __future__ import annotations
7
7
 
8
8
  from typing import TYPE_CHECKING, Any, cast
9
9
 
10
+ from hud.settings import settings
10
11
  from hud.types import AgentType
12
+ from hud.utils.exceptions import HudAuthenticationError
11
13
  from hud.utils.gateway import (
12
- build_gateway_client,
13
14
  gateway_model_aliases,
14
15
  list_gateway_models,
15
16
  normalize_gateway_model_id,
@@ -30,14 +31,29 @@ if TYPE_CHECKING:
30
31
  def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
31
32
  """Create an agent routed through the HUD gateway.
32
33
 
33
- For direct API access with provider API keys, instantiate the agent classes directly.
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.
38
+
39
+ For direct API access with provider API keys, instantiate the agent classes
40
+ directly.
34
41
  """
42
+ direct_credentials = [name for name in ("api_key", "base_url") if name in kwargs]
43
+ if direct_credentials:
44
+ names = ", ".join(direct_credentials)
45
+ raise ValueError(
46
+ f"create_agent routes through the HUD gateway and does not accept {names}; "
47
+ "instantiate the provider agent directly for custom/BYOK credentials"
48
+ )
49
+ if not settings.api_key:
50
+ raise HudAuthenticationError("HUD_API_KEY is required to create a gateway agent")
51
+
35
52
  requested_model = model
36
53
  model = normalize_gateway_model_id(model)
37
54
  agent_type = next((candidate for candidate in AgentType if candidate.value == model), None)
38
55
  if agent_type is not None:
39
56
  model_id = model
40
- provider_name = agent_type.gateway_provider
41
57
  else:
42
58
  try:
43
59
  gateway_models = list_gateway_models()
@@ -69,7 +85,6 @@ def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
69
85
  except ValueError as exc:
70
86
  raise ValueError(f"Model '{model}' has invalid agent type metadata") from exc
71
87
  model_id = gateway_model.model_name or model
72
- provider_name = gateway_model.provider.name or "openai"
73
88
  break
74
89
  else:
75
90
  import difflib
@@ -95,7 +110,6 @@ def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
95
110
  raise ValueError(f"Model {requested_model!r} not found in {source}.{hint}")
96
111
 
97
112
  kwargs.setdefault("model", model_id)
98
- kwargs.setdefault("model_client", build_gateway_client(provider_name))
99
113
  # cls/config_cls are matched unions; the pairing is correct by construction.
100
114
  config = agent_type.config_cls(**kwargs)
101
115
  return agent_type.cls(cast("Any", config))
@@ -15,13 +15,10 @@ optional dependency
15
15
 
16
16
  from __future__ import annotations
17
17
 
18
- # browser-use is an optional, untyped dependency (lazy __getattr__ exports), so
19
- # its symbols and members resolve as Unknown under strict checking. This whole
20
- # module is the boundary around that SDK; contain the unknowns here.
21
- # pyright: reportAttributeAccessIssue=false, reportUnknownVariableType=false, reportUnknownMemberType=false
22
18
  import contextlib
19
+ import importlib
23
20
  import logging
24
- from typing import TYPE_CHECKING, Any, cast
21
+ from typing import TYPE_CHECKING, Protocol, cast
25
22
  from urllib.parse import urlsplit, urlunsplit
26
23
 
27
24
  from hud.agents.base import Agent
@@ -37,6 +34,44 @@ LOGGER = logging.getLogger("hud.agents.browser_use")
37
34
  CDP_PROTOCOL = "cdp/1.3"
38
35
 
39
36
 
37
+ class _Browser(Protocol):
38
+ async def stop(self) -> None: ...
39
+
40
+
41
+ class _History(Protocol):
42
+ def is_successful(self) -> bool | None: ...
43
+
44
+ def final_result(self) -> str | None: ...
45
+
46
+ def number_of_steps(self) -> int: ...
47
+
48
+ def urls(self) -> list[str]: ...
49
+
50
+ def is_done(self) -> bool: ...
51
+
52
+
53
+ class _BrowserAgent(Protocol):
54
+ async def run(self, *, max_steps: int) -> _History: ...
55
+
56
+
57
+ class _ChatAnthropicFactory(Protocol):
58
+ def __call__(self, *, model: str, api_key: str, base_url: str | None) -> object: ...
59
+
60
+
61
+ class _BrowserFactory(Protocol):
62
+ def __call__(self, *, cdp_url: str) -> _Browser: ...
63
+
64
+
65
+ class _AgentFactory(Protocol):
66
+ def __call__(self, *, task: str, llm: object, browser: _Browser) -> _BrowserAgent: ...
67
+
68
+
69
+ class _BrowserUseModule(Protocol):
70
+ ChatAnthropic: _ChatAnthropicFactory
71
+ Browser: _BrowserFactory
72
+ Agent: _AgentFactory
73
+
74
+
40
75
  class BrowserUseAgent(Agent):
41
76
  """Run the ``browser-use`` agent against an env's ``cdp/1.3`` capability."""
42
77
 
@@ -52,8 +87,7 @@ class BrowserUseAgent(Agent):
52
87
  loop, and writes the final answer + trajectory metadata onto ``run.trace``
53
88
  (graded on exit).
54
89
  """
55
- from browser_use import Agent as BrowserUseSdkAgent
56
- from browser_use import Browser, ChatAnthropic
90
+ browser_use = cast("_BrowserUseModule", importlib.import_module("browser_use"))
57
91
 
58
92
  trace = run.trace
59
93
  cdp_url = _ws_to_http(run.client.binding(CDP_PROTOCOL).url)
@@ -63,12 +97,16 @@ class BrowserUseAgent(Agent):
63
97
  if not api_key:
64
98
  raise ValueError("BrowserUseAgent needs an Anthropic API key (set ANTHROPIC_API_KEY)")
65
99
 
66
- llm = ChatAnthropic(model=self.config.model, api_key=api_key, base_url=self.config.base_url)
67
- browser: Any = Browser(cdp_url=cdp_url)
68
- sdk_agent = cast("Any", BrowserUseSdkAgent(task=run.prompt_text, llm=llm, browser=browser))
100
+ llm = browser_use.ChatAnthropic(
101
+ model=self.config.model,
102
+ api_key=api_key,
103
+ base_url=self.config.base_url,
104
+ )
105
+ browser = browser_use.Browser(cdp_url=cdp_url)
106
+ sdk_agent = browser_use.Agent(task=run.prompt_text, llm=llm, browser=browser)
69
107
 
70
108
  try:
71
- history: Any = await sdk_agent.run(max_steps=self.config.max_steps)
109
+ history = await sdk_agent.run(max_steps=self.config.max_steps)
72
110
  except Exception as exc:
73
111
  LOGGER.exception("browser-use run failed")
74
112
  trace.status = "error"
@@ -35,7 +35,7 @@ from .tools.computer import ClaudeComputerTool
35
35
  from .tools.mcp_proxy import ClaudeMCPProxyTool
36
36
 
37
37
  if TYPE_CHECKING:
38
- from anthropic.types.beta import BetaTextBlock, BetaTextCitation
38
+ from anthropic.types.beta import BetaTextCitation
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -284,7 +284,7 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
284
284
  )
285
285
  result.done = False
286
286
  case "text":
287
- text_block = cast("BetaTextBlock", block)
287
+ text_block = block
288
288
  text_parts.append(text_block.text)
289
289
  citations.extend(self._citation(c) for c in (text_block.citations or []))
290
290
  case "thinking":
@@ -99,7 +99,7 @@ class ClaudeSDKAgent(Agent):
99
99
  family = cap.protocol.split("/", 1)[0]
100
100
  if family == "mcp":
101
101
  token = cap.params.get("auth_token")
102
- transport = "http" if cap.url.startswith("http") else "sse"
102
+ transport = "http" if cap.params["transport"] == "streamable-http" else "sse"
103
103
  server_config: dict[str, Any] = {"type": transport, "url": cap.url}
104
104
  if token:
105
105
  server_config["headers"] = {"Authorization": f"Bearer {token}"}
@@ -108,7 +108,7 @@ class ClaudeSDKAgent(Agent):
108
108
  from hud.agents.claude.sdk.computer_mcp import serve_computer_mcp
109
109
 
110
110
  rfb = cast("RFBClient", await run.client.open("rfb"))
111
- port = await serve_computer_mcp(rfb)
111
+ port = await serve_computer_mcp(rfb, self.config.screenshot_encoding)
112
112
  self._mcp_servers["computer-use"] = {
113
113
  "type": "http",
114
114
  "url": f"http://127.0.0.1:{port}/mcp",
@@ -12,6 +12,8 @@ from typing import TYPE_CHECKING, Any
12
12
 
13
13
  import fastmcp
14
14
 
15
+ from hud.capabilities.rfb import ScreenshotEncoding, WebPScreenshotEncoding
16
+
15
17
  if TYPE_CHECKING:
16
18
  from hud.capabilities.rfb import RFBClient
17
19
 
@@ -19,15 +21,19 @@ logger = logging.getLogger(__name__)
19
21
 
20
22
  #: Keep references to background server tasks so they aren't garbage-collected.
21
23
  _BACKGROUND_TASKS: set[asyncio.Task[None]] = set()
24
+ _DEFAULT_SCREENSHOT_ENCODING = WebPScreenshotEncoding()
22
25
 
23
26
 
24
- def create_computer_mcp(rfb: RFBClient) -> fastmcp.FastMCP:
27
+ def create_computer_mcp(
28
+ rfb: RFBClient,
29
+ screenshot_encoding: ScreenshotEncoding = _DEFAULT_SCREENSHOT_ENCODING,
30
+ ) -> fastmcp.FastMCP:
25
31
  """Build a FastMCP server with one ``computer`` tool backed by ``rfb``."""
26
32
 
27
33
  mcp = fastmcp.FastMCP("computer-use")
28
34
 
29
35
  @mcp.tool()
30
- async def computer( # pyright: ignore[reportUnusedFunction]
36
+ async def computer(
31
37
  action: str,
32
38
  coordinate: str | None = None,
33
39
  text: str | None = None,
@@ -79,7 +85,11 @@ def create_computer_mcp(rfb: RFBClient) -> fastmcp.FastMCP:
79
85
  arguments["region"] = region
80
86
 
81
87
  spec = AgentToolSpec(api_type="computer", api_name="computer")
82
- tool = ClaudeComputerTool(spec=spec, client=rfb)
88
+ tool = ClaudeComputerTool(
89
+ spec=spec,
90
+ client=rfb,
91
+ screenshot_encoding=screenshot_encoding,
92
+ )
83
93
  result = await tool.execute(arguments)
84
94
 
85
95
  # Return content blocks directly so the CLI/model sees real images.
@@ -106,6 +116,7 @@ def create_computer_mcp(rfb: RFBClient) -> fastmcp.FastMCP:
106
116
 
107
117
  async def serve_computer_mcp(
108
118
  rfb: RFBClient,
119
+ screenshot_encoding: ScreenshotEncoding = _DEFAULT_SCREENSHOT_ENCODING,
109
120
  host: str = "127.0.0.1",
110
121
  port: int = 0,
111
122
  ) -> int:
@@ -115,7 +126,7 @@ async def serve_computer_mcp(
115
126
  port = srv.sockets[0].getsockname()[1]
116
127
  srv.close()
117
128
 
118
- mcp = create_computer_mcp(rfb)
129
+ mcp = create_computer_mcp(rfb, screenshot_encoding)
119
130
  task = asyncio.create_task(_run(mcp, host, port))
120
131
  _BACKGROUND_TASKS.add(task)
121
132
  task.add_done_callback(_BACKGROUND_TASKS.discard)
@@ -16,6 +16,7 @@ import mcp.types as mcp_types
16
16
 
17
17
  from hud.agents.tools import RFBTool
18
18
  from hud.agents.tools.base import tool_err, tool_ok
19
+ from hud.capabilities.rfb import ScreenshotEncoding, WebPScreenshotEncoding
19
20
  from hud.types import MCPToolResult
20
21
 
21
22
  from .base import ClaudeToolSpec
@@ -278,13 +279,13 @@ class ClaudeComputerTool(RFBTool):
278
279
  x0, y0, x1, y1 = (int(v) for v in region_seq)
279
280
  except (TypeError, ValueError):
280
281
  return tool_err("region must contain 4 integers")
281
- png = await self.client.screenshot_png()
282
- cropped = _crop_png(png, (x0, y0, x1, y1))
282
+ screenshot, _ = await self.client.screenshot_png("image/png")
283
+ cropped, mime_type = _crop_png(screenshot, (x0, y0, x1, y1), self.screenshot_encoding)
283
284
  return MCPToolResult(
284
285
  content=[
285
286
  mcp_types.ImageContent(
286
287
  type="image",
287
- mimeType="image/png",
288
+ mimeType=mime_type,
288
289
  data=base64.b64encode(cropped).decode("ascii"),
289
290
  )
290
291
  ],
@@ -349,14 +350,21 @@ def _drag_path(arguments: dict[str, Any]) -> list[tuple[int, int]]:
349
350
  return path
350
351
 
351
352
 
352
- def _crop_png(png: bytes, region: tuple[int, int, int, int]) -> bytes:
353
+ def _crop_png(
354
+ png: bytes,
355
+ region: tuple[int, int, int, int],
356
+ encoding: ScreenshotEncoding,
357
+ ) -> tuple[bytes, str]:
353
358
  from PIL import Image
354
359
 
355
360
  image = Image.open(BytesIO(png))
356
361
  cropped = image.crop(region)
357
362
  buf = BytesIO()
358
- cropped.save(buf, format="PNG")
359
- return buf.getvalue()
363
+ if isinstance(encoding, WebPScreenshotEncoding):
364
+ cropped.save(buf, format="WEBP", quality=encoding.quality)
365
+ else:
366
+ cropped.save(buf, format="PNG")
367
+ return buf.getvalue(), encoding.mime_type
360
368
 
361
369
 
362
370
  __all__ = ["CLAUDE_COMPUTER_SPECS", "ClaudeComputerTool"]
@@ -1,21 +1,30 @@
1
1
  """``ClaudeComputerTool`` — key translation, per-model spec gating, and the
2
2
  computer-use action dispatch (translation to RFB primitives), without a live VNC.
3
3
  """
4
- # pyright: reportPrivateUsage=false, reportIncompatibleMethodOverride=false
5
4
 
6
5
  from __future__ import annotations
7
6
 
7
+ from io import BytesIO
8
8
  from types import SimpleNamespace
9
- from typing import Any
9
+ from typing import TYPE_CHECKING, Any
10
+ from unittest.mock import AsyncMock, patch
11
+
12
+ import mcp.types as mcp_types
13
+ from PIL import Image
10
14
 
11
15
  from hud.agents.claude.tools.computer import (
12
16
  CLAUDE_COMPUTER_SPECS,
13
17
  ClaudeComputerTool,
18
+ _crop_png,
14
19
  _hold_keys,
15
20
  _split_keys,
16
21
  _translate_key,
17
22
  )
23
+
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Iterable
18
26
  from hud.agents.tools.base import result_text, tool_ok
27
+ from hud.capabilities.rfb import WebPScreenshotEncoding
19
28
 
20
29
 
21
30
  class RecordingComputer(ClaudeComputerTool):
@@ -25,22 +34,41 @@ class RecordingComputer(ClaudeComputerTool):
25
34
 
26
35
  def __init__(self) -> None:
27
36
  self.calls: list[tuple[Any, ...]] = []
37
+ self.screenshot_encoding = WebPScreenshotEncoding(quality=42)
28
38
  self.client = SimpleNamespace(width=200, height=100)
29
39
 
30
40
  async def screenshot(self) -> Any:
31
41
  self.calls.append(("screenshot",))
32
42
  return tool_ok("shot")
33
43
 
34
- async def click(self, x: Any, y: Any, **kw: Any) -> None:
44
+ async def click(
45
+ self,
46
+ x: int | None = None,
47
+ y: int | None = None,
48
+ *,
49
+ button: Any = "left",
50
+ hold_keys: Iterable[str] | None = None,
51
+ count: int = 1,
52
+ interval_ms: int = 0,
53
+ ) -> None:
54
+ kw: dict[str, Any] = {}
55
+ if button != "left":
56
+ kw["button"] = button
57
+ if hold_keys is not None:
58
+ kw["hold_keys"] = hold_keys
59
+ if count != 1:
60
+ kw["count"] = count
61
+ if interval_ms:
62
+ kw["interval_ms"] = interval_ms
35
63
  self.calls.append(("click", x, y, kw))
36
64
 
37
65
  async def move(self, x: Any, y: Any) -> None:
38
66
  self.calls.append(("move", x, y))
39
67
 
40
- async def mouse_down(self, button: Any) -> None:
68
+ async def mouse_down(self, button: Any = "left") -> None:
41
69
  self.calls.append(("down", button))
42
70
 
43
- async def mouse_up(self, button: Any) -> None:
71
+ async def mouse_up(self, button: Any = "left") -> None:
44
72
  self.calls.append(("up", button))
45
73
 
46
74
  async def type_text(self, text: Any) -> None:
@@ -52,15 +80,21 @@ class RecordingComputer(ClaudeComputerTool):
52
80
  async def hold_key(self, key: Any, **kw: Any) -> None:
53
81
  self.calls.append(("hold", key, kw))
54
82
 
55
- async def scroll(self, x: Any, y: Any, **kw: Any) -> None:
83
+ async def scroll(
84
+ self,
85
+ x: int | None = None,
86
+ y: int | None = None,
87
+ *,
88
+ scroll_x: int = 0,
89
+ scroll_y: int = 0,
90
+ hold_keys: Iterable[str] | None = None,
91
+ ) -> None:
92
+ kw = {"scroll_x": scroll_x, "scroll_y": scroll_y, "hold_keys": hold_keys}
56
93
  self.calls.append(("scroll", x, y, kw))
57
94
 
58
95
  async def drag(self, path: Any, **kw: Any) -> None:
59
96
  self.calls.append(("drag", tuple(path), kw))
60
97
 
61
- async def wait(self, ms: Any) -> None:
62
- self.calls.append(("wait", ms))
63
-
64
98
 
65
99
  # ─── key translation helpers ──────────────────────────────────────────
66
100
 
@@ -147,3 +181,33 @@ async def test_unsupported_action_errors() -> None:
147
181
  result = await tool.execute({"action": "frobnicate"})
148
182
  assert result.isError
149
183
  assert "unsupported" in result_text(result).lower()
184
+
185
+
186
+ def test_crop_reports_encoded_mime_type() -> None:
187
+ source = BytesIO()
188
+ Image.effect_noise((128, 128), 100).convert("RGB").save(source, format="PNG")
189
+
190
+ cropped, mime_type = _crop_png(
191
+ source.getvalue(),
192
+ (0, 0, 128, 128),
193
+ WebPScreenshotEncoding(quality=42),
194
+ )
195
+
196
+ assert mime_type == "image/webp"
197
+ assert cropped.startswith(b"RIFF")
198
+
199
+
200
+ async def test_zoom_reports_encoded_mime_type() -> None:
201
+ tool = RecordingComputer()
202
+ tool.client.screenshot_png = AsyncMock(return_value=(b"png", "image/png"))
203
+
204
+ with patch(
205
+ "hud.agents.claude.tools.computer._crop_png",
206
+ return_value=(b"webp", "image/webp"),
207
+ ) as crop:
208
+ result = await tool._zoom({"region": [0, 0, 10, 10]})
209
+
210
+ tool.client.screenshot_png.assert_awaited_once_with("image/png")
211
+ crop.assert_called_once_with(b"png", (0, 0, 10, 10), tool.screenshot_encoding)
212
+ image = next(block for block in result.content if isinstance(block, mcp_types.ImageContent))
213
+ assert image.mimeType == "image/webp"