hud-python 0.6.7__tar.gz → 0.6.8.dev0__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.6.7 → hud_python-0.6.8.dev0}/PKG-INFO +27 -24
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/README.md +26 -23
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai_compatible/agent.py +7 -3
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai_compatible/tools/__init__.py +4 -2
- hud_python-0.6.8.dev0/hud/agents/openai_compatible/tools/filesystem.py +332 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_provider_native_tools.py +135 -6
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_rollout.py +90 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/version.py +1 -1
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/pyproject.toml +1 -1
- hud_python-0.6.7/hud/agents/openai_compatible/tools/filesystem.py +0 -138
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/.gitignore +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/LICENSE +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/a2a-chat/README.md +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/a2a-chat/pyproject.toml +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/codex-coding/README.md +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/codex-coding/pyproject.toml +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/connect4-selfplay/README.md +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/fireworks-rl-training/README.md +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/fireworks-rl-training/pyproject.toml +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/rl-training/README.md +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/cookbooks/rl-training/pyproject.toml +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/__main__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/_legacy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/browser_use/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/browser_use/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/sdk/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/sdk/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/sdk/computer_mcp.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/coding.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/hosted.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/mcp_proxy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/settings.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/claude/tools/tests/test_computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/settings.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/coding.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/filesystem.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/hosted.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/mcp_proxy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/gemini/tools/tests/test_computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/misc/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/misc/response_automation.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/apply_patch.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/coding.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/hosted.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/mcp_proxy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/strict_schema.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/tests/test_computer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai/tools/tests/test_strict_schema.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai_compatible/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai_compatible/tools/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/openai_compatible/tools/mcp_proxy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/_types.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/adapter.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/batching.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/model.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/record.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/robot/video.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_apply_patch.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_claude_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_claude_sdk_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_gemini_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_openai_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_openai_compatible_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_tool_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tests/test_trace.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tool_agent.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/hosted.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/mcp.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/rfb.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/tools/ssh.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/agents/types.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/cdp.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/filetracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/mcp.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/rfb.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/robot.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/capabilities/ssh.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/__main__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/cancel.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/client.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/deploy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/eval.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/init.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/jobs.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/login.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/models.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/presets.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/serve.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/sync.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/task.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/templates.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_cli_init.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_cli_main.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_deploy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_eval_bedrock.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_eval_config.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_init.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_main_module.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/tests/test_sync_export.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/trace.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/api.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/build_display.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/build_logs.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/config.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/context.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/display.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/jobs.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/registry.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/source.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tasks.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_build_display.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_config.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_context.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_registry.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_source.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_tasks.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/tests/test_version_check.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/cli/utils/version_check.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/clients/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/clients/client.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/clients/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/clients/tests/test_connect.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/conftest.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/env.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/file_tracker.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/file_tracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/legacy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/robot/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/robot/bridge.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/robot/endpoint.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/robot/sim_runner.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/server.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/conftest.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_capability_backing.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_file_tracker.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_file_tracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_legacy.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_loader.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_manifest.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_server.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/tests/test_tunnel.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/utils.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/environment/workspace.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/chat.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/file_tracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/job.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/run.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/runtime.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/sync.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/task.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/taskset.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_chat.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_docker_provider.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_file_tracking_observer.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_hosted.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_job.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_sync.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/eval/tests/test_task.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/bash.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/combine.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/judge.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/results.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/graders/text.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/patches/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/patches/mcp_patches.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/patches/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/patches/tests/test_warnings.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/patches/warnings.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/py.typed +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/server.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/settings.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/context.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/exporter.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/filetracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/instrument.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/span.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/tests/test_exporter.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/tests/test_filetracking.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/train/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/train/base.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/train/client.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/train/types.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/types.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/exceptions.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/gateway.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/hints.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/hud_console.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/modules.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/platform.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/requests.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/serialization.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/__init__.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_exceptions.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_hints.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_hud_console.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_platform.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_requests.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/tests/test_serialization.py +0 -0
- {hud_python-0.6.7 → hud_python-0.6.8.dev0}/hud/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hud-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.8.dev0
|
|
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
|
|
@@ -87,7 +87,7 @@ Description-Content-Type: text/markdown
|
|
|
87
87
|
|
|
88
88
|
HUD is a platform for building RL environments for AI agents, across coding, browser, computer-use, and robotics. Define an environment, write tasks, and run them as evals and training across any model, at any scale.
|
|
89
89
|
|
|
90
|
-
To learn more, see the [documentation](https://docs.hud.ai) and [
|
|
90
|
+
To learn more, see the [documentation](https://docs.hud.ai) and [environment reference](https://docs.hud.ai/v6/core/environment).
|
|
91
91
|
|
|
92
92
|
[](https://pypi.org/project/hud-python/)
|
|
93
93
|
[](LICENSE)
|
|
@@ -120,7 +120,7 @@ Then scaffold your first environment:
|
|
|
120
120
|
hud init my-env
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
-

|
|
124
124
|
|
|
125
125
|
## The protocol
|
|
126
126
|
|
|
@@ -159,14 +159,14 @@ hud eval my-taskset --remote
|
|
|
159
159
|
For local iteration, the same protocol works against a container on your laptop:
|
|
160
160
|
|
|
161
161
|
```bash
|
|
162
|
-
|
|
163
|
-
docker run -d --name run1 my-env
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
docker build -f Dockerfile.hud -t my-env .
|
|
163
|
+
docker run -d --name run1 -p 8765:8765 my-env
|
|
164
|
+
hud task start fix_bug --url tcp://127.0.0.1:8765
|
|
165
|
+
hud task grade fix_bug --url tcp://127.0.0.1:8765 --answer "..."
|
|
166
166
|
docker rm -f run1
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
-
→ [
|
|
169
|
+
→ [Run & deploy](https://docs.hud.ai/v6/core/runtime)
|
|
170
170
|
|
|
171
171
|
## Environments & templates
|
|
172
172
|
|
|
@@ -193,7 +193,7 @@ hud eval tasks.py claude --group 3
|
|
|
193
193
|
|
|
194
194
|
Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `HUD_API_KEY` set, every rollout is recorded on [hud.ai](https://hud.ai). Tasks that need a shell, browser, GUI, or robot declare **capabilities** (below); everything else — variants, grading, batching — stays identical.
|
|
195
195
|
|
|
196
|
-
→ [Quickstart](https://docs.hud.ai/quickstart) · [Tasks & tasksets](https://docs.hud.ai/
|
|
196
|
+
→ [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/core/tasks)
|
|
197
197
|
|
|
198
198
|
## Capabilities & harnesses
|
|
199
199
|
|
|
@@ -211,39 +211,42 @@ A **capability** is a connection the environment exposes; a **harness** attaches
|
|
|
211
211
|
|
|
212
212
|
**Bring your own:** a harness attaches to a capability and defines a tool spec — wrap `browser-use` on `cdp`, a VLA policy on `robot`, or your own agent on `ssh` / `mcp`. No protocol work required.
|
|
213
213
|
|
|
214
|
-
→ [Capabilities](https://docs.hud.ai/
|
|
214
|
+
→ [Capabilities](https://docs.hud.ai/v6/core/capabilities) · [Models](https://docs.hud.ai/v6/core/agents) · [Robots](https://docs.hud.ai/v6/advanced/robots)
|
|
215
215
|
|
|
216
216
|
## Deploy on the platform
|
|
217
217
|
|
|
218
218
|
From the [platform UI](https://hud.ai) you can run batches, compare models on the same taskset, and inspect every trace.
|
|
219
219
|
|
|
220
|
-
→ [
|
|
220
|
+
→ [Run & deploy](https://docs.hud.ai/v6/core/runtime)
|
|
221
221
|
|
|
222
222
|
## Train on rewards
|
|
223
223
|
|
|
224
|
-
Every rollout returns a `Run` carrying a `trace_id` and a `reward`, so the tasks you evaluate are already training data. Run a **group** per task and
|
|
224
|
+
Every rollout returns a `Run` carrying a `trace_id` and a `reward`, so the tasks you evaluate are already training data. Run a **group** per task and pass the graded runs to `TrainingClient.step()`:
|
|
225
225
|
|
|
226
226
|
```python
|
|
227
|
+
from hud import TrainingClient
|
|
227
228
|
from hud.agents import create_agent
|
|
228
|
-
from hud.eval import
|
|
229
|
+
from hud.eval import Job
|
|
229
230
|
|
|
230
|
-
agent = create_agent("
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
agent = create_agent("arith-rl", completion_kwargs={"extra_body": {"return_token_ids": True}})
|
|
232
|
+
trainer = TrainingClient("arith-rl")
|
|
233
|
+
taskset, runtime = ... # your Taskset and where rollouts run
|
|
234
|
+
|
|
235
|
+
session = await Job.start("arith-rl", group=8)
|
|
236
|
+
start = len(session.runs)
|
|
237
|
+
await taskset.run(agent, runtime=runtime, group=8, job=session)
|
|
238
|
+
await trainer.step(session.runs[start:], learning_rate=1e-5, group_size=8)
|
|
235
239
|
```
|
|
236
240
|
|
|
237
241
|
HUD is the environment-and-reward source for your own GRPO/PPO loop — the same environment trains any model, text or multimodal, unchanged.
|
|
238
242
|
|
|
239
|
-
→ [Training](https://docs.hud.ai/
|
|
243
|
+
→ [Training](https://docs.hud.ai/v6/core/training) · [Designing tasks for signal](https://docs.hud.ai/v6/core/advice)
|
|
240
244
|
|
|
241
245
|
## Links
|
|
242
246
|
|
|
243
247
|
- [Documentation](https://docs.hud.ai)
|
|
244
|
-
- [Quickstart](https://docs.hud.ai/quickstart)
|
|
245
|
-
- [CLI reference](https://docs.hud.ai/
|
|
246
|
-
- [Leaderboards](https://hud.ai/leaderboards)
|
|
248
|
+
- [Quickstart](https://docs.hud.ai/v6/start/quickstart)
|
|
249
|
+
- [CLI reference](https://docs.hud.ai/v6/core/cli)
|
|
247
250
|
- [Environment templates](https://hud.ai/environments)
|
|
248
251
|
- [Supported models](https://hud.ai/models)
|
|
249
252
|
- [Discord](https://discord.gg/wkjtmHYYjm)
|
|
@@ -268,8 +271,8 @@ Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabil
|
|
|
268
271
|
|
|
269
272
|
```bibtex
|
|
270
273
|
@software{hud2025agentevalplatform,
|
|
271
|
-
author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep and Nguyen Nhat Minh},
|
|
272
|
-
title = {HUD: An Evaluation and RL
|
|
274
|
+
author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep Chawla and Nguyen Nhat Minh},
|
|
275
|
+
title = {HUD: An Evaluation and RL Environments Platform for Agents},
|
|
273
276
|
date = {2025-04},
|
|
274
277
|
url = {https://github.com/hud-evals/hud-python},
|
|
275
278
|
langid = {en}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
HUD is a platform for building RL environments for AI agents, across coding, browser, computer-use, and robotics. Define an environment, write tasks, and run them as evals and training across any model, at any scale.
|
|
10
10
|
|
|
11
|
-
To learn more, see the [documentation](https://docs.hud.ai) and [
|
|
11
|
+
To learn more, see the [documentation](https://docs.hud.ai) and [environment reference](https://docs.hud.ai/v6/core/environment).
|
|
12
12
|
|
|
13
13
|
[](https://pypi.org/project/hud-python/)
|
|
14
14
|
[](LICENSE)
|
|
@@ -41,7 +41,7 @@ Then scaffold your first environment:
|
|
|
41
41
|
hud init my-env
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-

|
|
45
45
|
|
|
46
46
|
## The protocol
|
|
47
47
|
|
|
@@ -80,14 +80,14 @@ hud eval my-taskset --remote
|
|
|
80
80
|
For local iteration, the same protocol works against a container on your laptop:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
|
|
84
|
-
docker run -d --name run1 my-env
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
docker build -f Dockerfile.hud -t my-env .
|
|
84
|
+
docker run -d --name run1 -p 8765:8765 my-env
|
|
85
|
+
hud task start fix_bug --url tcp://127.0.0.1:8765
|
|
86
|
+
hud task grade fix_bug --url tcp://127.0.0.1:8765 --answer "..."
|
|
87
87
|
docker rm -f run1
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
→ [
|
|
90
|
+
→ [Run & deploy](https://docs.hud.ai/v6/core/runtime)
|
|
91
91
|
|
|
92
92
|
## Environments & templates
|
|
93
93
|
|
|
@@ -114,7 +114,7 @@ hud eval tasks.py claude --group 3
|
|
|
114
114
|
|
|
115
115
|
Each graded evaluation is a **trace** (the SDK's live handle is a `Run`). With `HUD_API_KEY` set, every rollout is recorded on [hud.ai](https://hud.ai). Tasks that need a shell, browser, GUI, or robot declare **capabilities** (below); everything else — variants, grading, batching — stays identical.
|
|
116
116
|
|
|
117
|
-
→ [Quickstart](https://docs.hud.ai/quickstart) · [Tasks & tasksets](https://docs.hud.ai/
|
|
117
|
+
→ [Quickstart](https://docs.hud.ai/v6/start/quickstart) · [Tasks & tasksets](https://docs.hud.ai/v6/core/tasks)
|
|
118
118
|
|
|
119
119
|
## Capabilities & harnesses
|
|
120
120
|
|
|
@@ -132,39 +132,42 @@ A **capability** is a connection the environment exposes; a **harness** attaches
|
|
|
132
132
|
|
|
133
133
|
**Bring your own:** a harness attaches to a capability and defines a tool spec — wrap `browser-use` on `cdp`, a VLA policy on `robot`, or your own agent on `ssh` / `mcp`. No protocol work required.
|
|
134
134
|
|
|
135
|
-
→ [Capabilities](https://docs.hud.ai/
|
|
135
|
+
→ [Capabilities](https://docs.hud.ai/v6/core/capabilities) · [Models](https://docs.hud.ai/v6/core/agents) · [Robots](https://docs.hud.ai/v6/advanced/robots)
|
|
136
136
|
|
|
137
137
|
## Deploy on the platform
|
|
138
138
|
|
|
139
139
|
From the [platform UI](https://hud.ai) you can run batches, compare models on the same taskset, and inspect every trace.
|
|
140
140
|
|
|
141
|
-
→ [
|
|
141
|
+
→ [Run & deploy](https://docs.hud.ai/v6/core/runtime)
|
|
142
142
|
|
|
143
143
|
## Train on rewards
|
|
144
144
|
|
|
145
|
-
Every rollout returns a `Run` carrying a `trace_id` and a `reward`, so the tasks you evaluate are already training data. Run a **group** per task and
|
|
145
|
+
Every rollout returns a `Run` carrying a `trace_id` and a `reward`, so the tasks you evaluate are already training data. Run a **group** per task and pass the graded runs to `TrainingClient.step()`:
|
|
146
146
|
|
|
147
147
|
```python
|
|
148
|
+
from hud import TrainingClient
|
|
148
149
|
from hud.agents import create_agent
|
|
149
|
-
from hud.eval import
|
|
150
|
+
from hud.eval import Job
|
|
150
151
|
|
|
151
|
-
agent = create_agent("
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
agent = create_agent("arith-rl", completion_kwargs={"extra_body": {"return_token_ids": True}})
|
|
153
|
+
trainer = TrainingClient("arith-rl")
|
|
154
|
+
taskset, runtime = ... # your Taskset and where rollouts run
|
|
155
|
+
|
|
156
|
+
session = await Job.start("arith-rl", group=8)
|
|
157
|
+
start = len(session.runs)
|
|
158
|
+
await taskset.run(agent, runtime=runtime, group=8, job=session)
|
|
159
|
+
await trainer.step(session.runs[start:], learning_rate=1e-5, group_size=8)
|
|
156
160
|
```
|
|
157
161
|
|
|
158
162
|
HUD is the environment-and-reward source for your own GRPO/PPO loop — the same environment trains any model, text or multimodal, unchanged.
|
|
159
163
|
|
|
160
|
-
→ [Training](https://docs.hud.ai/
|
|
164
|
+
→ [Training](https://docs.hud.ai/v6/core/training) · [Designing tasks for signal](https://docs.hud.ai/v6/core/advice)
|
|
161
165
|
|
|
162
166
|
## Links
|
|
163
167
|
|
|
164
168
|
- [Documentation](https://docs.hud.ai)
|
|
165
|
-
- [Quickstart](https://docs.hud.ai/quickstart)
|
|
166
|
-
- [CLI reference](https://docs.hud.ai/
|
|
167
|
-
- [Leaderboards](https://hud.ai/leaderboards)
|
|
169
|
+
- [Quickstart](https://docs.hud.ai/v6/start/quickstart)
|
|
170
|
+
- [CLI reference](https://docs.hud.ai/v6/core/cli)
|
|
168
171
|
- [Environment templates](https://hud.ai/environments)
|
|
169
172
|
- [Supported models](https://hud.ai/models)
|
|
170
173
|
- [Discord](https://discord.gg/wkjtmHYYjm)
|
|
@@ -189,8 +192,8 @@ Key areas: [Agents](hud/agents/) · [Environments](hud/environment/) · [Capabil
|
|
|
189
192
|
|
|
190
193
|
```bibtex
|
|
191
194
|
@software{hud2025agentevalplatform,
|
|
192
|
-
author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep and Nguyen Nhat Minh},
|
|
193
|
-
title = {HUD: An Evaluation and RL
|
|
195
|
+
author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep Chawla and Nguyen Nhat Minh},
|
|
196
|
+
title = {HUD: An Evaluation and RL Environments Platform for Agents},
|
|
194
197
|
date = {2025-04},
|
|
195
198
|
url = {https://github.com/hud-evals/hud-python},
|
|
196
199
|
langid = {en}
|
|
@@ -17,11 +17,13 @@ from hud.types import MCPToolCall, MCPToolResult
|
|
|
17
17
|
from hud.utils import gateway
|
|
18
18
|
|
|
19
19
|
from .tools import (
|
|
20
|
+
BashTool,
|
|
21
|
+
EditTool,
|
|
20
22
|
GlobTool,
|
|
21
23
|
GrepTool,
|
|
22
|
-
ListTool,
|
|
23
24
|
OpenAICompatibleMCPProxyTool,
|
|
24
25
|
ReadTool,
|
|
26
|
+
WriteTool,
|
|
25
27
|
)
|
|
26
28
|
from .tools.base import format_chat_result
|
|
27
29
|
|
|
@@ -41,10 +43,12 @@ class OpenAIChatAgent(ToolAgent[ChatCompletionMessageParam, OpenAIChatConfig]):
|
|
|
41
43
|
"""OpenAI-compatible agent using the chat.completions protocol."""
|
|
42
44
|
|
|
43
45
|
tool_catalog = (
|
|
46
|
+
BashTool,
|
|
44
47
|
ReadTool,
|
|
45
|
-
GrepTool,
|
|
46
48
|
GlobTool,
|
|
47
|
-
|
|
49
|
+
GrepTool,
|
|
50
|
+
EditTool,
|
|
51
|
+
WriteTool,
|
|
48
52
|
OpenAICompatibleMCPProxyTool,
|
|
49
53
|
)
|
|
50
54
|
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from .filesystem import GlobTool, GrepTool,
|
|
5
|
+
from .filesystem import BashTool, EditTool, GlobTool, GrepTool, ReadTool, WriteTool
|
|
6
6
|
from .mcp_proxy import OpenAICompatibleMCPProxyTool
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
9
|
+
"BashTool",
|
|
10
|
+
"EditTool",
|
|
9
11
|
"GlobTool",
|
|
10
12
|
"GrepTool",
|
|
11
|
-
"ListTool",
|
|
12
13
|
"OpenAICompatibleMCPProxyTool",
|
|
13
14
|
"ReadTool",
|
|
15
|
+
"WriteTool",
|
|
14
16
|
]
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"""OpenAI-compatible OpenCode-style workspace tools backed by SSHClient."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
import posixpath
|
|
7
|
+
import shlex
|
|
8
|
+
from typing import Any, ClassVar
|
|
9
|
+
|
|
10
|
+
import mcp.types as mcp_types
|
|
11
|
+
|
|
12
|
+
from hud.agents.tools import SSHTool
|
|
13
|
+
from hud.agents.tools.base import AgentToolSpec, result_text, tool_err
|
|
14
|
+
from hud.types import MCPToolResult
|
|
15
|
+
|
|
16
|
+
DEFAULT_READ_LIMIT = 2000
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _FilesystemTool(SSHTool):
|
|
20
|
+
description: ClassVar[str]
|
|
21
|
+
parameters: ClassVar[dict[str, Any]]
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def default_spec(cls, model: str) -> AgentToolSpec:
|
|
25
|
+
del model
|
|
26
|
+
return AgentToolSpec(api_type="function", api_name=cls.name)
|
|
27
|
+
|
|
28
|
+
def to_params(self) -> dict[str, Any]:
|
|
29
|
+
return {
|
|
30
|
+
"type": "function",
|
|
31
|
+
"function": {
|
|
32
|
+
"name": self.name,
|
|
33
|
+
"description": self.description,
|
|
34
|
+
"parameters": self.parameters,
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ReadTool(_FilesystemTool):
|
|
40
|
+
name = "read"
|
|
41
|
+
description = (
|
|
42
|
+
"Reads a file or directory from the workspace. Use offset and limit for pagination."
|
|
43
|
+
)
|
|
44
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"filePath": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "The absolute path to the file or directory to read.",
|
|
50
|
+
},
|
|
51
|
+
"offset": {
|
|
52
|
+
"type": "integer",
|
|
53
|
+
"description": "The line number to start reading from (1-indexed).",
|
|
54
|
+
"minimum": 0,
|
|
55
|
+
},
|
|
56
|
+
"limit": {
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"description": "The maximum number of lines to read (defaults to 2000).",
|
|
59
|
+
"minimum": 1,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
"required": ["filePath"],
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
66
|
+
path = arguments.get("filePath")
|
|
67
|
+
if not isinstance(path, str) or not path:
|
|
68
|
+
raise ValueError("filePath is required")
|
|
69
|
+
offset = _read_offset(arguments.get("offset"))
|
|
70
|
+
limit = _positive_int(arguments.get("limit"), default=DEFAULT_READ_LIMIT, name="limit")
|
|
71
|
+
if not (await self.bash(f"test -d {shlex.quote(path)}")).isError:
|
|
72
|
+
return await self._read_directory(path, offset=offset, limit=limit)
|
|
73
|
+
result = await self.file_read(path)
|
|
74
|
+
if result.isError:
|
|
75
|
+
return result
|
|
76
|
+
text = result_text(result)
|
|
77
|
+
lines = text.splitlines()
|
|
78
|
+
start = offset - 1
|
|
79
|
+
if start > len(lines) and not (len(lines) == 0 and offset == 1):
|
|
80
|
+
return tool_err(f"Offset {offset} is out of range for this file ({len(lines)} lines)")
|
|
81
|
+
sliced = lines[start : start + limit]
|
|
82
|
+
last = offset + len(sliced) - 1
|
|
83
|
+
more = last < len(lines)
|
|
84
|
+
body = [
|
|
85
|
+
f"<path>{path}</path>",
|
|
86
|
+
"<type>file</type>",
|
|
87
|
+
"<content>",
|
|
88
|
+
*[f"{i + offset}: {line}" for i, line in enumerate(sliced)],
|
|
89
|
+
]
|
|
90
|
+
if more:
|
|
91
|
+
body.append(
|
|
92
|
+
f"\n(Showing lines {offset}-{last} of {len(lines)}. "
|
|
93
|
+
f"Use offset={last + 1} to continue.)"
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
body.append(f"\n(End of file - total {len(lines)} lines)")
|
|
97
|
+
body.append("</content>")
|
|
98
|
+
return MCPToolResult(content=[mcp_types.TextContent(type="text", text="\n".join(body))])
|
|
99
|
+
|
|
100
|
+
async def _read_directory(self, path: str, *, offset: int, limit: int) -> MCPToolResult:
|
|
101
|
+
result = await self.file_list(path)
|
|
102
|
+
if result.isError:
|
|
103
|
+
return result
|
|
104
|
+
entries = result_text(result).splitlines()
|
|
105
|
+
if entries == ["(empty)"]:
|
|
106
|
+
entries = []
|
|
107
|
+
start = offset - 1
|
|
108
|
+
sliced = entries[start : start + limit]
|
|
109
|
+
truncated = start + len(sliced) < len(entries)
|
|
110
|
+
body = [
|
|
111
|
+
f"<path>{path}</path>",
|
|
112
|
+
"<type>directory</type>",
|
|
113
|
+
"<entries>",
|
|
114
|
+
*sliced,
|
|
115
|
+
]
|
|
116
|
+
if truncated:
|
|
117
|
+
body.append(
|
|
118
|
+
f"\n(Showing {len(sliced)} of {len(entries)} entries. "
|
|
119
|
+
f"Use offset={offset + len(sliced)} to continue.)"
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
body.append(f"\n({len(entries)} entries)")
|
|
123
|
+
body.append("</entries>")
|
|
124
|
+
return MCPToolResult(content=[mcp_types.TextContent(type="text", text="\n".join(body))])
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class BashTool(_FilesystemTool):
|
|
128
|
+
name = "bash"
|
|
129
|
+
description = (
|
|
130
|
+
"Executes a shell command in the workspace. Prefer read, grep, glob, edit, "
|
|
131
|
+
"and write for filesystem operations."
|
|
132
|
+
)
|
|
133
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"properties": {
|
|
136
|
+
"command": {"type": "string", "description": "The command to execute."},
|
|
137
|
+
"timeout": {
|
|
138
|
+
"type": "integer",
|
|
139
|
+
"description": "Optional timeout in milliseconds.",
|
|
140
|
+
"minimum": 1,
|
|
141
|
+
},
|
|
142
|
+
"workdir": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"description": "The working directory to run the command in.",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
"required": ["command"],
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
151
|
+
command = arguments.get("command")
|
|
152
|
+
if not isinstance(command, str) or not command:
|
|
153
|
+
raise ValueError("command is required")
|
|
154
|
+
timeout = arguments.get("timeout")
|
|
155
|
+
if timeout is not None:
|
|
156
|
+
if not isinstance(timeout, int) or timeout < 1:
|
|
157
|
+
raise ValueError("timeout must be a positive integer")
|
|
158
|
+
seconds = max(1, math.ceil(timeout / 1000))
|
|
159
|
+
command = f"timeout {seconds}s bash -lc {shlex.quote(command)}"
|
|
160
|
+
workdir = arguments.get("workdir")
|
|
161
|
+
if isinstance(workdir, str) and workdir:
|
|
162
|
+
command = f"cd {shlex.quote(workdir)} && {command}"
|
|
163
|
+
return await self.bash(command)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class EditTool(_FilesystemTool):
|
|
167
|
+
name = "edit"
|
|
168
|
+
description = (
|
|
169
|
+
"Replaces text within a file. Use oldString as exact literal context. "
|
|
170
|
+
"Set replaceAll to true to replace every occurrence."
|
|
171
|
+
)
|
|
172
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"properties": {
|
|
175
|
+
"filePath": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"description": "The absolute path to the file to modify.",
|
|
178
|
+
},
|
|
179
|
+
"oldString": {"type": "string", "description": "The text to replace."},
|
|
180
|
+
"newString": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"description": "The text to replace it with (must be different from oldString).",
|
|
183
|
+
},
|
|
184
|
+
"replaceAll": {
|
|
185
|
+
"type": "boolean",
|
|
186
|
+
"description": "Replace all occurrences of oldString (default false).",
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
"required": ["filePath", "oldString", "newString"],
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
193
|
+
path = arguments.get("filePath")
|
|
194
|
+
if not isinstance(path, str) or not path:
|
|
195
|
+
raise ValueError("filePath is required")
|
|
196
|
+
old = arguments.get("oldString")
|
|
197
|
+
new = arguments.get("newString")
|
|
198
|
+
if not isinstance(old, str):
|
|
199
|
+
raise ValueError("oldString is required")
|
|
200
|
+
if not isinstance(new, str):
|
|
201
|
+
raise ValueError("newString is required")
|
|
202
|
+
if old == new:
|
|
203
|
+
return tool_err("No changes to apply: oldString and newString are identical.")
|
|
204
|
+
if old == "":
|
|
205
|
+
exists = not (await self.bash(f"test -e {shlex.quote(path)}")).isError
|
|
206
|
+
if exists:
|
|
207
|
+
return tool_err(
|
|
208
|
+
"oldString cannot be empty when editing an existing file. "
|
|
209
|
+
"Provide exact text to replace, or use write for full-file replacement."
|
|
210
|
+
)
|
|
211
|
+
mkdir = await self._ensure_parent(path)
|
|
212
|
+
if mkdir.isError:
|
|
213
|
+
return mkdir
|
|
214
|
+
return await self.file_write(path, new)
|
|
215
|
+
|
|
216
|
+
existing = await self.file_read(path)
|
|
217
|
+
if existing.isError:
|
|
218
|
+
return existing
|
|
219
|
+
text = result_text(existing)
|
|
220
|
+
count = text.count(old)
|
|
221
|
+
if count == 0:
|
|
222
|
+
return tool_err(f"oldString not found in {path}")
|
|
223
|
+
replace_all = arguments.get("replaceAll") is True
|
|
224
|
+
if count > 1 and not replace_all:
|
|
225
|
+
return tool_err(f"oldString matches {count} times in {path}; set replaceAll to true")
|
|
226
|
+
next_text = text.replace(old, new) if replace_all else text.replace(old, new, 1)
|
|
227
|
+
return await self.file_write(path, next_text)
|
|
228
|
+
|
|
229
|
+
async def _ensure_parent(self, path: str) -> MCPToolResult:
|
|
230
|
+
parent = posixpath.dirname(path)
|
|
231
|
+
if not parent or parent in {".", "/"}:
|
|
232
|
+
return MCPToolResult(content=[])
|
|
233
|
+
return await self.bash(f"mkdir -p {shlex.quote(parent)}")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class WriteTool(_FilesystemTool):
|
|
237
|
+
name = "write"
|
|
238
|
+
description = "Creates or overwrites a file with the provided content."
|
|
239
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
240
|
+
"type": "object",
|
|
241
|
+
"properties": {
|
|
242
|
+
"content": {"type": "string", "description": "The content to write to the file."},
|
|
243
|
+
"filePath": {
|
|
244
|
+
"type": "string",
|
|
245
|
+
"description": "The absolute path to the file to write.",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
"required": ["content", "filePath"],
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
252
|
+
path = arguments.get("filePath")
|
|
253
|
+
if not isinstance(path, str) or not path:
|
|
254
|
+
raise ValueError("filePath is required")
|
|
255
|
+
content = arguments.get("content")
|
|
256
|
+
if not isinstance(content, str):
|
|
257
|
+
raise ValueError("content is required")
|
|
258
|
+
mkdir = await self._ensure_parent(path)
|
|
259
|
+
if mkdir.isError:
|
|
260
|
+
return mkdir
|
|
261
|
+
return await self.file_write(path, content)
|
|
262
|
+
|
|
263
|
+
async def _ensure_parent(self, path: str) -> MCPToolResult:
|
|
264
|
+
parent = posixpath.dirname(path)
|
|
265
|
+
if not parent or parent in {".", "/"}:
|
|
266
|
+
return MCPToolResult(content=[])
|
|
267
|
+
return await self.bash(f"mkdir -p {shlex.quote(parent)}")
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class GrepTool(_FilesystemTool):
|
|
271
|
+
name = "grep"
|
|
272
|
+
description = "Searches file contents using a regular expression and returns matching lines."
|
|
273
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
274
|
+
"type": "object",
|
|
275
|
+
"properties": {
|
|
276
|
+
"pattern": {
|
|
277
|
+
"type": "string",
|
|
278
|
+
"description": "Regular expression pattern to search for.",
|
|
279
|
+
},
|
|
280
|
+
"path": {"type": "string", "description": "Directory to search in."},
|
|
281
|
+
"include": {"type": "string", "description": "Glob pattern for files to include."},
|
|
282
|
+
},
|
|
283
|
+
"required": ["pattern"],
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
287
|
+
pattern = arguments.get("pattern")
|
|
288
|
+
if not isinstance(pattern, str):
|
|
289
|
+
raise ValueError("pattern is required")
|
|
290
|
+
path = arguments.get("path") or "."
|
|
291
|
+
cmd = f"grep -rn {shlex.quote(pattern)} {shlex.quote(str(path))}"
|
|
292
|
+
include = arguments.get("include")
|
|
293
|
+
if isinstance(include, str) and include:
|
|
294
|
+
cmd += f" --include={shlex.quote(include)}"
|
|
295
|
+
return await self.bash(cmd)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class GlobTool(_FilesystemTool):
|
|
299
|
+
name = "glob"
|
|
300
|
+
description = "Finds files matching a glob pattern."
|
|
301
|
+
parameters: ClassVar[dict[str, Any]] = {
|
|
302
|
+
"type": "object",
|
|
303
|
+
"properties": {
|
|
304
|
+
"pattern": {"type": "string", "description": "Glob pattern to match."},
|
|
305
|
+
"path": {"type": "string", "description": "Directory to search from."},
|
|
306
|
+
},
|
|
307
|
+
"required": ["pattern"],
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async def execute(self, arguments: dict[str, Any]) -> MCPToolResult:
|
|
311
|
+
pattern = arguments.get("pattern")
|
|
312
|
+
if not isinstance(pattern, str):
|
|
313
|
+
raise ValueError("pattern is required")
|
|
314
|
+
path = arguments.get("path") or "."
|
|
315
|
+
return await self.bash(f"find {shlex.quote(str(path))} -name {shlex.quote(pattern)}")
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _positive_int(value: Any, *, default: int, name: str) -> int:
|
|
319
|
+
if value is None:
|
|
320
|
+
return default
|
|
321
|
+
if not isinstance(value, int) or value < 1:
|
|
322
|
+
raise ValueError(f"{name} must be a positive integer")
|
|
323
|
+
return value
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _read_offset(value: Any) -> int:
|
|
327
|
+
if value is None or value == 0:
|
|
328
|
+
return 1
|
|
329
|
+
return _positive_int(value, default=1, name="offset")
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
__all__ = ["BashTool", "EditTool", "GlobTool", "GrepTool", "ReadTool", "WriteTool"]
|