hud-python 0.5.18__tar.gz → 0.5.20__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_python-0.5.18 → hud_python-0.5.20}/PKG-INFO +6 -6
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/base.py +72 -41
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/claude.py +68 -33
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/gemini.py +12 -10
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/gemini_cua.py +14 -12
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/openai.py +20 -20
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/operator.py +25 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_claude.py +217 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/__init__.py +3 -3
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/build.py +16 -5
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_build.py +2 -2
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_build_module.py +4 -4
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/interactive.py +10 -8
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/validation.py +29 -21
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/scenarios.py +1 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_connection.py +1 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/patches/mcp_patches.py +2 -2
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/exceptions.py +7 -4
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/base.py +24 -6
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/bash.py +9 -21
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/edit.py +0 -3
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/session.py +10 -34
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/utils.py +32 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/anthropic.py +182 -38
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/tests/test_computer.py +39 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/base.py +82 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/pyautogui.py +31 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/xdo.py +43 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/native_types.py +4 -3
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_native_tool_e2e.py +26 -27
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_native_types.py +150 -6
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_version.py +1 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/version.py +1 -1
- {hud_python-0.5.18 → hud_python-0.5.20}/pyproject.toml +5 -4
- {hud_python-0.5.18 → hud_python-0.5.20}/.gitignore +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/LICENSE +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/README.md +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/examples/README.md +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/__main__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/gateway.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/grounded_openai.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/misc/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/misc/integration_test_agent.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/misc/response_agent.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/openai_chat.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/resolver.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/conftest.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_base_runtime.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_grounded_openai_agent.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_openai.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_operator.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_resolver.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/tests/test_run_eval.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/agents/types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/__main__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/analyze.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/clone.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/debug.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/deploy.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/dev.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/eval.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/dev.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/tasks.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/templates.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/flows/tests/test_dev.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/get.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/link.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/list_func.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/pull.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/push.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/remove.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/rft.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/rft_status.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_analyze.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_analyze_metadata.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_analyze_module.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_build_failure.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_cli_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_cli_main.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_cli_root.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_clone.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_convert.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_cursor.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_debug.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_debug_directory_mode.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_deploy.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_dev.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_eval.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_eval_bedrock.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_list_func.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_main_module.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_mcp_server.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_pull.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_push.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_push_happy.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_push_wrapper.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_registry.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/tests/test_utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/build_display.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/build_logs.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/celebrate.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/config.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/cursor.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/docker.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/env_check.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/environment.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/git.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/local_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/logging.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/mcp.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/metadata.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/package_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/registry.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/remote_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/server.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/source_hash.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tasks.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_config.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_docker.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_docker_hints.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_env_check.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_environment.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_git.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_interactive_module.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_local_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_logging_utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_metadata.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_package_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_registry_utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_remote_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_runner_modules.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_source_hash.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/tests/test_tasks.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/version_check.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/cli/utils/viewer.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/loader.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/tests/test_loader.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/tests/test_utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/datasets/utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connection.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/local.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/mcp_config.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/openai.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/connectors/remote.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/environment.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/adk.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/anthropic.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/langchain.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/llamaindex.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/integrations/openai.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/mock.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/router.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_connectors.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_environment.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_integrations.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_local_connectors.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_scenarios.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/tests/test_tools.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/utils/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/utils/formats.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/utils/schema.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/environment/utils/tool_wrappers.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/display.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/instrument.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/manager.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/parallel.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/task.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/test_context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/test_eval.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/test_manager.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/test_parallel.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/tests/test_task.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/eval/utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/native/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/native/comparator.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/native/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/native/tests/test_comparator.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/native/tests/test_native_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/patches/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/patches/warnings.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/py.typed +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/samples/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/samples/browser.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/helper/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/low_level.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/router.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/server.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_add_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_mcp_server_handlers.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_mcp_server_integration.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_mcp_server_more.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_run_wrapper.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_server_extra.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/server/tests/test_sigterm_runner.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/settings.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/hints.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/requests.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/tests/test_exceptions.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/tests/test_hints.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/shared/tests/test_requests.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/exporter.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/instrument.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/tests/test_eval_telemetry.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/tests/test_exporter.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/agent.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/apply_patch.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/gemini_edit.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/gemini_shell.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/shell.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_apply_patch.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_bash.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_bash_extended.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_edit.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_gemini_tools.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/coding/tests/test_shell.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/hud.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/openai.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/qwen.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/settings.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/computer/tests/test_computer_actions.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/tests/test_base_executor.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/executors/tests/test_pyautogui_executor.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/glob.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/grep.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/list.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/read.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/tests/test_glob.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/tests/test_grep.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/tests/test_list.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/filesystem/tests/test_read.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/config.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/grounded_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/grounder.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/grounding/tests/test_grounded_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/code_execution.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/google_search.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/url_context.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/web_fetch.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/hosted/web_search.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/jupyter.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/claude.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/session.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/tests/test_claude.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/tests/test_gemini.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/memory/tests/test_session.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/playwright.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/response.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/submit.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_agent_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_base.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_jupyter_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_playwright_tool.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_response.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_submit.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_tools.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_tools_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/tests/test_utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/tools/utils.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/types.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/env.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/hud_console.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/mcp.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/pretty_errors.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/strict_schema.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/telemetry.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/__init__.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_init.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_mcp.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_pretty_errors.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_telemetry.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tests/test_tool_shorthand.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/tool_shorthand.py +0 -0
- {hud_python-0.5.18 → hud_python-0.5.20}/hud/utils/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hud-python
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.20
|
|
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
|
|
@@ -51,7 +51,7 @@ Requires-Dist: toml>=0.10.2
|
|
|
51
51
|
Requires-Dist: typer>=0.9.0
|
|
52
52
|
Requires-Dist: watchfiles>=0.21.0
|
|
53
53
|
Provides-Extra: agent
|
|
54
|
-
Requires-Dist: anthropic>=0.
|
|
54
|
+
Requires-Dist: anthropic>=0.78.0; extra == 'agent'
|
|
55
55
|
Requires-Dist: datasets>=2.14.0; extra == 'agent'
|
|
56
56
|
Requires-Dist: google-genai; extra == 'agent'
|
|
57
57
|
Requires-Dist: langchain>=1.1.0; extra == 'agent'
|
|
@@ -60,7 +60,7 @@ Requires-Dist: openai-agents; extra == 'agent'
|
|
|
60
60
|
Requires-Dist: pillow>=11.1.0; extra == 'agent'
|
|
61
61
|
Requires-Dist: tornado>=6.5.2; extra == 'agent'
|
|
62
62
|
Provides-Extra: agents
|
|
63
|
-
Requires-Dist: anthropic>=0.
|
|
63
|
+
Requires-Dist: anthropic>=0.78.0; extra == 'agents'
|
|
64
64
|
Requires-Dist: datasets>=2.14.0; extra == 'agents'
|
|
65
65
|
Requires-Dist: google-genai; extra == 'agents'
|
|
66
66
|
Requires-Dist: langchain>=1.1.0; extra == 'agents'
|
|
@@ -69,9 +69,9 @@ Requires-Dist: openai-agents; extra == 'agents'
|
|
|
69
69
|
Requires-Dist: pillow>=11.1.0; extra == 'agents'
|
|
70
70
|
Requires-Dist: tornado>=6.5.2; extra == 'agents'
|
|
71
71
|
Provides-Extra: bedrock
|
|
72
|
-
Requires-Dist: anthropic[bedrock]>=0.
|
|
72
|
+
Requires-Dist: anthropic[bedrock]>=0.78.0; extra == 'bedrock'
|
|
73
73
|
Provides-Extra: dev
|
|
74
|
-
Requires-Dist: anthropic>=0.
|
|
74
|
+
Requires-Dist: anthropic>=0.78.0; extra == 'dev'
|
|
75
75
|
Requires-Dist: datasets>=2.14.0; extra == 'dev'
|
|
76
76
|
Requires-Dist: dotenv>=0.9.9; extra == 'dev'
|
|
77
77
|
Requires-Dist: google-adk; extra == 'dev'
|
|
@@ -92,7 +92,7 @@ Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
|
92
92
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
93
93
|
Requires-Dist: pytest-mock; extra == 'dev'
|
|
94
94
|
Requires-Dist: pytest>=8.1.1; extra == 'dev'
|
|
95
|
-
Requires-Dist: ruff
|
|
95
|
+
Requires-Dist: ruff<0.15.0,>=0.11.8; extra == 'dev'
|
|
96
96
|
Requires-Dist: tornado>=6.5.2; extra == 'dev'
|
|
97
97
|
Description-Content-Type: text/markdown
|
|
98
98
|
|
|
@@ -88,6 +88,9 @@ class MCPAgent(ABC):
|
|
|
88
88
|
Returns a NativeToolSpec that can be used to register the tool with
|
|
89
89
|
the provider's native API format.
|
|
90
90
|
|
|
91
|
+
When the spec data is a list (model-specific variants), specs are tried in order
|
|
92
|
+
and the first one whose supports_model() matches wins.
|
|
93
|
+
|
|
91
94
|
Falls back to legacy name-based detection for backwards compatibility with
|
|
92
95
|
old environments that don't emit native_tools metadata.
|
|
93
96
|
|
|
@@ -101,42 +104,28 @@ class MCPAgent(ABC):
|
|
|
101
104
|
generic function calling.
|
|
102
105
|
"""
|
|
103
106
|
spec: NativeToolSpec | None = None
|
|
107
|
+
spec_data = None
|
|
104
108
|
|
|
105
109
|
# First try metadata-based resolution
|
|
106
110
|
if tool.meta:
|
|
107
111
|
native_tools = tool.meta.get("native_tools", {})
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
# Convert supported_models list to tuple for frozen model
|
|
123
|
-
supported_models_raw = spec_dict.get("supported_models")
|
|
124
|
-
supported_models: tuple[str, ...] | None = None
|
|
125
|
-
if supported_models_raw:
|
|
126
|
-
supported_models = tuple(supported_models_raw)
|
|
127
|
-
|
|
128
|
-
spec = NativeToolSpec(
|
|
129
|
-
api_type=spec_dict.get("api_type"),
|
|
130
|
-
api_name=spec_dict.get("api_name"),
|
|
131
|
-
beta=spec_dict.get("beta"),
|
|
132
|
-
hosted=spec_dict.get("hosted", False),
|
|
133
|
-
role=spec_dict.get("role"),
|
|
134
|
-
supported_models=supported_models,
|
|
135
|
-
extra=extra,
|
|
136
|
-
)
|
|
112
|
+
spec_data = native_tools.get(self.agent_type().value)
|
|
113
|
+
|
|
114
|
+
if isinstance(spec_data, list):
|
|
115
|
+
# List of specs -- pick first model-matching spec
|
|
116
|
+
for item in spec_data:
|
|
117
|
+
if not isinstance(item, dict):
|
|
118
|
+
continue
|
|
119
|
+
candidate = _parse_spec_dict(item)
|
|
120
|
+
if candidate and candidate.supports_model(self.model):
|
|
121
|
+
spec = candidate
|
|
122
|
+
break
|
|
123
|
+
elif isinstance(spec_data, dict):
|
|
124
|
+
spec = _parse_spec_dict(spec_data)
|
|
137
125
|
|
|
138
126
|
# Fall back to legacy name-based detection for old environments
|
|
139
|
-
if
|
|
127
|
+
# Only if metadata didn't contain specs for this agent type at all
|
|
128
|
+
if spec is None and not spec_data:
|
|
140
129
|
spec = self._legacy_native_spec_fallback(tool)
|
|
141
130
|
|
|
142
131
|
# Check if current model supports this native spec
|
|
@@ -170,23 +159,33 @@ class MCPAgent(ABC):
|
|
|
170
159
|
The role is used for mutual exclusion - when an agent accepts a tool
|
|
171
160
|
natively, other tools with the same role are excluded.
|
|
172
161
|
|
|
162
|
+
Checks metadata first, then falls back to legacy name-based detection
|
|
163
|
+
so old environments without native_tools metadata still get proper
|
|
164
|
+
role-based exclusion.
|
|
165
|
+
|
|
173
166
|
Args:
|
|
174
167
|
tool: MCP Tool object to check
|
|
175
168
|
|
|
176
169
|
Returns:
|
|
177
170
|
The role string if any native spec defines one, None otherwise
|
|
178
171
|
"""
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
172
|
+
# Check metadata-based specs first
|
|
173
|
+
if tool.meta:
|
|
174
|
+
native_tools = tool.meta.get("native_tools", {})
|
|
175
|
+
if native_tools:
|
|
176
|
+
# Check all specs for a role (they should all have the same role)
|
|
177
|
+
for spec_data in native_tools.values():
|
|
178
|
+
if isinstance(spec_data, dict) and spec_data.get("role"):
|
|
179
|
+
return spec_data["role"]
|
|
180
|
+
if isinstance(spec_data, list):
|
|
181
|
+
for item in spec_data:
|
|
182
|
+
if isinstance(item, dict) and item.get("role"):
|
|
183
|
+
return item["role"]
|
|
184
|
+
|
|
185
|
+
# Fall back to legacy detection for old environments without metadata
|
|
186
|
+
legacy_spec = self._legacy_native_spec_fallback(tool)
|
|
187
|
+
if legacy_spec and legacy_spec.role:
|
|
188
|
+
return legacy_spec.role
|
|
190
189
|
|
|
191
190
|
return None
|
|
192
191
|
|
|
@@ -229,6 +228,10 @@ class MCPAgent(ABC):
|
|
|
229
228
|
else:
|
|
230
229
|
result.native.append((tool, spec))
|
|
231
230
|
|
|
231
|
+
# Collect api_names claimed by native tools to prevent name collisions
|
|
232
|
+
claimed_api_names = {s.api_name for _, s in result.native if s.api_name}
|
|
233
|
+
claimed_api_names |= {s.api_name for _, s in result.hosted if s.api_name}
|
|
234
|
+
|
|
232
235
|
# Second pass: process tools without native specs (generic function tools)
|
|
233
236
|
for tool in tools:
|
|
234
237
|
spec = self.resolve_native_spec(tool)
|
|
@@ -242,6 +245,13 @@ class MCPAgent(ABC):
|
|
|
242
245
|
result.skipped.append((tool, f"role '{tool_role}' already claimed by native tool"))
|
|
243
246
|
continue
|
|
244
247
|
|
|
248
|
+
# Check if this tool's name collides with a native tool's api_name
|
|
249
|
+
if tool.name in claimed_api_names:
|
|
250
|
+
result.skipped.append(
|
|
251
|
+
(tool, f"name '{tool.name}' collides with native tool api_name")
|
|
252
|
+
)
|
|
253
|
+
continue
|
|
254
|
+
|
|
245
255
|
result.generic.append(tool)
|
|
246
256
|
|
|
247
257
|
return result
|
|
@@ -723,6 +733,27 @@ class MCPAgent(ABC):
|
|
|
723
733
|
self.ctx = None
|
|
724
734
|
|
|
725
735
|
|
|
736
|
+
def _parse_spec_dict(spec_dict: dict[str, Any]) -> NativeToolSpec | None:
|
|
737
|
+
"""Parse a dict (from MCP meta) into a NativeToolSpec."""
|
|
738
|
+
if not spec_dict:
|
|
739
|
+
return None
|
|
740
|
+
known_fields = {"api_type", "api_name", "beta", "hosted", "role", "supported_models"}
|
|
741
|
+
extra = {k: v for k, v in spec_dict.items() if k not in known_fields}
|
|
742
|
+
supported_models_raw = spec_dict.get("supported_models")
|
|
743
|
+
supported_models: tuple[str, ...] | None = None
|
|
744
|
+
if supported_models_raw:
|
|
745
|
+
supported_models = tuple(supported_models_raw)
|
|
746
|
+
return NativeToolSpec(
|
|
747
|
+
api_type=spec_dict.get("api_type"),
|
|
748
|
+
api_name=spec_dict.get("api_name"),
|
|
749
|
+
beta=spec_dict.get("beta"),
|
|
750
|
+
hosted=spec_dict.get("hosted", False),
|
|
751
|
+
role=spec_dict.get("role"),
|
|
752
|
+
supported_models=supported_models,
|
|
753
|
+
extra=extra,
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
|
|
726
757
|
def _format_error_result(error_message: str) -> MCPToolResult:
|
|
727
758
|
return MCPToolResult(content=text_to_blocks(error_message), isError=True)
|
|
728
759
|
|
|
@@ -20,6 +20,7 @@ from anthropic.types.beta import (
|
|
|
20
20
|
BetaTextBlockParam,
|
|
21
21
|
BetaToolBash20250124Param,
|
|
22
22
|
BetaToolComputerUse20250124Param,
|
|
23
|
+
BetaToolComputerUse20251124Param,
|
|
23
24
|
BetaToolParam,
|
|
24
25
|
BetaToolResultBlockParam,
|
|
25
26
|
BetaToolTextEditor20250728Param,
|
|
@@ -71,41 +72,49 @@ class ClaudeAgent(MCPAgent):
|
|
|
71
72
|
|
|
72
73
|
Supports old environments that expose tools like 'anthropic_computer',
|
|
73
74
|
'bash', or 'str_replace_based_edit_tool' without native_tools metadata.
|
|
75
|
+
|
|
76
|
+
Each tuple is ordered by preference — first name that exists wins.
|
|
77
|
+
Only returns a spec if this tool IS that preferred match.
|
|
74
78
|
"""
|
|
75
|
-
|
|
79
|
+
import fnmatch
|
|
80
|
+
|
|
81
|
+
available = {t.name for t in (self._available_tools or [])} | {tool.name}
|
|
82
|
+
preferred = lambda names: next((n for n in names if n in available), None) == tool.name
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
if preferred(self._LEGACY_COMPUTER_NAMES):
|
|
85
|
+
logger.debug("Legacy fallback: detected %s as computer tool", tool.name)
|
|
86
|
+
model_lower = (self.model or "").lower()
|
|
87
|
+
if any(
|
|
88
|
+
fnmatch.fnmatch(model_lower, p) for p in ("claude-opus-4-5*", "claude-opus-4-6*")
|
|
89
|
+
):
|
|
81
90
|
return NativeToolSpec(
|
|
82
|
-
api_type="
|
|
91
|
+
api_type="computer_20251124",
|
|
83
92
|
api_name="computer",
|
|
84
|
-
beta="computer-use-2025-
|
|
93
|
+
beta="computer-use-2025-11-24",
|
|
85
94
|
role="computer",
|
|
86
95
|
)
|
|
96
|
+
return NativeToolSpec(
|
|
97
|
+
api_type="computer_20250124",
|
|
98
|
+
api_name="computer",
|
|
99
|
+
beta="computer-use-2025-01-24",
|
|
100
|
+
role="computer",
|
|
101
|
+
)
|
|
87
102
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
beta="computer-use-2025-01-24",
|
|
96
|
-
role="shell",
|
|
97
|
-
)
|
|
103
|
+
if preferred(self._LEGACY_BASH_NAMES):
|
|
104
|
+
logger.debug("Legacy fallback: detected %s as bash tool", tool.name)
|
|
105
|
+
return NativeToolSpec(
|
|
106
|
+
api_type="bash_20250124",
|
|
107
|
+
api_name="bash",
|
|
108
|
+
role="shell",
|
|
109
|
+
)
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
beta="computer-use-2025-01-24",
|
|
107
|
-
role="editor",
|
|
108
|
-
)
|
|
111
|
+
if preferred(self._LEGACY_EDITOR_NAMES):
|
|
112
|
+
logger.debug("Legacy fallback: detected %s as text_editor tool", tool.name)
|
|
113
|
+
return NativeToolSpec(
|
|
114
|
+
api_type="text_editor_20250728",
|
|
115
|
+
api_name="str_replace_based_edit_tool",
|
|
116
|
+
role="editor",
|
|
117
|
+
)
|
|
109
118
|
|
|
110
119
|
return None
|
|
111
120
|
|
|
@@ -142,7 +151,7 @@ class ClaudeAgent(MCPAgent):
|
|
|
142
151
|
self.has_computer_tool = False
|
|
143
152
|
self.tool_mapping: dict[str, str] = {}
|
|
144
153
|
self.claude_tools: list[BetaToolUnionParam] = []
|
|
145
|
-
self._required_betas: set[str] =
|
|
154
|
+
self._required_betas: set[str] = set()
|
|
146
155
|
|
|
147
156
|
def _on_tools_ready(self) -> None:
|
|
148
157
|
"""Build Claude-specific tool mappings after tools are discovered."""
|
|
@@ -191,7 +200,9 @@ class ClaudeAgent(MCPAgent):
|
|
|
191
200
|
messages_cached = self._add_prompt_caching(messages)
|
|
192
201
|
|
|
193
202
|
# betas to use - collected during tool conversion based on native specs
|
|
194
|
-
betas
|
|
203
|
+
# Only pass betas when non-empty; an empty list can produce an empty
|
|
204
|
+
# anthropic-beta header which the API rejects.
|
|
205
|
+
betas: list[str] | Omit = list(self._required_betas) if self._required_betas else Omit()
|
|
195
206
|
|
|
196
207
|
# Bedrock doesn't support .stream() - use create(stream=True) instead
|
|
197
208
|
if isinstance(self.anthropic_client, AsyncAnthropicBedrock):
|
|
@@ -331,7 +342,7 @@ class ClaudeAgent(MCPAgent):
|
|
|
331
342
|
self.has_computer_tool = False
|
|
332
343
|
self.tool_mapping: dict[str, str] = {}
|
|
333
344
|
self.claude_tools: list[BetaToolUnionParam] = []
|
|
334
|
-
self._required_betas: set[str] =
|
|
345
|
+
self._required_betas: set[str] = set()
|
|
335
346
|
|
|
336
347
|
categorized = self.categorize_tools()
|
|
337
348
|
|
|
@@ -371,6 +382,7 @@ class ClaudeAgent(MCPAgent):
|
|
|
371
382
|
name=tool.name,
|
|
372
383
|
description=tool.description,
|
|
373
384
|
input_schema=tool.inputSchema,
|
|
385
|
+
eager_input_streaming=True,
|
|
374
386
|
)
|
|
375
387
|
self.tool_mapping[tool.name] = tool.name
|
|
376
388
|
self.claude_tools.append(claude_tool)
|
|
@@ -387,7 +399,7 @@ class ClaudeAgent(MCPAgent):
|
|
|
387
399
|
Claude's native tools have fixed names that must be used exactly.
|
|
388
400
|
"""
|
|
389
401
|
match spec.api_type:
|
|
390
|
-
case "computer_20250124":
|
|
402
|
+
case "computer_20250124" | "computer_20251124":
|
|
391
403
|
return "computer"
|
|
392
404
|
case "bash_20250124":
|
|
393
405
|
return "bash"
|
|
@@ -407,8 +419,32 @@ class ClaudeAgent(MCPAgent):
|
|
|
407
419
|
Claude-specific tool parameter
|
|
408
420
|
"""
|
|
409
421
|
match spec.api_type:
|
|
422
|
+
case "computer_20251124":
|
|
423
|
+
display_width = spec.extra.get("display_width")
|
|
424
|
+
display_height = spec.extra.get("display_height")
|
|
425
|
+
|
|
426
|
+
if display_width is None or display_height is None:
|
|
427
|
+
import warnings
|
|
428
|
+
|
|
429
|
+
warnings.warn(
|
|
430
|
+
"Computer tool missing display dimensions in native_specs.extra. "
|
|
431
|
+
"Falling back to computer_settings. This fallback will be removed "
|
|
432
|
+
"in v0.6.0. Update your tool to pass display_width/display_height.",
|
|
433
|
+
DeprecationWarning,
|
|
434
|
+
stacklevel=2,
|
|
435
|
+
)
|
|
436
|
+
display_width = display_width or computer_settings.ANTHROPIC_COMPUTER_WIDTH
|
|
437
|
+
display_height = display_height or computer_settings.ANTHROPIC_COMPUTER_HEIGHT
|
|
438
|
+
|
|
439
|
+
return BetaToolComputerUse20251124Param(
|
|
440
|
+
type="computer_20251124",
|
|
441
|
+
name="computer",
|
|
442
|
+
display_number=1,
|
|
443
|
+
display_width_px=display_width,
|
|
444
|
+
display_height_px=display_height,
|
|
445
|
+
enable_zoom=True,
|
|
446
|
+
)
|
|
410
447
|
case "computer_20250124":
|
|
411
|
-
# Get display dimensions from spec.extra, fallback to settings
|
|
412
448
|
display_width = spec.extra.get("display_width")
|
|
413
449
|
display_height = spec.extra.get("display_height")
|
|
414
450
|
|
|
@@ -425,7 +461,6 @@ class ClaudeAgent(MCPAgent):
|
|
|
425
461
|
display_width = display_width or computer_settings.ANTHROPIC_COMPUTER_WIDTH
|
|
426
462
|
display_height = display_height or computer_settings.ANTHROPIC_COMPUTER_HEIGHT
|
|
427
463
|
|
|
428
|
-
# Claude expects name to be literal "computer"
|
|
429
464
|
return BetaToolComputerUse20250124Param(
|
|
430
465
|
type="computer_20250124",
|
|
431
466
|
name="computer",
|
|
@@ -47,20 +47,22 @@ class GeminiAgent(MCPAgent):
|
|
|
47
47
|
|
|
48
48
|
Supports old environments that expose tools like 'gemini_computer'
|
|
49
49
|
without native_tools metadata.
|
|
50
|
+
|
|
51
|
+
Each tuple is ordered by preference — first name that exists wins.
|
|
52
|
+
Only returns a spec if this tool IS that preferred match.
|
|
50
53
|
"""
|
|
51
54
|
from hud.tools.native_types import NativeToolSpec
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
available = {t.name for t in (self._available_tools or [])} | {tool.name}
|
|
57
|
+
preferred = lambda names: next((n for n in names if n in available), None) == tool.name
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
role="computer",
|
|
63
|
-
)
|
|
59
|
+
if preferred(self._LEGACY_COMPUTER_NAMES):
|
|
60
|
+
logger.debug("Legacy fallback: detected %s as computer tool", tool.name)
|
|
61
|
+
return NativeToolSpec(
|
|
62
|
+
api_type="computer_use",
|
|
63
|
+
api_name="gemini_computer",
|
|
64
|
+
role="computer",
|
|
65
|
+
)
|
|
64
66
|
|
|
65
67
|
return None
|
|
66
68
|
|
|
@@ -78,25 +78,27 @@ class GeminiCUAAgent(GeminiAgent):
|
|
|
78
78
|
return AgentType.GEMINI_CUA
|
|
79
79
|
|
|
80
80
|
# Legacy tool name patterns for backwards compatibility
|
|
81
|
-
_LEGACY_COMPUTER_NAMES = ("gemini_computer", "
|
|
81
|
+
_LEGACY_COMPUTER_NAMES = ("gemini_computer", "computer")
|
|
82
82
|
|
|
83
83
|
def _legacy_native_spec_fallback(self, tool: types.Tool) -> NativeToolSpec | None:
|
|
84
84
|
"""Detect Gemini CUA native tools by name for backwards compatibility.
|
|
85
85
|
|
|
86
86
|
Supports old environments that expose tools like 'gemini_computer'
|
|
87
87
|
without native_tools metadata.
|
|
88
|
+
|
|
89
|
+
Each tuple is ordered by preference — first name that exists wins.
|
|
90
|
+
Only returns a spec if this tool IS that preferred match.
|
|
88
91
|
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
92
|
+
available = {t.name for t in (self._available_tools or [])} | {tool.name}
|
|
93
|
+
preferred = lambda names: next((n for n in names if n in available), None) == tool.name
|
|
94
|
+
|
|
95
|
+
if preferred(self._LEGACY_COMPUTER_NAMES):
|
|
96
|
+
logger.debug("Legacy fallback: detected %s as computer_use tool", tool.name)
|
|
97
|
+
return NativeToolSpec(
|
|
98
|
+
api_type="computer_use",
|
|
99
|
+
api_name="gemini_computer",
|
|
100
|
+
role="computer",
|
|
101
|
+
)
|
|
100
102
|
|
|
101
103
|
return None
|
|
102
104
|
|
|
@@ -62,28 +62,28 @@ class OpenAIAgent(MCPAgent):
|
|
|
62
62
|
|
|
63
63
|
Supports old environments that expose tools like 'shell' or 'apply_patch'
|
|
64
64
|
without native_tools metadata.
|
|
65
|
+
|
|
66
|
+
Each tuple is ordered by preference — first name that exists wins.
|
|
67
|
+
Only returns a spec if this tool IS that preferred match.
|
|
65
68
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
69
|
+
available = {t.name for t in (self._available_tools or [])} | {tool.name}
|
|
70
|
+
preferred = lambda names: next((n for n in names if n in available), None) == tool.name
|
|
71
|
+
|
|
72
|
+
if preferred(self._LEGACY_SHELL_NAMES):
|
|
73
|
+
logger.debug("Legacy fallback: detected %s as shell tool", tool.name)
|
|
74
|
+
return NativeToolSpec(
|
|
75
|
+
api_type="shell",
|
|
76
|
+
api_name="shell",
|
|
77
|
+
role="shell",
|
|
78
|
+
)
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
role="editor",
|
|
86
|
-
)
|
|
80
|
+
if preferred(self._LEGACY_APPLY_PATCH_NAMES):
|
|
81
|
+
logger.debug("Legacy fallback: detected %s as apply_patch tool", tool.name)
|
|
82
|
+
return NativeToolSpec(
|
|
83
|
+
api_type="apply_patch",
|
|
84
|
+
api_name="apply_patch",
|
|
85
|
+
role="editor",
|
|
86
|
+
)
|
|
87
87
|
|
|
88
88
|
return None
|
|
89
89
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
5
6
|
from typing import TYPE_CHECKING, Any, ClassVar, Literal
|
|
6
7
|
|
|
7
8
|
import mcp.types as types
|
|
@@ -17,7 +18,7 @@ from openai.types.responses.response_input_param import (
|
|
|
17
18
|
from openai.types.shared_params.reasoning import Reasoning
|
|
18
19
|
|
|
19
20
|
from hud.tools.computer.settings import computer_settings
|
|
20
|
-
from hud.tools.native_types import NativeToolSpec
|
|
21
|
+
from hud.tools.native_types import NativeToolSpec
|
|
21
22
|
from hud.types import AgentType, BaseAgentConfig, MCPToolCall, MCPToolResult
|
|
22
23
|
from hud.utils.types import with_signature
|
|
23
24
|
|
|
@@ -25,6 +26,8 @@ from .base import MCPAgent
|
|
|
25
26
|
from .openai import OpenAIAgent
|
|
26
27
|
from .types import OperatorConfig, OperatorCreateParams
|
|
27
28
|
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
28
31
|
if TYPE_CHECKING:
|
|
29
32
|
from openai.types.responses.response_computer_tool_call import PendingSafetyCheck
|
|
30
33
|
|
|
@@ -201,3 +204,24 @@ class OperatorAgent(OpenAIAgent):
|
|
|
201
204
|
if isinstance(content, types.TextContent) and result.isError:
|
|
202
205
|
self.console.error_log(f"Computer tool error: {content.text}")
|
|
203
206
|
return None
|
|
207
|
+
|
|
208
|
+
_LEGACY_COMPUTER_NAMES = ("openai_computer",)
|
|
209
|
+
|
|
210
|
+
def _legacy_native_spec_fallback(self, tool: types.Tool) -> NativeToolSpec | None:
|
|
211
|
+
"""Detect Operator native tools by name for backwards compatibility.
|
|
212
|
+
|
|
213
|
+
Each tuple is ordered by preference — first name that exists wins.
|
|
214
|
+
Only returns a spec if this tool IS that preferred match.
|
|
215
|
+
"""
|
|
216
|
+
available = {t.name for t in (self._available_tools or [])} | {tool.name}
|
|
217
|
+
preferred = lambda names: next((n for n in names if n in available), None) == tool.name
|
|
218
|
+
|
|
219
|
+
if preferred(self._LEGACY_COMPUTER_NAMES):
|
|
220
|
+
logger.debug("Legacy fallback: detected %s as computer tool", tool.name)
|
|
221
|
+
return NativeToolSpec(
|
|
222
|
+
api_type="computer_use_preview",
|
|
223
|
+
api_name="computer",
|
|
224
|
+
role="computer",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
return super()._legacy_native_spec_fallback(tool)
|