hud 0.6.16.dev2__tar.gz → 0.6.16.dev3__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.16.dev2 → hud-0.6.16.dev3}/PKG-INFO +2 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/agent.py +82 -9
- hud-0.6.16.dev3/hud/agents/claude/tools/base.py +26 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/coding.py +89 -9
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/computer.py +102 -4
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/tests/test_computer.py +18 -4
- hud-0.6.16.dev3/hud/agents/tests/test_claude_agent.py +261 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_provider_native_tools.py +19 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/eval.py +2 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/jobs.py +2 -1
- hud-0.6.16.dev3/hud/cli/qa.py +218 -0
- hud-0.6.16.dev3/hud/cli/tests/test_jobs.py +38 -0
- hud-0.6.16.dev3/hud/cli/tests/test_qa.py +190 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/trace.py +2 -2
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/egress.py +10 -8
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/namespace.py +3 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/robot/gym.py +1 -1
- hud-0.6.16.dev3/hud/environment/tests/test_platform.py +52 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_robot_regressions.py +52 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_workspace.py +3 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/job.py +2 -2
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/run.py +8 -7
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/__init__.py +0 -2
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/core.py +12 -26
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/daytona.py +22 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/docker.py +50 -19
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/local.py +60 -25
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/modal.py +52 -21
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_docker_provider.py +185 -7
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_job.py +19 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_local_runtime.py +71 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_rollout.py +17 -16
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/robot/recorder.py +11 -3
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/platform.py +12 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/process.py +77 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/requests.py +9 -2
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_platform.py +18 -2
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_process.py +39 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_requests.py +16 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/version.py +1 -1
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/pyproject.toml +1 -0
- hud-0.6.16.dev2/hud/agents/claude/tools/base.py +0 -17
- hud-0.6.16.dev2/hud/agents/tests/test_claude_agent.py +0 -144
- hud-0.6.16.dev2/hud/cli/qa.py +0 -193
- hud-0.6.16.dev2/hud/cli/tests/test_qa.py +0 -171
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/.gitignore +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/LICENSE +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/README.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/__main__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/browser_use/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/browser_use/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/sdk/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/sdk/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/sdk/computer_mcp.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/mcp_proxy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/settings.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/claude/tools/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/settings.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/coding.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/computer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/filesystem.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/gemini/tools/tests/test_computer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/misc/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/misc/response_automation.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/apply_patch.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/coding.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/computer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/mcp_proxy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/strict_schema.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/tests/test_computer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/tools/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/tools/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/tools/filesystem.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/openai_compatible/tools/mcp_proxy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/adapter.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/batching.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/dataset.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/robot/model.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_apply_patch.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_claude_sdk_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_gemini_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_openai_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_openai_compatible_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_robot_dataset_writer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_tool_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tests/test_trace.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tool_agent.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/mcp.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/rfb.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/tools/ssh.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/agents/types.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/cdp.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/mcp.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/rfb.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/robot.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/ssh.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/tests/test_rfb.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/capabilities/tests/test_ssh.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/__main__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/cancel.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/client.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/deploy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/init.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/login.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/models.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/presets.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/serve.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/sync.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/task.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/templates.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_cli_init.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_cli_main.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_deploy.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_eval_bedrock.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_eval_config.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_init.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_main_module.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_sync_export.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_trace.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/tests/test_usage.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/api.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/build_display.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/build_logs.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/config.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/context.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/display.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/jobs.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/registry.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/source.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tasks.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_build_display.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_config.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_context.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_registry.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_source.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_tasks.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/tests/test_version_check.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/usage.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/cli/utils/version_check.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/clients/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/clients/client.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/clients/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/clients/tests/test_connect.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/conftest.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/arguments.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/env.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/file_tracker.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/robot/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/robot/bridge.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/robot/endpoint.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/server.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/conftest.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_arguments.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_capability_backing.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_file_tracker.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_file_tracking.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_loader.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_manifest.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_server.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_sessions.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/tests/test_tunnel.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/utils.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/environment/workspace.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/chat.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/docker-seccomp.json +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/file_tracking.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/compose.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/runtime/hud.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/sync.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/task.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/taskset.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_chat.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_file_tracking_observer.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_hosted.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_shared.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_sync.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/eval/tests/test_task.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/bash.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/combine.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/judge.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/results.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/graders/text.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/adapt.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/env.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/export.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/install.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/conftest.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/docker-compose.yaml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/docker-compose.yaml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/test_contract.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/test_harbor.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/integrations/harbor/tests/test_integration.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/patches/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/patches/mcp_patches.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/patches/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/patches/tests/test_warnings.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/patches/warnings.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/py.typed +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/settings.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/context.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/exporter.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/instrument.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/robot/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/robot/video.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/span.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/tests/test_exporter.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/base.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/client.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/tests/test_client.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/train/types.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/types.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/docker.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/exceptions.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/gateway.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/hints.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/hud_console.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/modules.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/naming.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/serialization.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/__init__.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_exceptions.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_gateway.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_hints.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_hud_console.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/tests/test_serialization.py +0 -0
- {hud-0.6.16.dev2 → hud-0.6.16.dev3}/hud/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hud
|
|
3
|
-
Version: 0.6.16.
|
|
3
|
+
Version: 0.6.16.dev3
|
|
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
|
|
@@ -39,6 +39,7 @@ Requires-Dist: asyncssh>=2.23.0
|
|
|
39
39
|
Requires-Dist: asyncvnc>=1.3.0
|
|
40
40
|
Requires-Dist: fastmcp==3.2.0
|
|
41
41
|
Requires-Dist: google-genai
|
|
42
|
+
Requires-Dist: httpx2<3,>=2.0.0
|
|
42
43
|
Requires-Dist: httpx<1,>=0.23.0
|
|
43
44
|
Requires-Dist: mcp<2.0,>=1.24.0
|
|
44
45
|
Requires-Dist: openai>=2.45.0
|
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import copy
|
|
6
7
|
import json
|
|
7
8
|
import logging
|
|
8
9
|
from typing import TYPE_CHECKING, Literal, cast
|
|
9
10
|
|
|
11
|
+
import httpx
|
|
12
|
+
import httpx2
|
|
10
13
|
import mcp.types as mcp_types
|
|
11
|
-
from anthropic import
|
|
14
|
+
from anthropic import (
|
|
15
|
+
APIConnectionError,
|
|
16
|
+
APIStatusError,
|
|
17
|
+
APITimeoutError,
|
|
18
|
+
AsyncAnthropic,
|
|
19
|
+
AsyncAnthropicBedrock,
|
|
20
|
+
Omit,
|
|
21
|
+
)
|
|
12
22
|
from anthropic.types import CacheControlEphemeralParam
|
|
13
23
|
from anthropic.types.beta import (
|
|
14
24
|
BetaBase64ImageSourceParam,
|
|
@@ -42,6 +52,19 @@ logger = logging.getLogger(__name__)
|
|
|
42
52
|
ClaudeImageMediaType = Literal["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
43
53
|
ClaudeToolResultContent = BetaTextBlockParam | BetaImageBlockParam | BetaRequestDocumentBlockParam
|
|
44
54
|
|
|
55
|
+
_RETRYABLE_STREAM_ERROR_TYPES = frozenset(
|
|
56
|
+
{
|
|
57
|
+
"api_error",
|
|
58
|
+
"gateway_error",
|
|
59
|
+
"gateway_timeout",
|
|
60
|
+
"overloaded_error",
|
|
61
|
+
"rate_limit_error",
|
|
62
|
+
"timeout_error",
|
|
63
|
+
"upstream_error",
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
_STREAM_RETRY_DELAY_SECONDS = 1.0
|
|
67
|
+
|
|
45
68
|
|
|
46
69
|
class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
47
70
|
"""Anthropic Claude agent. Drives SSH (coding), RFB (computer), and MCP capabilities."""
|
|
@@ -168,6 +191,60 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
168
191
|
|
|
169
192
|
# ─── Anthropic call ───────────────────────────────────────────────
|
|
170
193
|
|
|
194
|
+
async def _stream_response(
|
|
195
|
+
self,
|
|
196
|
+
client: AsyncAnthropic,
|
|
197
|
+
*,
|
|
198
|
+
messages: list[BetaMessageParam],
|
|
199
|
+
system: str | Omit,
|
|
200
|
+
tools: list[BetaToolUnionParam],
|
|
201
|
+
tool_choice: BetaToolChoiceAutoParam,
|
|
202
|
+
betas: list[str] | Omit,
|
|
203
|
+
) -> BetaMessage:
|
|
204
|
+
retries = 0
|
|
205
|
+
while True:
|
|
206
|
+
stream_opened = False
|
|
207
|
+
try:
|
|
208
|
+
async with client.beta.messages.stream(
|
|
209
|
+
model=self.config.model,
|
|
210
|
+
system=system,
|
|
211
|
+
max_tokens=self.config.max_tokens,
|
|
212
|
+
messages=messages,
|
|
213
|
+
tools=tools,
|
|
214
|
+
tool_choice=tool_choice,
|
|
215
|
+
betas=betas,
|
|
216
|
+
) as stream:
|
|
217
|
+
stream_opened = True
|
|
218
|
+
async for _ in stream:
|
|
219
|
+
pass
|
|
220
|
+
return await stream.get_final_message()
|
|
221
|
+
except (
|
|
222
|
+
APIConnectionError,
|
|
223
|
+
APIStatusError,
|
|
224
|
+
APITimeoutError,
|
|
225
|
+
httpx.TransportError,
|
|
226
|
+
httpx2.TransportError,
|
|
227
|
+
) as exc:
|
|
228
|
+
inline_error = (
|
|
229
|
+
isinstance(exc, APIStatusError)
|
|
230
|
+
and exc.status_code == 200
|
|
231
|
+
and exc.type in _RETRYABLE_STREAM_ERROR_TYPES
|
|
232
|
+
)
|
|
233
|
+
interrupted_stream = stream_opened and isinstance(
|
|
234
|
+
exc,
|
|
235
|
+
APIConnectionError
|
|
236
|
+
| APITimeoutError
|
|
237
|
+
| httpx.TransportError
|
|
238
|
+
| httpx2.TransportError,
|
|
239
|
+
)
|
|
240
|
+
if retries or not (inline_error or interrupted_stream):
|
|
241
|
+
raise
|
|
242
|
+
|
|
243
|
+
retries += 1
|
|
244
|
+
error_type = exc.type if isinstance(exc, APIStatusError) else type(exc).__name__
|
|
245
|
+
logger.warning("Claude stream failed with %s; retrying once", error_type)
|
|
246
|
+
await asyncio.sleep(_STREAM_RETRY_DELAY_SECONDS)
|
|
247
|
+
|
|
171
248
|
async def get_response(
|
|
172
249
|
self,
|
|
173
250
|
state: RunState[BetaMessageParam],
|
|
@@ -202,18 +279,14 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
202
279
|
)
|
|
203
280
|
else:
|
|
204
281
|
client = cast("AsyncAnthropic", self.anthropic_client)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
system=system,
|
|
208
|
-
max_tokens=self.config.max_tokens,
|
|
282
|
+
response = await self._stream_response(
|
|
283
|
+
client,
|
|
209
284
|
messages=messages_cached,
|
|
285
|
+
system=system,
|
|
210
286
|
tools=tools,
|
|
211
287
|
tool_choice=tool_choice,
|
|
212
288
|
betas=betas,
|
|
213
|
-
)
|
|
214
|
-
async for _ in stream:
|
|
215
|
-
pass
|
|
216
|
-
response = await stream.get_final_message()
|
|
289
|
+
)
|
|
217
290
|
|
|
218
291
|
state.messages.append(
|
|
219
292
|
BetaMessageParam(role="assistant", content=response.content),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Claude-specific tool spec."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from hud.agents.tools.base import AgentToolSpec
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class ClaudeToolSpec(AgentToolSpec):
|
|
12
|
+
"""Claude tool spec — adds the optional Anthropic beta flag."""
|
|
13
|
+
|
|
14
|
+
beta: str | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def is_anthropic_model(model: str | None) -> bool:
|
|
18
|
+
"""Whether the model accepts Anthropic server-tool shorthands (``bash_20250124`` etc.).
|
|
19
|
+
|
|
20
|
+
Non-Anthropic models served over Anthropic-compatible endpoints (e.g. OpenRouter)
|
|
21
|
+
reject those shorthands, so tools fall back to plain ``input_schema`` definitions.
|
|
22
|
+
"""
|
|
23
|
+
return bool(model) and "claude" in model.lower()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
__all__ = ["ClaudeToolSpec", "is_anthropic_model"]
|
|
@@ -10,12 +10,13 @@ from hud.agents.tools import SSHTool
|
|
|
10
10
|
from hud.agents.tools.base import result_text, tool_err
|
|
11
11
|
from hud.types import MCPToolResult
|
|
12
12
|
|
|
13
|
-
from .base import ClaudeToolSpec
|
|
13
|
+
from .base import ClaudeToolSpec, is_anthropic_model
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from anthropic.types.beta import (
|
|
17
17
|
BetaToolBash20250124Param,
|
|
18
18
|
BetaToolTextEditor20250728Param,
|
|
19
|
+
BetaToolUnionParam,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
|
|
@@ -24,11 +25,64 @@ CLAUDE_BASH_SPEC = ClaudeToolSpec(
|
|
|
24
25
|
api_name="bash",
|
|
25
26
|
)
|
|
26
27
|
|
|
28
|
+
GENERIC_BASH_SPEC = ClaudeToolSpec(
|
|
29
|
+
api_type="function",
|
|
30
|
+
api_name="bash",
|
|
31
|
+
)
|
|
32
|
+
|
|
27
33
|
CLAUDE_TEXT_EDITOR_SPEC = ClaudeToolSpec(
|
|
28
34
|
api_type="text_editor_20250728",
|
|
29
35
|
api_name="str_replace_based_edit_tool",
|
|
30
36
|
)
|
|
31
37
|
|
|
38
|
+
GENERIC_TEXT_EDITOR_SPEC = ClaudeToolSpec(
|
|
39
|
+
api_type="function",
|
|
40
|
+
api_name="str_replace_based_edit_tool",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
_BASH_INPUT_SCHEMA: dict[str, Any] = {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
"command": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"description": "The bash command to run.",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
"required": ["command"],
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
_TEXT_EDITOR_INPUT_SCHEMA: dict[str, Any] = {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"properties": {
|
|
57
|
+
"command": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"enum": ["view", "create", "str_replace", "insert"],
|
|
60
|
+
"description": "The editor operation to run.",
|
|
61
|
+
},
|
|
62
|
+
"path": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "Absolute path to the file.",
|
|
65
|
+
},
|
|
66
|
+
"file_text": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"description": "Full file contents for `create`.",
|
|
69
|
+
},
|
|
70
|
+
"old_str": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"description": "Exact existing text to replace for `str_replace`; must be unique.",
|
|
73
|
+
},
|
|
74
|
+
"new_str": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"description": "Replacement text for `str_replace`, or text to insert for `insert`.",
|
|
77
|
+
},
|
|
78
|
+
"insert_line": {
|
|
79
|
+
"type": "integer",
|
|
80
|
+
"description": "Line number after which to insert for `insert` (0 = top of file).",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
"required": ["command", "path"],
|
|
84
|
+
}
|
|
85
|
+
|
|
32
86
|
|
|
33
87
|
class ClaudeBashTool(SSHTool):
|
|
34
88
|
"""Claude's native ``bash_20250124`` schema, executed over SSH."""
|
|
@@ -37,10 +91,18 @@ class ClaudeBashTool(SSHTool):
|
|
|
37
91
|
|
|
38
92
|
@classmethod
|
|
39
93
|
def default_spec(cls, model: str) -> ClaudeToolSpec:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
94
|
+
return CLAUDE_BASH_SPEC if is_anthropic_model(model) else GENERIC_BASH_SPEC
|
|
95
|
+
|
|
96
|
+
def to_params(self) -> BetaToolUnionParam:
|
|
97
|
+
if self.spec.api_type == "function":
|
|
98
|
+
return cast(
|
|
99
|
+
"BetaToolUnionParam",
|
|
100
|
+
{
|
|
101
|
+
"name": self.name,
|
|
102
|
+
"description": "Run a command in a bash shell on the remote machine.",
|
|
103
|
+
"input_schema": _BASH_INPUT_SCHEMA,
|
|
104
|
+
},
|
|
105
|
+
)
|
|
44
106
|
return cast(
|
|
45
107
|
"BetaToolBash20250124Param",
|
|
46
108
|
{"type": self.spec.api_type, "name": self.name},
|
|
@@ -77,14 +139,25 @@ class ClaudeTextEditorTool(SSHTool):
|
|
|
77
139
|
|
|
78
140
|
@classmethod
|
|
79
141
|
def default_spec(cls, model: str) -> ClaudeToolSpec:
|
|
80
|
-
|
|
81
|
-
return CLAUDE_TEXT_EDITOR_SPEC
|
|
142
|
+
return CLAUDE_TEXT_EDITOR_SPEC if is_anthropic_model(model) else GENERIC_TEXT_EDITOR_SPEC
|
|
82
143
|
|
|
83
144
|
@property
|
|
84
145
|
def provider_name(self) -> str:
|
|
85
146
|
return self.spec.api_name
|
|
86
147
|
|
|
87
|
-
def to_params(self) ->
|
|
148
|
+
def to_params(self) -> BetaToolUnionParam:
|
|
149
|
+
if self.spec.api_type == "function":
|
|
150
|
+
return cast(
|
|
151
|
+
"BetaToolUnionParam",
|
|
152
|
+
{
|
|
153
|
+
"name": self.provider_name,
|
|
154
|
+
"description": (
|
|
155
|
+
"View, create, and edit files on the remote machine "
|
|
156
|
+
"(view/create/str_replace/insert)."
|
|
157
|
+
),
|
|
158
|
+
"input_schema": _TEXT_EDITOR_INPUT_SCHEMA,
|
|
159
|
+
},
|
|
160
|
+
)
|
|
88
161
|
return cast(
|
|
89
162
|
"BetaToolTextEditor20250728Param",
|
|
90
163
|
{"type": self.spec.api_type, "name": self.provider_name},
|
|
@@ -142,4 +215,11 @@ class ClaudeTextEditorTool(SSHTool):
|
|
|
142
215
|
return await self.file_write(path, "".join(lines))
|
|
143
216
|
|
|
144
217
|
|
|
145
|
-
__all__ = [
|
|
218
|
+
__all__ = [
|
|
219
|
+
"CLAUDE_BASH_SPEC",
|
|
220
|
+
"CLAUDE_TEXT_EDITOR_SPEC",
|
|
221
|
+
"GENERIC_BASH_SPEC",
|
|
222
|
+
"GENERIC_TEXT_EDITOR_SPEC",
|
|
223
|
+
"ClaudeBashTool",
|
|
224
|
+
"ClaudeTextEditorTool",
|
|
225
|
+
]
|
|
@@ -19,12 +19,13 @@ from hud.agents.tools.base import tool_err, tool_ok
|
|
|
19
19
|
from hud.capabilities.rfb import ScreenshotEncoding, WebPScreenshotEncoding
|
|
20
20
|
from hud.types import MCPToolResult
|
|
21
21
|
|
|
22
|
-
from .base import ClaudeToolSpec
|
|
22
|
+
from .base import ClaudeToolSpec, is_anthropic_model
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
25
|
from anthropic.types.beta import (
|
|
26
26
|
BetaToolComputerUse20250124Param,
|
|
27
27
|
BetaToolComputerUse20251124Param,
|
|
28
|
+
BetaToolUnionParam,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
from hud.agents.tools.rfb import Button
|
|
@@ -110,9 +111,89 @@ CLAUDE_COMPUTER_SPECS: tuple[ClaudeToolSpec, ...] = (
|
|
|
110
111
|
),
|
|
111
112
|
)
|
|
112
113
|
|
|
113
|
-
# Fallback for unknown models — use the latest version.
|
|
114
|
+
# Fallback for unknown Claude models — use the latest version.
|
|
114
115
|
_DEFAULT_COMPUTER_SPEC = CLAUDE_COMPUTER_SPECS[0]
|
|
115
116
|
|
|
117
|
+
GENERIC_COMPUTER_SPEC = ClaudeToolSpec(
|
|
118
|
+
api_type="function",
|
|
119
|
+
api_name="computer",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
_COMPUTER_INPUT_SCHEMA: dict[str, Any] = {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"properties": {
|
|
125
|
+
"action": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"enum": [
|
|
128
|
+
"screenshot",
|
|
129
|
+
"zoom",
|
|
130
|
+
"left_click",
|
|
131
|
+
"right_click",
|
|
132
|
+
"middle_click",
|
|
133
|
+
"double_click",
|
|
134
|
+
"triple_click",
|
|
135
|
+
"mouse_move",
|
|
136
|
+
"left_mouse_down",
|
|
137
|
+
"left_mouse_up",
|
|
138
|
+
"type",
|
|
139
|
+
"key",
|
|
140
|
+
"hold_key",
|
|
141
|
+
"scroll",
|
|
142
|
+
"left_click_drag",
|
|
143
|
+
"wait",
|
|
144
|
+
"cursor_position",
|
|
145
|
+
],
|
|
146
|
+
"description": "The action to perform on the screen.",
|
|
147
|
+
},
|
|
148
|
+
"coordinate": {
|
|
149
|
+
"type": "array",
|
|
150
|
+
"items": {"type": "integer"},
|
|
151
|
+
"minItems": 2,
|
|
152
|
+
"maxItems": 2,
|
|
153
|
+
"description": "[x, y] pixel coordinate for click/move/scroll, or drag end point.",
|
|
154
|
+
},
|
|
155
|
+
"start_coordinate": {
|
|
156
|
+
"type": "array",
|
|
157
|
+
"items": {"type": "integer"},
|
|
158
|
+
"minItems": 2,
|
|
159
|
+
"maxItems": 2,
|
|
160
|
+
"description": "[x, y] drag start point for `left_click_drag`.",
|
|
161
|
+
},
|
|
162
|
+
"text": {
|
|
163
|
+
"type": "string",
|
|
164
|
+
"description": (
|
|
165
|
+
"Text to type for `type`; key chord (xdotool syntax, e.g. `ctrl+s`) for "
|
|
166
|
+
"`key`/`hold_key`; optional modifier keys held during clicks and scrolls."
|
|
167
|
+
),
|
|
168
|
+
},
|
|
169
|
+
"duration": {
|
|
170
|
+
"type": "number",
|
|
171
|
+
"description": "Seconds to hold for `hold_key` or pause for `wait`.",
|
|
172
|
+
},
|
|
173
|
+
"scroll_direction": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"enum": ["up", "down", "left", "right"],
|
|
176
|
+
"description": "Direction for `scroll`.",
|
|
177
|
+
},
|
|
178
|
+
"scroll_amount": {
|
|
179
|
+
"type": "integer",
|
|
180
|
+
"description": "Number of scroll clicks for `scroll`.",
|
|
181
|
+
},
|
|
182
|
+
"repeat": {
|
|
183
|
+
"type": "integer",
|
|
184
|
+
"description": "Times to repeat the key chord for `key`.",
|
|
185
|
+
},
|
|
186
|
+
"region": {
|
|
187
|
+
"type": "array",
|
|
188
|
+
"items": {"type": "integer"},
|
|
189
|
+
"minItems": 4,
|
|
190
|
+
"maxItems": 4,
|
|
191
|
+
"description": "[x0, y0, x1, y1] region to magnify for `zoom`.",
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
"required": ["action"],
|
|
195
|
+
}
|
|
196
|
+
|
|
116
197
|
|
|
117
198
|
class ClaudeComputerTool(RFBTool):
|
|
118
199
|
"""Claude's native ``computer_use`` schema, executed over an RFB capability."""
|
|
@@ -121,12 +202,29 @@ class ClaudeComputerTool(RFBTool):
|
|
|
121
202
|
|
|
122
203
|
@classmethod
|
|
123
204
|
def default_spec(cls, model: str) -> ClaudeToolSpec | None:
|
|
205
|
+
if not is_anthropic_model(model):
|
|
206
|
+
return GENERIC_COMPUTER_SPEC
|
|
124
207
|
for candidate in CLAUDE_COMPUTER_SPECS:
|
|
125
208
|
if candidate.supports_model(model):
|
|
126
209
|
return candidate
|
|
127
210
|
return _DEFAULT_COMPUTER_SPEC
|
|
128
211
|
|
|
129
|
-
def to_params(
|
|
212
|
+
def to_params(
|
|
213
|
+
self,
|
|
214
|
+
) -> BetaToolComputerUse20250124Param | BetaToolComputerUse20251124Param | BetaToolUnionParam:
|
|
215
|
+
if self.spec.api_type == "function":
|
|
216
|
+
return cast(
|
|
217
|
+
"BetaToolUnionParam",
|
|
218
|
+
{
|
|
219
|
+
"name": self.name,
|
|
220
|
+
"description": (
|
|
221
|
+
"Control the remote computer's screen, mouse, and keyboard. "
|
|
222
|
+
f"The display is {self.display_width}x{self.display_height} pixels. "
|
|
223
|
+
"Most actions return a screenshot of the result."
|
|
224
|
+
),
|
|
225
|
+
"input_schema": _COMPUTER_INPUT_SCHEMA,
|
|
226
|
+
},
|
|
227
|
+
)
|
|
130
228
|
if self.spec.api_type == "computer_20251124":
|
|
131
229
|
return cast(
|
|
132
230
|
"BetaToolComputerUse20251124Param",
|
|
@@ -375,4 +473,4 @@ def _crop_png(
|
|
|
375
473
|
return buf.getvalue(), encoding.mime_type
|
|
376
474
|
|
|
377
475
|
|
|
378
|
-
__all__ = ["CLAUDE_COMPUTER_SPECS", "ClaudeComputerTool"]
|
|
476
|
+
__all__ = ["CLAUDE_COMPUTER_SPECS", "GENERIC_COMPUTER_SPEC", "ClaudeComputerTool"]
|
|
@@ -14,6 +14,7 @@ from PIL import Image
|
|
|
14
14
|
|
|
15
15
|
from hud.agents.claude.tools.computer import (
|
|
16
16
|
CLAUDE_COMPUTER_SPECS,
|
|
17
|
+
GENERIC_COMPUTER_SPEC,
|
|
17
18
|
ClaudeComputerTool,
|
|
18
19
|
_crop_png,
|
|
19
20
|
_hold_keys,
|
|
@@ -120,18 +121,31 @@ def test_default_spec_per_model() -> None:
|
|
|
120
121
|
spec_45 = ClaudeComputerTool.default_spec("claude-sonnet-4-5-20250101")
|
|
121
122
|
assert spec_45 is not None
|
|
122
123
|
assert spec_45.api_type == "computer_20250124"
|
|
123
|
-
# Unknown model falls back to the latest spec.
|
|
124
|
-
spec_unknown = ClaudeComputerTool.default_spec("totally-unknown")
|
|
124
|
+
# Unknown Claude model falls back to the latest spec.
|
|
125
|
+
spec_unknown = ClaudeComputerTool.default_spec("claude-totally-unknown")
|
|
125
126
|
assert spec_unknown is not None
|
|
126
127
|
assert spec_unknown.api_type == "computer_20251124"
|
|
128
|
+
# Non-Anthropic models get the generic input_schema spec.
|
|
129
|
+
assert ClaudeComputerTool.default_spec("qwen/qwen3.8-max") is GENERIC_COMPUTER_SPEC
|
|
127
130
|
|
|
128
131
|
|
|
129
132
|
def test_to_params_reflects_spec_version() -> None:
|
|
130
133
|
tool = RecordingComputer()
|
|
131
134
|
tool.spec = CLAUDE_COMPUTER_SPECS[0]
|
|
132
|
-
assert tool.to_params()
|
|
135
|
+
assert tool.to_params().get("type") == "computer_20251124"
|
|
133
136
|
tool.spec = CLAUDE_COMPUTER_SPECS[1]
|
|
134
|
-
assert tool.to_params()
|
|
137
|
+
assert tool.to_params().get("type") == "computer_20250124"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_to_params_generic_spec_uses_input_schema() -> None:
|
|
141
|
+
tool = RecordingComputer()
|
|
142
|
+
tool.spec = GENERIC_COMPUTER_SPEC
|
|
143
|
+
params: Any = tool.to_params()
|
|
144
|
+
assert "type" not in params
|
|
145
|
+
assert params["name"] == "computer"
|
|
146
|
+
assert "200x100" in params["description"]
|
|
147
|
+
assert params["input_schema"]["required"] == ["action"]
|
|
148
|
+
assert "left_click" in params["input_schema"]["properties"]["action"]["enum"]
|
|
135
149
|
|
|
136
150
|
|
|
137
151
|
# ─── action dispatch ──────────────────────────────────────────────────
|