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.
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/.gitignore +1 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/PKG-INFO +27 -7
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/README.md +16 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/__init__.py +2 -8
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/__init__.py +19 -5
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/browser_use/agent.py +49 -11
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/agent.py +2 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/agent.py +2 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/computer_mcp.py +15 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/computer.py +14 -6
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/tests/test_computer.py +73 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/tests/test_computer.py +28 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/misc/response_automation.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/agent.py +6 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/apply_patch.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/base.py +1 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/coding.py +60 -17
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/computer.py +9 -3
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/test_computer.py +33 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/base.py +1 -12
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/filesystem.py +2 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/mcp_proxy.py +1 -1
- hud-0.6.13.dev2/hud/agents/robot/__init__.py +39 -0
- hud-0.6.13.dev2/hud/agents/robot/adapter.py +132 -0
- hud-0.6.13.dev2/hud/agents/robot/agent.py +174 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/robot/batching.py +23 -26
- hud-0.6.13.dev2/hud/agents/robot/dataset.py +243 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/robot/model.py +1 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_apply_patch.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_base.py +43 -7
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_claude_agent.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_claude_sdk_agent.py +92 -3
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_gemini_agent.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_openai_agent.py +37 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_openai_compatible_agent.py +0 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_provider_native_tools.py +164 -41
- hud-0.6.13.dev2/hud/agents/tests/test_robot_dataset_writer.py +162 -0
- hud-0.6.13.dev2/hud/agents/tests/test_tool_agent.py +513 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tool_agent.py +47 -14
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/base.py +21 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/mcp.py +5 -3
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/rfb.py +17 -5
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/ssh.py +22 -6
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/types.py +16 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/base.py +38 -12
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/mcp.py +9 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/rfb.py +45 -7
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/robot.py +44 -19
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/ssh.py +7 -32
- hud-0.6.13.dev2/hud/capabilities/tests/test_rfb.py +76 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/__init__.py +5 -12
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/cancel.py +4 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/deploy.py +16 -19
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/eval.py +3 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/serve.py +17 -23
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_init.py +0 -11
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_deploy.py +24 -10
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_eval_config.py +20 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/trace.py +11 -8
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/source.py +36 -46
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_registry.py +3 -3
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_source.py +29 -12
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_tasks.py +5 -5
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_version_check.py +3 -15
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/version_check.py +2 -34
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/client.py +176 -105
- hud-0.6.13.dev2/hud/clients/tests/test_connect.py +213 -0
- hud-0.6.13.dev2/hud/environment/__init__.py +98 -0
- hud-0.6.13.dev2/hud/environment/egress.py +653 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/env.py +50 -26
- hud-0.6.13.dev2/hud/environment/namespace.py +605 -0
- hud-0.6.13.dev2/hud/environment/robot/__init__.py +38 -0
- hud-0.6.13.dev2/hud/environment/robot/bridge.py +620 -0
- hud-0.6.13.dev2/hud/environment/robot/endpoint.py +350 -0
- hud-0.6.13.dev2/hud/environment/robot/gym.py +726 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/server.py +184 -89
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_capability_backing.py +185 -9
- hud-0.6.13.dev2/hud/environment/tests/test_loader.py +169 -0
- hud-0.6.13.dev2/hud/environment/tests/test_robot_regressions.py +505 -0
- hud-0.6.13.dev2/hud/environment/tests/test_sessions.py +89 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_tunnel.py +23 -11
- hud-0.6.13.dev2/hud/environment/tests/test_workspace.py +1391 -0
- hud-0.6.13.dev2/hud/environment/workspace.py +1696 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/__init__.py +2 -0
- hud-0.6.13.dev2/hud/eval/_runtime_protocols.py +212 -0
- hud-0.6.13.dev2/hud/eval/compose.py +172 -0
- hud-0.6.13.dev2/hud/eval/docker-seccomp.json +21 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/job.py +37 -6
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/run.py +234 -89
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/runtime.py +572 -125
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/sync.py +6 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/task.py +30 -12
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/taskset.py +58 -30
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_chat.py +0 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_docker_provider.py +569 -26
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_file_tracking_observer.py +8 -6
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_hosted.py +159 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_job.py +48 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_local_runtime.py +42 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_rollout.py +475 -9
- hud-0.6.13.dev2/hud/eval/tests/test_shared.py +178 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_sync.py +28 -4
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/tests/test_task.py +98 -9
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/bash.py +17 -15
- hud-0.6.13.dev2/hud/integrations/__init__.py +1 -0
- hud-0.6.13.dev2/hud/integrations/harbor/Dockerfile +25 -0
- hud-0.6.13.dev2/hud/integrations/harbor/__init__.py +12 -0
- hud-0.6.13.dev2/hud/integrations/harbor/adapt.py +734 -0
- hud-0.6.13.dev2/hud/integrations/harbor/env.py +678 -0
- hud-0.6.13.dev2/hud/integrations/harbor/export.py +233 -0
- hud-0.6.13.dev2/hud/integrations/harbor/install.sh +32 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/conftest.py +135 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +5 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +1 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +6 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +10 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +15 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +9 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/compose.yaml +17 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +6 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +13 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +1 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +3 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +10 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +9 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +6 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +7 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +13 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +49 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +31 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +33 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +5 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/compose.yaml +11 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +1 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +26 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +26 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +14 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +19 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +5 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +7 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +1 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +4 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +17 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +20 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/test_contract.py +896 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/test_harbor.py +267 -0
- hud-0.6.13.dev2/hud/integrations/harbor/tests/test_integration.py +339 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/mcp_patches.py +4 -4
- hud-0.6.13.dev2/hud/py.typed +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/instrument.py +11 -3
- hud-0.6.13.dev2/hud/telemetry/robot/__init__.py +12 -0
- hud-0.6.13.dev2/hud/telemetry/robot/recorder.py +313 -0
- hud-0.6.13.dev2/hud/telemetry/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/tests/test_instrument.py +2 -2
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/client.py +49 -6
- hud-0.6.13.dev2/hud/train/tests/__init__.py +1 -0
- hud-0.6.13.dev2/hud/train/tests/test_client.py +86 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/types.py +2 -2
- hud-0.6.13.dev2/hud/utils/docker.py +32 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/gateway.py +33 -3
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/hints.py +2 -1
- hud-0.6.13.dev2/hud/utils/naming.py +19 -0
- hud-0.6.13.dev2/hud/utils/process.py +224 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/serialization.py +1 -1
- hud-0.6.13.dev2/hud/utils/tests/__init__.py +0 -0
- hud-0.6.13.dev2/hud/utils/tests/test_gateway.py +160 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_platform.py +5 -1
- hud-0.6.13.dev2/hud/utils/tests/test_process.py +110 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/version.py +1 -1
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/pyproject.toml +32 -25
- hud-0.6.12.dev0/hud/_legacy.py +0 -300
- hud-0.6.12.dev0/hud/agents/robot/__init__.py +0 -41
- hud-0.6.12.dev0/hud/agents/robot/_types.py +0 -12
- hud-0.6.12.dev0/hud/agents/robot/adapter.py +0 -105
- hud-0.6.12.dev0/hud/agents/robot/agent.py +0 -169
- hud-0.6.12.dev0/hud/agents/robot/record.py +0 -230
- hud-0.6.12.dev0/hud/agents/tests/test_tool_agent.py +0 -242
- hud-0.6.12.dev0/hud/clients/tests/test_connect.py +0 -111
- hud-0.6.12.dev0/hud/environment/__init__.py +0 -58
- hud-0.6.12.dev0/hud/environment/legacy.py +0 -364
- hud-0.6.12.dev0/hud/environment/robot/__init__.py +0 -29
- hud-0.6.12.dev0/hud/environment/robot/bridge.py +0 -176
- hud-0.6.12.dev0/hud/environment/robot/endpoint.py +0 -210
- hud-0.6.12.dev0/hud/environment/robot/sim_runner.py +0 -111
- hud-0.6.12.dev0/hud/environment/tests/test_legacy.py +0 -273
- hud-0.6.12.dev0/hud/environment/tests/test_loader.py +0 -31
- hud-0.6.12.dev0/hud/environment/tests/test_workspace.py +0 -244
- hud-0.6.12.dev0/hud/environment/workspace.py +0 -724
- hud-0.6.12.dev0/hud/server.py +0 -32
- hud-0.6.12.dev0/hud/utils/process.py +0 -130
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/LICENSE +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/__main__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/base.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/browser_use/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/sdk/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/base.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/coding.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/hosted.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/mcp_proxy.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/settings.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/claude/tools/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/agent.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/settings.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/base.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/coding.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/computer.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/filesystem.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/hosted.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/gemini/tools/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/misc/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/hosted.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/mcp_proxy.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/strict_schema.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/agent.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/openai_compatible/tools/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tests/test_trace.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/agents/tools/hosted.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/capabilities/cdp.py +0 -0
- {hud-0.6.12.dev0/hud/cli/utils → hud-0.6.13.dev2/hud/capabilities}/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/__main__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/client.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/init.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/jobs.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/login.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/models.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/presets.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/sync.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/task.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/templates.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_main.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_eval_bedrock.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_init.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_main_module.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/tests/test_sync_export.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/api.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/build_display.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/build_logs.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/config.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/context.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/display.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/jobs.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/registry.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tasks.py +0 -0
- {hud-0.6.12.dev0/hud/environment → hud-0.6.13.dev2/hud/cli/utils}/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_build_display.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_config.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/cli/utils/tests/test_context.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/clients/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/conftest.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/file_tracker.py +0 -0
- {hud-0.6.12.dev0/hud/eval → hud-0.6.13.dev2/hud/environment}/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/conftest.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_file_tracker.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_file_tracking.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_manifest.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/tests/test_server.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/environment/utils.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/chat.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/eval/file_tracking.py +0 -0
- {hud-0.6.12.dev0/hud/telemetry → hud-0.6.13.dev2/hud/eval}/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/base.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/combine.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/judge.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/results.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/graders/text.py +0 -0
- {hud-0.6.12.dev0/hud/utils → hud-0.6.13.dev2/hud/integrations/harbor}/tests/__init__.py +0 -0
- /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
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/tests/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/tests/test_warnings.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/patches/warnings.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/settings.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/context.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/exporter.py +0 -0
- {hud-0.6.12.dev0/hud/agents → hud-0.6.13.dev2/hud/telemetry}/robot/video.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/span.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/telemetry/tests/test_exporter.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/base.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/train/types.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/__init__.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/exceptions.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/hud_console.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/modules.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/platform.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/requests.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_exceptions.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_hints.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_hud_console.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_requests.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/tests/test_serialization.py +0 -0
- {hud-0.6.12.dev0 → hud-0.6.13.dev2}/hud/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hud
|
|
3
|
-
Version: 0.6.
|
|
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
|
|
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
|
|
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.
|
|
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:
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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(
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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.
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
282
|
-
cropped = _crop_png(
|
|
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=
|
|
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(
|
|
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
|
-
|
|
359
|
-
|
|
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(
|
|
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(
|
|
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"
|