hud 0.6.18.dev1__tar.gz → 0.6.19.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/PKG-INFO +13 -15
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/README.md +11 -13
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/__init__.py +2 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/__init__.py +20 -41
- hud-0.6.19.dev1/hud/agents/base.py +47 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/browser_use/agent.py +2 -13
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/__init__.py +3 -3
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/agent.py +24 -14
- hud-0.6.19.dev1/hud/agents/claude/sdk/__init__.py +7 -0
- hud-0.6.19.dev1/hud/agents/claude/sdk/agent.py +219 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/sdk/computer_mcp.py +50 -108
- hud-0.6.19.dev1/hud/agents/claude/sdk/events.py +128 -0
- hud-0.6.19.dev1/hud/agents/cli.py +141 -0
- hud-0.6.19.dev1/hud/agents/codex/__init__.py +7 -0
- hud-0.6.19.dev1/hud/agents/codex/agent.py +336 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/agent.py +7 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/agent.py +4 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/agent.py +14 -19
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/agent.py +0 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/batching.py +1 -0
- hud-0.6.19.dev1/hud/agents/tests/cli_fakes.py +111 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_base.py +37 -14
- hud-0.6.19.dev1/hud/agents/tests/test_claude_cli_agent.py +835 -0
- hud-0.6.19.dev1/hud/agents/tests/test_codex_cli_agent.py +381 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_gemini_agent.py +16 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_openai_compatible_agent.py +4 -3
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_tool_agent.py +54 -18
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tool_agent.py +38 -92
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/ssh.py +1 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/types.py +59 -33
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/__init__.py +2 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/base.py +3 -0
- hud-0.6.19.dev1/hud/capabilities/connection.py +106 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/ssh.py +38 -4
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/tests/test_ssh.py +51 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/eval.py +26 -18
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_eval.py +272 -5
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/clients/client.py +42 -7
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/clients/tests/test_connect.py +85 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/__init__.py +23 -8
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/egress.py +241 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/env.py +168 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/namespace.py +77 -29
- hud-0.6.19.dev1/hud/environment/process_guard.py +723 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/server.py +45 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_loader.py +140 -0
- hud-0.6.19.dev1/hud/environment/tests/test_process_connection.py +368 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_sessions.py +73 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_workspace.py +419 -7
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/utils.py +16 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/workspace.py +297 -82
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/run.py +49 -30
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/__init__.py +2 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/compose.py +49 -4
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/docker.py +8 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/hosted.py +7 -13
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/local.py +25 -23
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_docker_provider.py +88 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_hosted.py +52 -20
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_local_runtime.py +115 -3
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_rollout.py +25 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_task.py +8 -4
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/test_integration.py +1 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/exporter.py +47 -29
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/tests/test_exporter.py +24 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/types.py +40 -19
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/gateway.py +27 -11
- hud-0.6.19.dev1/hud/utils/modules.py +122 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/process.py +57 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_gateway.py +18 -2
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/version.py +1 -1
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/pyproject.toml +1 -1
- hud-0.6.18.dev1/hud/agents/base.py +0 -22
- hud-0.6.18.dev1/hud/agents/claude/sdk/__init__.py +0 -5
- hud-0.6.18.dev1/hud/agents/claude/sdk/agent.py +0 -355
- hud-0.6.18.dev1/hud/agents/tests/test_claude_sdk_agent.py +0 -679
- hud-0.6.18.dev1/hud/utils/modules.py +0 -79
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/.gitignore +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/LICENSE +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/__main__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/browser_use/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/coding.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/hosted.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/settings.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/claude/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/settings.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/coding.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/filesystem.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/hosted.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/gemini/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/misc/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/misc/response_automation.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/apply_patch.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/coding.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/hosted.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/strict_schema.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/tests/test_computer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/tools/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/tools/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/tools/filesystem.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/openai_compatible/tools/mcp_proxy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/adapter.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/dataset.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/robot/model.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_apply_patch.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_claude_agent.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_openai_agent.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_provider_native_tools.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_robot_dataset_writer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tests/test_trace.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/hosted.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/mcp.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/agents/tools/rfb.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/cdp.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/mcp.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/rfb.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/robot.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/capabilities/tests/test_rfb.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/__main__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/deploy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/init.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/jobs.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/models.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/project.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/qa.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/serve.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/sync.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/task.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_cli.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_deploy.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_init.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_jobs.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_main.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_project.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_qa.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_sync.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_task.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/tests/test_trace.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/cli/trace.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/clients/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/clients/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/conftest.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/arguments.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/file_tracker.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/robot/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/robot/bridge.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/robot/endpoint.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/robot/gym.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/conftest.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_arguments.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_capability_backing.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_file_tracker.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_file_tracking.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_manifest.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_platform.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_robot_regressions.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_server.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/environment/tests/test_tunnel.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/chat.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/docker-seccomp.json +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/file_tracking.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/job.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/core.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/daytona.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/hud.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/runtime/modal.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/sync.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/task.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/taskset.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_chat.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_file_tracking_observer.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_job.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_shared.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/eval/tests/test_sync.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/bash.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/combine.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/judge.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/results.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/graders/text.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/adapt.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/env.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/export.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/install.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/conftest.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/instruction.md +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/task.toml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/agent-lifecycle/tests/test.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/docker-compose.yaml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/environment/mcp-server/server.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/instruction.md +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/solution/solve.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/task.toml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/hello-mcp/tests/test.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/environment/entrypoint.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/instruction.md +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/solution/solve.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/task.toml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/phase-boundary/tests/test.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/environment/docker-compose.yaml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/instruction.md +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/solution/solve.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/task.toml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/sidecar-reachability/tests/test.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/Dockerfile +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/environment/entrypoint.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/instruction.md +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/solution/solve.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/task.toml +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/tasks/verifier-lifecycle/tests/test.sh +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/test_contract.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/integrations/harbor/tests/test_harbor.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/patches/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/patches/mcp_patches.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/patches/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/patches/tests/test_warnings.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/patches/warnings.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/py.typed +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/settings.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/context.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/instrument.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/robot/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/robot/recorder.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/robot/video.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/span.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/base.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/client.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/tests/test_client.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/train/types.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/docker.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/exceptions.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/hints.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/hud_console.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/naming.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/platform.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/requests.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/serialization.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/__init__.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_exceptions.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_hints.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_hud_console.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_naming.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_platform.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_process.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_requests.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/hud/utils/tests/test_serialization.py +0 -0
- {hud-0.6.18.dev1 → hud-0.6.19.dev1}/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.dev1
|
|
4
4
|
Summary: SDK for the HUD platform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hud-evals/hud-python
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/hud-evals/hud-python/issues
|
|
@@ -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",
|
|
@@ -48,6 +48,7 @@ from .tools.mcp_proxy import ClaudeMCPProxyTool
|
|
|
48
48
|
if TYPE_CHECKING:
|
|
49
49
|
from anthropic.types.beta import BetaTextCitation
|
|
50
50
|
|
|
51
|
+
|
|
51
52
|
logger = logging.getLogger(__name__)
|
|
52
53
|
|
|
53
54
|
ClaudeImageMediaType = Literal["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
@@ -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:
|
|
@@ -360,26 +362,36 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
360
362
|
if response is None:
|
|
361
363
|
raise ValueError("Claude response missing after retries")
|
|
362
364
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
return self.message_to_agent_step(response, citations_enabled=citations_enabled)
|
|
366
|
+
|
|
367
|
+
@classmethod
|
|
368
|
+
def message_to_agent_step(
|
|
369
|
+
cls,
|
|
370
|
+
response: BetaMessage,
|
|
371
|
+
*,
|
|
372
|
+
citations_enabled: bool = False,
|
|
373
|
+
) -> AgentStep:
|
|
374
|
+
result = AgentStep(
|
|
375
|
+
content="",
|
|
376
|
+
done=True,
|
|
377
|
+
model=response.model,
|
|
378
|
+
usage=Usage(
|
|
379
|
+
prompt_tokens=response.usage.input_tokens,
|
|
380
|
+
completion_tokens=response.usage.output_tokens,
|
|
381
|
+
cached_tokens=response.usage.cache_read_input_tokens,
|
|
382
|
+
),
|
|
369
383
|
)
|
|
370
384
|
text_parts: list[str] = []
|
|
371
385
|
thinking_parts: list[str] = []
|
|
372
|
-
citations: list[Citation] = []
|
|
373
386
|
|
|
374
387
|
for block in response.content:
|
|
375
388
|
match block.type:
|
|
376
389
|
case "tool_use":
|
|
377
|
-
arguments = dict(block.input) if block.input else {}
|
|
378
390
|
result.tool_calls.append(
|
|
379
391
|
MCPToolCall(
|
|
380
392
|
id=block.id,
|
|
381
393
|
name=block.name,
|
|
382
|
-
arguments=
|
|
394
|
+
arguments=dict(block.input) if block.input else {},
|
|
383
395
|
_meta=mcp_types.RequestParams.Meta.model_validate(
|
|
384
396
|
{"citations_enabled": citations_enabled},
|
|
385
397
|
),
|
|
@@ -387,9 +399,8 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
387
399
|
)
|
|
388
400
|
result.done = False
|
|
389
401
|
case "text":
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
citations.extend(self._citation(c) for c in (text_block.citations or []))
|
|
402
|
+
text_parts.append(block.text)
|
|
403
|
+
result.citations.extend(cls._citation(c) for c in (block.citations or []))
|
|
393
404
|
case "thinking":
|
|
394
405
|
if block.thinking:
|
|
395
406
|
thinking_parts.append(block.thinking)
|
|
@@ -397,7 +408,6 @@ class ClaudeAgent(ToolAgent[BetaMessageParam, ClaudeConfig]):
|
|
|
397
408
|
pass
|
|
398
409
|
|
|
399
410
|
result.content = "".join(text_parts)
|
|
400
|
-
result.citations = citations
|
|
401
411
|
if thinking_parts:
|
|
402
412
|
result.reasoning = "\n".join(thinking_parts)
|
|
403
413
|
result.finish_reason = response.stop_reason
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""ClaudeCLIAgent — runs ``claude`` CLI over SSH inside the env workspace.
|
|
2
|
+
|
|
3
|
+
SSH-execs the ``claude`` CLI on the remote workspace so all built-in tools
|
|
4
|
+
(Bash, Read, Write, Edit, Glob, Grep) operate on the env's filesystem.
|
|
5
|
+
MCP capabilities from the manifest are written as MCP server config so the
|
|
6
|
+
CLI can call env-hosted MCP tools too.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import shlex
|
|
14
|
+
from contextlib import AsyncExitStack
|
|
15
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
16
|
+
|
|
17
|
+
import asyncssh
|
|
18
|
+
|
|
19
|
+
from hud.agents.base import Agent
|
|
20
|
+
from hud.agents.cli import (
|
|
21
|
+
PROCESS_BOUND_CREDENTIAL,
|
|
22
|
+
WINDOWS_SHELLS,
|
|
23
|
+
powershell,
|
|
24
|
+
powershell_quote,
|
|
25
|
+
resolve_executable,
|
|
26
|
+
run_jsonl,
|
|
27
|
+
)
|
|
28
|
+
from hud.agents.types import ClaudeCLIConfig
|
|
29
|
+
from hud.settings import settings
|
|
30
|
+
from hud.telemetry.context import get_trace_headers
|
|
31
|
+
from hud.utils.gateway import routes_to_gateway
|
|
32
|
+
from hud.utils.time import now_iso
|
|
33
|
+
|
|
34
|
+
from . import computer_mcp
|
|
35
|
+
from .events import ClaudeEvents
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from hud.capabilities import Connection, SSHClient
|
|
39
|
+
from hud.eval.run import Run
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
INPUT_PATH = ".hud_input.jsonl"
|
|
44
|
+
MCP_CONFIG_PATH = ".hud_mcp_config.json"
|
|
45
|
+
RUN_SCRIPT_PATH = ".hud_run.bat"
|
|
46
|
+
|
|
47
|
+
_MANAGED_CLAUDE_PATHS = {
|
|
48
|
+
"linux-x64": "/usr/local/lib/agents/claude/linux-x64/claude",
|
|
49
|
+
"linux-x64-musl": "/usr/local/lib/agents/claude/linux-x64-musl/claude",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ClaudeCLIAgent(Agent[ClaudeCLIConfig]):
|
|
54
|
+
"""Runs ``claude`` CLI over SSH inside the env workspace.
|
|
55
|
+
|
|
56
|
+
Stateless w.r.t. the env: driven by ``await agent(run)``. SSH is opened
|
|
57
|
+
live off the run. Environment MCP bindings are used directly; computer MCP
|
|
58
|
+
servers are bridged over the run's SSH connection.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
config_cls = ClaudeCLIConfig
|
|
62
|
+
|
|
63
|
+
async def __call__(self, run: Run) -> None:
|
|
64
|
+
ssh = cast("SSHClient", await run.client.open("ssh"))
|
|
65
|
+
manifest = run.client.manifest
|
|
66
|
+
assert manifest is not None
|
|
67
|
+
shell = ssh.capability.params.get("shell", "bash")
|
|
68
|
+
windows = shell in WINDOWS_SHELLS
|
|
69
|
+
connection: Connection | None = run.connections.get("inference")
|
|
70
|
+
executable = await resolve_executable(
|
|
71
|
+
ssh, "claude", _MANAGED_CLAUDE_PATHS, run.runtime_config
|
|
72
|
+
)
|
|
73
|
+
rfb_count = sum(cap.protocol.partition("/")[0] == "rfb" for cap in manifest.bindings)
|
|
74
|
+
|
|
75
|
+
async with AsyncExitStack() as resources:
|
|
76
|
+
mcp_servers: dict[str, dict[str, Any]] = {}
|
|
77
|
+
for cap in manifest.bindings:
|
|
78
|
+
family = cap.protocol.partition("/")[0]
|
|
79
|
+
if family == "mcp":
|
|
80
|
+
name = cap.name
|
|
81
|
+
transport = "http" if cap.params["transport"] == "streamable-http" else "sse"
|
|
82
|
+
server: dict[str, Any] = {"type": transport, "url": cap.url}
|
|
83
|
+
if token := cap.params.get("auth_token"):
|
|
84
|
+
server["headers"] = {"Authorization": f"Bearer {token}"}
|
|
85
|
+
elif family == "rfb":
|
|
86
|
+
name = "computer-use" if rfb_count == 1 else f"computer-use-{cap.name}"
|
|
87
|
+
server = await resources.enter_async_context(
|
|
88
|
+
computer_mcp.bridge_computer_mcp(
|
|
89
|
+
ssh,
|
|
90
|
+
run.client.binding(cap.name),
|
|
91
|
+
self.config.screenshot_encoding,
|
|
92
|
+
shell=shell,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
continue
|
|
97
|
+
if name in mcp_servers:
|
|
98
|
+
raise RuntimeError(f"duplicate MCP server name {name!r}")
|
|
99
|
+
mcp_servers[name] = server
|
|
100
|
+
|
|
101
|
+
env: dict[str, str] = {
|
|
102
|
+
"ANTHROPIC_MODEL": self.config.model,
|
|
103
|
+
"ANTHROPIC_SMALL_FAST_MODEL": self.config.model,
|
|
104
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
|
|
105
|
+
"DISABLE_AUTOUPDATER": "1",
|
|
106
|
+
"IS_SANDBOX": "1",
|
|
107
|
+
}
|
|
108
|
+
if connection is not None or routes_to_gateway(
|
|
109
|
+
"anthropic", gateway=self.config.gateway
|
|
110
|
+
):
|
|
111
|
+
if connection is not None:
|
|
112
|
+
# The relay injects the scoped credential; the process never sees it.
|
|
113
|
+
# AUTH_TOKEN sends Authorization: Bearer, the header Codex uses too.
|
|
114
|
+
env["ANTHROPIC_BASE_URL"] = connection.client_url
|
|
115
|
+
env["ANTHROPIC_AUTH_TOKEN"] = PROCESS_BOUND_CREDENTIAL
|
|
116
|
+
elif settings.api_key:
|
|
117
|
+
env["ANTHROPIC_BASE_URL"] = settings.hud_gateway_url
|
|
118
|
+
env["ANTHROPIC_API_KEY"] = settings.api_key
|
|
119
|
+
else:
|
|
120
|
+
raise ValueError("HUD_API_KEY is required for HUD gateway routing")
|
|
121
|
+
env["CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS"] = "1"
|
|
122
|
+
env["DISABLE_AUTO_COMPACT"] = "1"
|
|
123
|
+
# Alias every model tier so background requests never bypass the gateway.
|
|
124
|
+
env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = self.config.model
|
|
125
|
+
env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = self.config.model
|
|
126
|
+
env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = self.config.model
|
|
127
|
+
env["CLAUDE_CODE_SUBAGENT_MODEL"] = self.config.model
|
|
128
|
+
if connection is None and (trace_headers := get_trace_headers()):
|
|
129
|
+
env["ANTHROPIC_CUSTOM_HEADERS"] = "\n".join(
|
|
130
|
+
f"{name}: {value}" for name, value in trace_headers.items()
|
|
131
|
+
)
|
|
132
|
+
elif settings.anthropic_api_key:
|
|
133
|
+
env["ANTHROPIC_API_KEY"] = settings.anthropic_api_key
|
|
134
|
+
|
|
135
|
+
args = [
|
|
136
|
+
"--verbose",
|
|
137
|
+
"--input-format=stream-json",
|
|
138
|
+
"--output-format=stream-json",
|
|
139
|
+
"--print",
|
|
140
|
+
f"--permission-mode={self.config.permission_mode}",
|
|
141
|
+
]
|
|
142
|
+
if self.config.max_steps > 0:
|
|
143
|
+
args.append(f"--max-turns={self.config.max_steps}")
|
|
144
|
+
if self.config.system_prompt:
|
|
145
|
+
args.extend(["--system-prompt", self.config.system_prompt])
|
|
146
|
+
for tool in self.config.allowed_tools:
|
|
147
|
+
args.extend(["--allowedTools", tool])
|
|
148
|
+
if mcp_servers:
|
|
149
|
+
args.extend(["--mcp-config", MCP_CONFIG_PATH])
|
|
150
|
+
|
|
151
|
+
if windows:
|
|
152
|
+
script = ";".join(
|
|
153
|
+
[
|
|
154
|
+
*(f"$env:{key}={powershell_quote(value)}" for key, value in env.items()),
|
|
155
|
+
f"Get-Content -Raw -Encoding UTF8 {powershell_quote(INPUT_PATH)}"
|
|
156
|
+
f" | & {powershell_quote(executable)} "
|
|
157
|
+
f"{' '.join(powershell_quote(arg) for arg in args)}",
|
|
158
|
+
"exit $LASTEXITCODE",
|
|
159
|
+
]
|
|
160
|
+
)
|
|
161
|
+
command = powershell(script)
|
|
162
|
+
else:
|
|
163
|
+
env_prefix = " ".join(f"{key}={shlex.quote(value)}" for key, value in env.items())
|
|
164
|
+
cli = " ".join(shlex.quote(arg) for arg in [executable, *args])
|
|
165
|
+
invocation = f"{env_prefix} {cli}"
|
|
166
|
+
if connection is not None:
|
|
167
|
+
# A guarded connection is bound to the launched process, so exec the CLI itself.
|
|
168
|
+
invocation = f"exec env {invocation}"
|
|
169
|
+
command = f'export PATH="$HOME/.local/bin:$PATH"; {invocation}'
|
|
170
|
+
|
|
171
|
+
input_text = (
|
|
172
|
+
json.dumps(
|
|
173
|
+
{
|
|
174
|
+
"type": "user",
|
|
175
|
+
"message": {
|
|
176
|
+
"role": "user",
|
|
177
|
+
"content": [{"type": "text", "text": run.prompt_text}],
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
+ "\n"
|
|
182
|
+
)
|
|
183
|
+
files: list[str] = []
|
|
184
|
+
try:
|
|
185
|
+
if mcp_servers:
|
|
186
|
+
await ssh.write_text(
|
|
187
|
+
MCP_CONFIG_PATH, json.dumps({"mcpServers": mcp_servers}, indent=2)
|
|
188
|
+
)
|
|
189
|
+
files.append(MCP_CONFIG_PATH)
|
|
190
|
+
if windows:
|
|
191
|
+
await ssh.write_text(INPUT_PATH, input_text)
|
|
192
|
+
await ssh.write_text(RUN_SCRIPT_PATH, f"@echo off\r\n{command}\r\n")
|
|
193
|
+
files += [INPUT_PATH, RUN_SCRIPT_PATH]
|
|
194
|
+
command = f"cmd /c {RUN_SCRIPT_PATH}"
|
|
195
|
+
|
|
196
|
+
logger.info("SSH exec claude CLI (%d chars)", len(command))
|
|
197
|
+
events = ClaudeEvents(run, started_at=now_iso())
|
|
198
|
+
returncode, stderr = await run_jsonl(
|
|
199
|
+
ssh,
|
|
200
|
+
command,
|
|
201
|
+
events.consume,
|
|
202
|
+
input_text=None if windows else input_text,
|
|
203
|
+
connections=(connection,) if connection is not None else (),
|
|
204
|
+
)
|
|
205
|
+
logger.info("exit=%s stderr=%d", returncode, len(stderr))
|
|
206
|
+
events.finish(returncode=returncode, stderr=stderr)
|
|
207
|
+
finally:
|
|
208
|
+
if files:
|
|
209
|
+
if windows:
|
|
210
|
+
cleanup = f"cmd /c del /f /q {' '.join(files)} 2>nul"
|
|
211
|
+
else:
|
|
212
|
+
cleanup = "rm -f -- " + " ".join(shlex.quote(path) for path in files)
|
|
213
|
+
try:
|
|
214
|
+
await ssh.run(cleanup, check=False)
|
|
215
|
+
except (OSError, asyncssh.Error):
|
|
216
|
+
logger.warning("Failed to remove Claude CLI runtime files")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
__all__ = ["ClaudeCLIAgent"]
|