hud 0.6.18.dev2__tar.gz → 0.6.19.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.18.dev2 → hud-0.6.19.dev2}/PKG-INFO +13 -15
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/README.md +11 -13
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/__init__.py +2 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/__init__.py +20 -41
- hud-0.6.19.dev2/hud/agents/base.py +47 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/browser_use/agent.py +2 -13
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/__init__.py +3 -3
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/agent.py +42 -25
- hud-0.6.19.dev2/hud/agents/claude/images.py +65 -0
- hud-0.6.19.dev2/hud/agents/claude/sdk/__init__.py +7 -0
- hud-0.6.19.dev2/hud/agents/claude/sdk/agent.py +219 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/sdk/computer_mcp.py +50 -108
- hud-0.6.19.dev2/hud/agents/claude/sdk/events.py +128 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/coding.py +1 -1
- hud-0.6.19.dev2/hud/agents/cli.py +141 -0
- hud-0.6.19.dev2/hud/agents/codex/__init__.py +7 -0
- hud-0.6.19.dev2/hud/agents/codex/agent.py +336 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/agent.py +4 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/agent.py +4 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/agent.py +14 -19
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/tools/filesystem.py +4 -3
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/agent.py +0 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/batching.py +1 -0
- hud-0.6.19.dev2/hud/agents/tests/cli_fakes.py +111 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_base.py +37 -14
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_claude_agent.py +117 -0
- hud-0.6.19.dev2/hud/agents/tests/test_claude_cli_agent.py +835 -0
- hud-0.6.19.dev2/hud/agents/tests/test_codex_cli_agent.py +381 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_openai_compatible_agent.py +4 -3
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_provider_native_tools.py +55 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_tool_agent.py +38 -19
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tool_agent.py +33 -92
- hud-0.6.19.dev2/hud/agents/tools/file_view.py +38 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/ssh.py +9 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/types.py +58 -33
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/__init__.py +2 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/base.py +3 -0
- hud-0.6.19.dev2/hud/capabilities/connection.py +106 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/ssh.py +44 -8
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/tests/test_ssh.py +51 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/eval.py +9 -10
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_eval.py +3 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/clients/client.py +42 -7
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/clients/tests/test_connect.py +85 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/__init__.py +2 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/egress.py +241 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/env.py +168 -1
- hud-0.6.19.dev2/hud/environment/process_guard.py +723 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/server.py +45 -2
- hud-0.6.19.dev2/hud/environment/tests/test_process_connection.py +368 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_sessions.py +73 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_workspace.py +323 -6
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/workspace.py +234 -27
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/run.py +49 -30
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/__init__.py +2 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/compose.py +49 -4
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/docker.py +8 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/hosted.py +7 -13
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_docker_provider.py +88 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_hosted.py +52 -20
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_local_runtime.py +1 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_rollout.py +25 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_task.py +8 -4
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/test_integration.py +1 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/exporter.py +47 -29
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/tests/test_exporter.py +24 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/types.py +40 -19
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/gateway.py +27 -11
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_gateway.py +18 -2
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/version.py +1 -1
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/pyproject.toml +1 -1
- hud-0.6.18.dev2/hud/agents/base.py +0 -22
- hud-0.6.18.dev2/hud/agents/claude/sdk/__init__.py +0 -5
- hud-0.6.18.dev2/hud/agents/claude/sdk/agent.py +0 -355
- hud-0.6.18.dev2/hud/agents/tests/test_claude_sdk_agent.py +0 -679
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/.gitignore +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/LICENSE +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/__main__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/browser_use/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/hosted.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/settings.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/claude/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/settings.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/coding.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/filesystem.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/hosted.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/gemini/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/misc/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/misc/response_automation.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/apply_patch.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/coding.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/hosted.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/strict_schema.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/tools/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/tools/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/openai_compatible/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/adapter.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/dataset.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/robot/model.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_apply_patch.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_gemini_agent.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_openai_agent.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_robot_dataset_writer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tests/test_trace.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/hosted.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/mcp.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/agents/tools/rfb.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/cdp.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/mcp.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/rfb.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/robot.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/capabilities/tests/test_rfb.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/__main__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/deploy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/init.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/jobs.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/models.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/project.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/qa.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/serve.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/sync.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/task.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_cli.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_deploy.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_init.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_jobs.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_main.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_project.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_qa.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_sync.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_task.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/tests/test_trace.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/cli/trace.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/clients/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/clients/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/conftest.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/arguments.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/file_tracker.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/namespace.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/robot/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/robot/bridge.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/robot/endpoint.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/robot/gym.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/conftest.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_arguments.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_capability_backing.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_file_tracker.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_file_tracking.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_loader.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_manifest.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_platform.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_robot_regressions.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_server.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/tests/test_tunnel.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/environment/utils.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/chat.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/docker-seccomp.json +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/file_tracking.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/job.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/core.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/daytona.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/hud.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/local.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/runtime/modal.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/sync.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/task.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/taskset.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_chat.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_file_tracking_observer.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_job.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_shared.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/eval/tests/test_sync.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/bash.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/combine.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/judge.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/results.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/graders/text.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/adapt.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/env.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/export.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/install.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/conftest.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/docker-compose.yaml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/docker-compose.yaml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/test_contract.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/integrations/harbor/tests/test_harbor.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/patches/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/patches/mcp_patches.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/patches/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/patches/tests/test_warnings.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/patches/warnings.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/py.typed +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/settings.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/context.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/instrument.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/robot/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/robot/recorder.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/robot/video.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/span.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/base.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/client.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/tests/test_client.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/train/types.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/docker.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/exceptions.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/hints.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/hud_console.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/modules.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/naming.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/platform.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/process.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/requests.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/serialization.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/__init__.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_exceptions.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_hints.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_hud_console.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_naming.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_platform.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_process.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_requests.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/tests/test_serialization.py +0 -0
- {hud-0.6.18.dev2 → hud-0.6.19.dev2}/hud/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hud
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.19.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
|
|
@@ -38,7 +38,7 @@ Requires-Dist: anthropic>=0.98.0
|
|
|
38
38
|
Requires-Dist: asyncssh>=2.23.0
|
|
39
39
|
Requires-Dist: asyncvnc>=1.3.0
|
|
40
40
|
Requires-Dist: fastmcp==3.2.0
|
|
41
|
-
Requires-Dist: google-genai
|
|
41
|
+
Requires-Dist: google-genai>=1.75.0
|
|
42
42
|
Requires-Dist: httpx2<3,>=2.0.0
|
|
43
43
|
Requires-Dist: httpx<1,>=0.23.0
|
|
44
44
|
Requires-Dist: mcp<2.0,>=1.24.0
|
|
@@ -199,19 +199,6 @@ Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `
|
|
|
199
199
|
|
|
200
200
|
→ [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/reference/tasks)
|
|
201
201
|
|
|
202
|
-
## Existing benchmarks
|
|
203
|
-
|
|
204
|
-
The experimental `hud.integrations.harbor` adapter turns Harbor task directories into runnable HUD
|
|
205
|
-
tasksets and can export authored HUD tasks back to Harbor folders.
|
|
206
|
-
|
|
207
|
-
```python
|
|
208
|
-
from hud.integrations import harbor
|
|
209
|
-
|
|
210
|
-
taskset = await harbor.adapt("./benchmark")
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
→ [Harbor interop](https://docs.hud.ai/v6/advanced/harbor-convert)
|
|
214
|
-
|
|
215
202
|
## Capabilities & harnesses
|
|
216
203
|
|
|
217
204
|
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.
|
|
@@ -234,6 +221,17 @@ A **capability** is a connection the environment exposes; a **harness** attaches
|
|
|
234
221
|
|
|
235
222
|
From the [platform UI](https://hud.ai) you can run batches, compare models on the same taskset, and inspect every trace.
|
|
236
223
|
|
|
224
|
+
Hosted Claude Code and Codex harnesses reach platform inference through an
|
|
225
|
+
environment-owned, workspace-local endpoint. The endpoint is available only to
|
|
226
|
+
`bwrap` workspaces with network isolation and is bound to the exact CLI process
|
|
227
|
+
selected by the harness. Platform credentials stay in the environment-owned
|
|
228
|
+
relay rather than the CLI environment, workspace manifest, or child processes.
|
|
229
|
+
Codex therefore uses the environment sandbox instead of starting a nested
|
|
230
|
+
Codex sandbox for process-bound hosted execution.
|
|
231
|
+
The workspace probes its substrate and uses either seccomp notification or a
|
|
232
|
+
ptrace-backed seccomp guard; it does not advertise process-bound connections
|
|
233
|
+
when neither enforcement backend is available.
|
|
234
|
+
|
|
237
235
|
→ [Run & deploy](https://docs.hud.ai/v6/reference/runtime)
|
|
238
236
|
|
|
239
237
|
## Train on rewards
|
|
@@ -113,19 +113,6 @@ Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `
|
|
|
113
113
|
|
|
114
114
|
→ [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/reference/tasks)
|
|
115
115
|
|
|
116
|
-
## Existing benchmarks
|
|
117
|
-
|
|
118
|
-
The experimental `hud.integrations.harbor` adapter turns Harbor task directories into runnable HUD
|
|
119
|
-
tasksets and can export authored HUD tasks back to Harbor folders.
|
|
120
|
-
|
|
121
|
-
```python
|
|
122
|
-
from hud.integrations import harbor
|
|
123
|
-
|
|
124
|
-
taskset = await harbor.adapt("./benchmark")
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
→ [Harbor interop](https://docs.hud.ai/v6/advanced/harbor-convert)
|
|
128
|
-
|
|
129
116
|
## Capabilities & harnesses
|
|
130
117
|
|
|
131
118
|
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.
|
|
@@ -148,6 +135,17 @@ A **capability** is a connection the environment exposes; a **harness** attaches
|
|
|
148
135
|
|
|
149
136
|
From the [platform UI](https://hud.ai) you can run batches, compare models on the same taskset, and inspect every trace.
|
|
150
137
|
|
|
138
|
+
Hosted Claude Code and Codex harnesses reach platform inference through an
|
|
139
|
+
environment-owned, workspace-local endpoint. The endpoint is available only to
|
|
140
|
+
`bwrap` workspaces with network isolation and is bound to the exact CLI process
|
|
141
|
+
selected by the harness. Platform credentials stay in the environment-owned
|
|
142
|
+
relay rather than the CLI environment, workspace manifest, or child processes.
|
|
143
|
+
Codex therefore uses the environment sandbox instead of starting a nested
|
|
144
|
+
Codex sandbox for process-bound hosted execution.
|
|
145
|
+
The workspace probes its substrate and uses either seccomp notification or a
|
|
146
|
+
ptrace-backed seccomp guard; it does not advertise process-bound connections
|
|
147
|
+
when neither enforcement backend is available.
|
|
148
|
+
|
|
151
149
|
→ [Run & deploy](https://docs.hud.ai/v6/reference/runtime)
|
|
152
150
|
|
|
153
151
|
## Train on rewards
|
|
@@ -7,6 +7,7 @@ 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 .capabilities import Connection
|
|
10
11
|
from .clients import connect
|
|
11
12
|
from .environment import Environment
|
|
12
13
|
from .eval import (
|
|
@@ -38,6 +39,7 @@ from .version import __version__
|
|
|
38
39
|
__all__ = [
|
|
39
40
|
"Chat",
|
|
40
41
|
"ComposeProject",
|
|
42
|
+
"Connection",
|
|
41
43
|
"DockerRuntime",
|
|
42
44
|
"Environment",
|
|
43
45
|
"Grade",
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
"""Agent implementations.
|
|
2
|
-
|
|
3
|
-
The robot policy harness lives in :mod:`hud.agents.robot` (requires the ``robot`` extra).
|
|
4
|
-
"""
|
|
1
|
+
"""Agent implementations."""
|
|
5
2
|
|
|
6
3
|
from __future__ import annotations
|
|
7
4
|
|
|
@@ -15,13 +12,16 @@ from hud.utils.gateway import resolve_gateway_model
|
|
|
15
12
|
if TYPE_CHECKING:
|
|
16
13
|
from typing import TypeAlias
|
|
17
14
|
|
|
18
|
-
from hud.agents.claude import ClaudeAgent,
|
|
15
|
+
from hud.agents.claude import ClaudeAgent, ClaudeCLIAgent, ClaudeCLIConfig
|
|
16
|
+
from hud.agents.codex import CodexCLIAgent, CodexCLIConfig
|
|
19
17
|
from hud.agents.gemini import GeminiAgent
|
|
20
18
|
from hud.agents.openai import OpenAIAgent
|
|
21
19
|
from hud.agents.openai_compatible import OpenAIChatAgent
|
|
22
20
|
from hud.agents.tool_agent import ToolAgent as MCPAgent
|
|
23
21
|
|
|
24
|
-
GatewayAgent: TypeAlias =
|
|
22
|
+
GatewayAgent: TypeAlias = (
|
|
23
|
+
ClaudeAgent | ClaudeCLIAgent | CodexCLIAgent | GeminiAgent | OpenAIAgent | OpenAIChatAgent
|
|
24
|
+
)
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
|
|
@@ -46,44 +46,22 @@ def create_agent(model: str, **kwargs: Any) -> GatewayAgent:
|
|
|
46
46
|
if not settings.api_key:
|
|
47
47
|
raise HudAuthenticationError("HUD_API_KEY is required to create a gateway agent")
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# cls/config_cls are matched unions; the pairing is correct by construction.
|
|
53
|
-
config = agent_type.config_cls(**kwargs)
|
|
54
|
-
return agent_type.cls(cast("Any", config))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def resolve_agent_model(model: str) -> tuple[AgentType, str]:
|
|
58
|
-
"""Resolve a catalog id/name/slug or an agent type without constructing a client."""
|
|
59
|
-
agent_type = next((candidate for candidate in AgentType if candidate.value == model), None)
|
|
60
|
-
if agent_type is not None:
|
|
61
|
-
return agent_type, model
|
|
62
|
-
try:
|
|
49
|
+
if model in {member.value for member in AgentType}:
|
|
50
|
+
agent_type = AgentType(model)
|
|
51
|
+
else:
|
|
63
52
|
entry = resolve_gateway_model(model)
|
|
64
|
-
except HudAuthenticationError:
|
|
65
|
-
types = ", ".join(candidate.value for candidate in AgentType)
|
|
66
|
-
raise ValueError(
|
|
67
|
-
f"Resolving {model!r} needs the HUD model catalog; set HUD_API_KEY, or pass an "
|
|
68
|
-
f"agent type ({types}) and choose the model with its config."
|
|
69
|
-
) from None
|
|
70
|
-
if entry.sdk_agent_type in ("operator", "gemini_cua"):
|
|
71
|
-
replacement = "openai" if entry.sdk_agent_type == "operator" else "gemini"
|
|
72
|
-
raise ValueError(
|
|
73
|
-
f"The {entry.sdk_agent_type} agent is no longer supported; use {replacement} with a "
|
|
74
|
-
"supported computer-use model."
|
|
75
|
-
)
|
|
76
|
-
try:
|
|
77
53
|
agent_type = AgentType(entry.sdk_agent_type)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return
|
|
54
|
+
kwargs.setdefault("model", entry.model_name or model)
|
|
55
|
+
kwargs["gateway"] = True
|
|
56
|
+
return cast("GatewayAgent", agent_type.cls.load(kwargs))
|
|
81
57
|
|
|
82
58
|
|
|
83
59
|
_LAZY_EXPORTS = {
|
|
84
60
|
"ClaudeAgent": ("hud.agents.claude", "ClaudeAgent"),
|
|
85
|
-
"
|
|
86
|
-
"
|
|
61
|
+
"ClaudeCLIAgent": ("hud.agents.claude", "ClaudeCLIAgent"),
|
|
62
|
+
"ClaudeCLIConfig": ("hud.agents.claude", "ClaudeCLIConfig"),
|
|
63
|
+
"CodexCLIAgent": ("hud.agents.codex", "CodexCLIAgent"),
|
|
64
|
+
"CodexCLIConfig": ("hud.agents.codex", "CodexCLIConfig"),
|
|
87
65
|
"GeminiAgent": ("hud.agents.gemini", "GeminiAgent"),
|
|
88
66
|
"MCPAgent": ("hud.agents.tool_agent", "ToolAgent"),
|
|
89
67
|
"OpenAIAgent": ("hud.agents.openai", "OpenAIAgent"),
|
|
@@ -92,14 +70,15 @@ _LAZY_EXPORTS = {
|
|
|
92
70
|
|
|
93
71
|
__all__ = [
|
|
94
72
|
"ClaudeAgent",
|
|
95
|
-
"
|
|
96
|
-
"
|
|
73
|
+
"ClaudeCLIAgent",
|
|
74
|
+
"ClaudeCLIConfig",
|
|
75
|
+
"CodexCLIAgent",
|
|
76
|
+
"CodexCLIConfig",
|
|
97
77
|
"GeminiAgent",
|
|
98
78
|
"MCPAgent",
|
|
99
79
|
"OpenAIAgent",
|
|
100
80
|
"OpenAIChatAgent",
|
|
101
81
|
"create_agent",
|
|
102
|
-
"resolve_agent_model",
|
|
103
82
|
]
|
|
104
83
|
|
|
105
84
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Agent ABC: the rollout contract."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import TYPE_CHECKING, ClassVar, Generic, Self, cast
|
|
7
|
+
|
|
8
|
+
from typing_extensions import TypeVar
|
|
9
|
+
|
|
10
|
+
from hud.agents.types import AgentConfig
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from hud.eval.run import Run
|
|
14
|
+
from hud.utils.serialization import JsonObject
|
|
15
|
+
|
|
16
|
+
ConfigT_co = TypeVar("ConfigT_co", bound=AgentConfig, covariant=True, default=AgentConfig)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Agent(ABC, Generic[ConfigT_co]):
|
|
20
|
+
"""Drives a live ``Run`` by recording its trajectory and final answer.
|
|
21
|
+
|
|
22
|
+
Subclasses implement ``__call__(run)``; callers do ``await agent(run)``. Stateless
|
|
23
|
+
per run — everything comes from ``run`` — so one instance drives many concurrent
|
|
24
|
+
rollouts. The caller owns lifecycle status, cancellation, and grading.
|
|
25
|
+
|
|
26
|
+
``config`` is the agent's serializable identity: :meth:`dump` writes it and
|
|
27
|
+
:meth:`load` rebuilds the agent from it. Subclasses parametrize ``Agent[XConfig]``,
|
|
28
|
+
set ``config_cls = XConfig`` for construction, and, when they override
|
|
29
|
+
``__init__``, call ``super().__init__(config)``.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
config_cls: ClassVar[type[AgentConfig]] = AgentConfig
|
|
33
|
+
config: ConfigT_co
|
|
34
|
+
|
|
35
|
+
def __init__(self, config: ConfigT_co | None = None) -> None:
|
|
36
|
+
self.config = config or cast("ConfigT_co", self.config_cls())
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
async def __call__(self, run: Run) -> None:
|
|
40
|
+
"""Fill ``run.trace`` with the trajectory and final answer."""
|
|
41
|
+
|
|
42
|
+
def dump(self) -> JsonObject:
|
|
43
|
+
return self.config.model_dump(mode="json")
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def load(cls, data: JsonObject) -> Self:
|
|
47
|
+
return cls(cast("ConfigT_co", cls.config_cls.model_validate(data)))
|
|
@@ -24,7 +24,6 @@ from urllib.parse import urlsplit, urlunsplit
|
|
|
24
24
|
from hud.agents.base import Agent
|
|
25
25
|
from hud.agents.types import AgentStep, BrowserUseConfig
|
|
26
26
|
from hud.settings import settings
|
|
27
|
-
from hud.types import Step
|
|
28
27
|
|
|
29
28
|
if TYPE_CHECKING:
|
|
30
29
|
from hud.eval.run import Run
|
|
@@ -72,13 +71,10 @@ class _BrowserUseModule(Protocol):
|
|
|
72
71
|
Agent: _AgentFactory
|
|
73
72
|
|
|
74
73
|
|
|
75
|
-
class BrowserUseAgent(Agent):
|
|
74
|
+
class BrowserUseAgent(Agent[BrowserUseConfig]):
|
|
76
75
|
"""Run the ``browser-use`` agent against an env's ``cdp/1.3`` capability."""
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def __init__(self, config: BrowserUseConfig | None = None) -> None:
|
|
81
|
-
self.config = config or BrowserUseConfig()
|
|
77
|
+
config_cls = BrowserUseConfig
|
|
82
78
|
|
|
83
79
|
async def __call__(self, run: Run) -> None:
|
|
84
80
|
"""Drive browser-use over the run's CDP capability, filling ``run.trace``.
|
|
@@ -107,18 +103,12 @@ class BrowserUseAgent(Agent):
|
|
|
107
103
|
|
|
108
104
|
try:
|
|
109
105
|
history = await sdk_agent.run(max_steps=self.config.max_steps)
|
|
110
|
-
except Exception as exc:
|
|
111
|
-
LOGGER.exception("browser-use run failed")
|
|
112
|
-
trace.status = "error"
|
|
113
|
-
run.record(Step(source="system", error=str(exc)))
|
|
114
|
-
return
|
|
115
106
|
finally:
|
|
116
107
|
with contextlib.suppress(Exception):
|
|
117
108
|
await browser.stop()
|
|
118
109
|
|
|
119
110
|
successful = history.is_successful()
|
|
120
111
|
content = history.final_result() or ""
|
|
121
|
-
trace.status = "error" if successful is False else "completed"
|
|
122
112
|
trace.content = content
|
|
123
113
|
trace.extra.update(
|
|
124
114
|
{
|
|
@@ -133,7 +123,6 @@ class BrowserUseAgent(Agent):
|
|
|
133
123
|
AgentStep(
|
|
134
124
|
content=content,
|
|
135
125
|
done=history.is_done(),
|
|
136
|
-
error=content if successful is False else None,
|
|
137
126
|
),
|
|
138
127
|
)
|
|
139
128
|
|
|
@@ -7,15 +7,15 @@ from .agent import (
|
|
|
7
7
|
AsyncAnthropicBedrock,
|
|
8
8
|
ClaudeAgent,
|
|
9
9
|
)
|
|
10
|
-
from .sdk import
|
|
10
|
+
from .sdk import ClaudeCLIAgent, ClaudeCLIConfig
|
|
11
11
|
from .tools import ClaudeToolSearchTool, ClaudeWebFetchTool, ClaudeWebSearchTool
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
14
|
"AsyncAnthropic",
|
|
15
15
|
"AsyncAnthropicBedrock",
|
|
16
16
|
"ClaudeAgent",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"ClaudeCLIAgent",
|
|
18
|
+
"ClaudeCLIConfig",
|
|
19
19
|
"ClaudeToolSearchTool",
|
|
20
20
|
"ClaudeWebFetchTool",
|
|
21
21
|
"ClaudeWebSearchTool",
|
|
@@ -8,7 +8,7 @@ import json
|
|
|
8
8
|
import logging
|
|
9
9
|
import math
|
|
10
10
|
from random import SystemRandom
|
|
11
|
-
from typing import TYPE_CHECKING,
|
|
11
|
+
from typing import TYPE_CHECKING, cast
|
|
12
12
|
|
|
13
13
|
import httpx
|
|
14
14
|
import httpx2
|
|
@@ -23,7 +23,6 @@ from anthropic import (
|
|
|
23
23
|
)
|
|
24
24
|
from anthropic.types import CacheControlEphemeralParam
|
|
25
25
|
from anthropic.types.beta import (
|
|
26
|
-
BetaBase64ImageSourceParam,
|
|
27
26
|
BetaBase64PDFSourceParam,
|
|
28
27
|
BetaImageBlockParam,
|
|
29
28
|
BetaMessage,
|
|
@@ -35,12 +34,14 @@ from anthropic.types.beta import (
|
|
|
35
34
|
BetaToolResultBlockParam,
|
|
36
35
|
BetaToolUnionParam,
|
|
37
36
|
)
|
|
37
|
+
from PIL import Image
|
|
38
38
|
|
|
39
39
|
from hud.agents.tool_agent import RunState, ToolAgent
|
|
40
40
|
from hud.agents.types import AgentStep, Citation, ClaudeConfig, Usage
|
|
41
41
|
from hud.types import MCPToolCall, MCPToolResult
|
|
42
42
|
from hud.utils import gateway
|
|
43
43
|
|
|
44
|
+
from .images import image_source
|
|
44
45
|
from .tools.coding import ClaudeBashTool, ClaudeTextEditorTool
|
|
45
46
|
from .tools.computer import ClaudeComputerTool
|
|
46
47
|
from .tools.mcp_proxy import ClaudeMCPProxyTool
|
|
@@ -48,9 +49,9 @@ from .tools.mcp_proxy import ClaudeMCPProxyTool
|
|
|
48
49
|
if TYPE_CHECKING:
|
|
49
50
|
from anthropic.types.beta import BetaTextCitation
|
|
50
51
|
|
|
52
|
+
|
|
51
53
|
logger = logging.getLogger(__name__)
|
|
52
54
|
|
|
53
|
-
ClaudeImageMediaType = Literal["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
54
55
|
ClaudeToolResultContent = BetaTextBlockParam | BetaImageBlockParam | BetaRequestDocumentBlockParam
|
|
55
56
|
|
|
56
57
|
_RETRYABLE_STREAM_ERROR_TYPES = frozenset(
|
|
@@ -93,6 +94,7 @@ def _stream_retry_delay(attempt: int, error: Exception) -> float:
|
|
|
93
94
|
class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
94
95
|
"""Anthropic Claude agent. Drives SSH (coding), RFB (computer), and MCP capabilities."""
|
|
95
96
|
|
|
97
|
+
config_cls = ClaudeConfig
|
|
96
98
|
tool_catalog = (
|
|
97
99
|
ClaudeBashTool,
|
|
98
100
|
ClaudeTextEditorTool,
|
|
@@ -101,7 +103,7 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
101
103
|
)
|
|
102
104
|
|
|
103
105
|
def __init__(self, config: ClaudeConfig | None = None) -> None:
|
|
104
|
-
|
|
106
|
+
super().__init__(config)
|
|
105
107
|
self.anthropic_client: AsyncAnthropic | AsyncAnthropicBedrock = self._resolve_client()
|
|
106
108
|
|
|
107
109
|
def _resolve_client(self) -> AsyncAnthropic | AsyncAnthropicBedrock:
|
|
@@ -138,6 +140,7 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
138
140
|
return None
|
|
139
141
|
|
|
140
142
|
result_content = result.content
|
|
143
|
+
image_error = False
|
|
141
144
|
if result.isError:
|
|
142
145
|
error_msg = next(
|
|
143
146
|
(c.text for c in result.content if isinstance(c, mcp_types.TextContent)),
|
|
@@ -166,14 +169,19 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
166
169
|
citations={"enabled": True},
|
|
167
170
|
)
|
|
168
171
|
case mcp_types.ImageContent():
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
try:
|
|
173
|
+
block = BetaImageBlockParam(
|
|
174
|
+
type="image",
|
|
175
|
+
source=image_source(
|
|
176
|
+
content,
|
|
177
|
+
preserve_dimensions=isinstance(
|
|
178
|
+
state.tools.get(call.name), ClaudeComputerTool
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
except (ValueError, OSError, Image.DecompressionBombError) as exc:
|
|
183
|
+
image_error = True
|
|
184
|
+
block = BetaTextBlockParam(type="text", text=f"Cannot view image: {exc}")
|
|
177
185
|
case mcp_types.EmbeddedResource(
|
|
178
186
|
resource=mcp_types.BlobResourceContents(mimeType="application/pdf") as resource,
|
|
179
187
|
):
|
|
@@ -205,6 +213,7 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
205
213
|
type="tool_result",
|
|
206
214
|
tool_use_id=tool_use_id,
|
|
207
215
|
content=claude_blocks,
|
|
216
|
+
is_error=bool(result.isError) or image_error,
|
|
208
217
|
),
|
|
209
218
|
],
|
|
210
219
|
)
|
|
@@ -360,26 +369,36 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
360
369
|
if response is None:
|
|
361
370
|
raise ValueError("Claude response missing after retries")
|
|
362
371
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
372
|
+
return self.message_to_agent_step(response, citations_enabled=citations_enabled)
|
|
373
|
+
|
|
374
|
+
@classmethod
|
|
375
|
+
def message_to_agent_step(
|
|
376
|
+
cls,
|
|
377
|
+
response: BetaMessage,
|
|
378
|
+
*,
|
|
379
|
+
citations_enabled: bool = False,
|
|
380
|
+
) -> AgentStep:
|
|
381
|
+
result = AgentStep(
|
|
382
|
+
content="",
|
|
383
|
+
done=True,
|
|
384
|
+
model=response.model,
|
|
385
|
+
usage=Usage(
|
|
386
|
+
prompt_tokens=response.usage.input_tokens,
|
|
387
|
+
completion_tokens=response.usage.output_tokens,
|
|
388
|
+
cached_tokens=response.usage.cache_read_input_tokens,
|
|
389
|
+
),
|
|
369
390
|
)
|
|
370
391
|
text_parts: list[str] = []
|
|
371
392
|
thinking_parts: list[str] = []
|
|
372
|
-
citations: list[Citation] = []
|
|
373
393
|
|
|
374
394
|
for block in response.content:
|
|
375
395
|
match block.type:
|
|
376
396
|
case "tool_use":
|
|
377
|
-
arguments = dict(block.input) if block.input else {}
|
|
378
397
|
result.tool_calls.append(
|
|
379
398
|
MCPToolCall(
|
|
380
399
|
id=block.id,
|
|
381
400
|
name=block.name,
|
|
382
|
-
arguments=
|
|
401
|
+
arguments=dict(block.input) if block.input else {},
|
|
383
402
|
_meta=mcp_types.RequestParams.Meta.model_validate(
|
|
384
403
|
{"citations_enabled": citations_enabled},
|
|
385
404
|
),
|
|
@@ -387,9 +406,8 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
387
406
|
)
|
|
388
407
|
result.done = False
|
|
389
408
|
case "text":
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
citations.extend(self._citation(c) for c in (text_block.citations or []))
|
|
409
|
+
text_parts.append(block.text)
|
|
410
|
+
result.citations.extend(cls._citation(c) for c in (block.citations or []))
|
|
393
411
|
case "thinking":
|
|
394
412
|
if block.thinking:
|
|
395
413
|
thinking_parts.append(block.thinking)
|
|
@@ -397,7 +415,6 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
397
415
|
pass
|
|
398
416
|
|
|
399
417
|
result.content = "".join(text_parts)
|
|
400
|
-
result.citations = citations
|
|
401
418
|
if thinking_parts:
|
|
402
419
|
result.reasoning = "\n".join(thinking_parts)
|
|
403
420
|
result.finish_reason = response.stop_reason
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Image input preparation for Anthropic Messages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import math
|
|
7
|
+
from io import BytesIO
|
|
8
|
+
from typing import TYPE_CHECKING, Literal, cast
|
|
9
|
+
|
|
10
|
+
from anthropic.types.beta import BetaBase64ImageSourceParam
|
|
11
|
+
from PIL import Image, ImageOps
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from mcp.types import ImageContent
|
|
15
|
+
|
|
16
|
+
ClaudeImageMediaType = Literal["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
17
|
+
MAX_SOURCE_IMAGE_PIXELS = 16_000_000
|
|
18
|
+
MAX_IMAGE_EDGE = 1568
|
|
19
|
+
MAX_IMAGE_PIXELS = 1_150_000
|
|
20
|
+
MAX_IMAGE_BASE64_BYTES = 5_000_000
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def image_source(
|
|
24
|
+
content: ImageContent, *, preserve_dimensions: bool = False
|
|
25
|
+
) -> BetaBase64ImageSourceParam:
|
|
26
|
+
"""Prepare a tool image, preserving computer-tool coordinate space when requested."""
|
|
27
|
+
if preserve_dimensions:
|
|
28
|
+
return BetaBase64ImageSourceParam(
|
|
29
|
+
type="base64",
|
|
30
|
+
media_type=cast("ClaudeImageMediaType", content.mimeType),
|
|
31
|
+
data=content.data,
|
|
32
|
+
)
|
|
33
|
+
with Image.open(BytesIO(base64.b64decode(content.data, validate=True))) as image:
|
|
34
|
+
if image.width * image.height > MAX_SOURCE_IMAGE_PIXELS:
|
|
35
|
+
raise ValueError(
|
|
36
|
+
f"Image exceeds the {MAX_SOURCE_IMAGE_PIXELS:,}-pixel source limit. "
|
|
37
|
+
"Resize or crop it before viewing."
|
|
38
|
+
)
|
|
39
|
+
return _encode_image(image)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _encode_image(image: Image.Image) -> BetaBase64ImageSourceParam:
|
|
43
|
+
scale = min(
|
|
44
|
+
1.0,
|
|
45
|
+
MAX_IMAGE_EDGE / max(image.size),
|
|
46
|
+
math.sqrt(MAX_IMAGE_PIXELS / (image.width * image.height)),
|
|
47
|
+
)
|
|
48
|
+
image.thumbnail(
|
|
49
|
+
(max(1, int(image.width * scale)), max(1, int(image.height * scale))),
|
|
50
|
+
Image.Resampling.LANCZOS,
|
|
51
|
+
)
|
|
52
|
+
image = ImageOps.exif_transpose(image)
|
|
53
|
+
image = image.convert("RGBA" if image.has_transparency_data else "RGB")
|
|
54
|
+
buffer = BytesIO()
|
|
55
|
+
image.save(buffer, format="PNG", optimize=True)
|
|
56
|
+
data = base64.b64encode(buffer.getvalue()).decode("ascii")
|
|
57
|
+
mime_type: ClaudeImageMediaType = "image/png"
|
|
58
|
+
if len(data) > MAX_IMAGE_BASE64_BYTES:
|
|
59
|
+
background = Image.new("RGB", image.size, "white")
|
|
60
|
+
background.paste(image, mask=image.getchannel("A") if image.mode == "RGBA" else None)
|
|
61
|
+
buffer = BytesIO()
|
|
62
|
+
background.save(buffer, format="JPEG", quality=85, optimize=True)
|
|
63
|
+
data = base64.b64encode(buffer.getvalue()).decode("ascii")
|
|
64
|
+
mime_type = "image/jpeg"
|
|
65
|
+
return BetaBase64ImageSourceParam(type="base64", media_type=mime_type, data=data)
|