verifiers 0.3.2.dev65__tar.gz → 0.3.2.dev67__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.
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/PKG-INFO +1 -1
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/bash/harness.py +0 -2
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/browser_use/program.py +53 -55
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/null/harness.py +0 -2
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/utils/core.py +31 -28
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/utils/launch.py +1 -4
- verifiers-0.3.2.dev67/verifiers/v1/harnesses/utils/mcp.py +201 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/harbor/taskset.py +8 -2
- verifiers-0.3.2.dev65/verifiers/v1/harnesses/utils/mcp.py +0 -127
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/.gitignore +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/LICENSE +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/README.md +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/pyproject.toml +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/conftest.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/duet_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/echo_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/pyproject.toml +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_color_codeword_tasks.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_configs.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_e2e.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_envs.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_graph.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_judges.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_scoring.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/tests/v1/test_trace.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/cli/commands/init.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/acp/runner.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/agent.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/dashboard/eval.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/debug.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/eval/main.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/eval/runner.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/gepa.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/init.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/replay.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/resume.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/cli/validate.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/clients/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/clients/train.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/agent.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/eval.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/init.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/cli/validate.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/client.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/runtime.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/isolated_verifier/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/isolated_verifier/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/shared_agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/episode.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/errors.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/graph.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/node.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/pool/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/pool/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/rlm/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/utils/compaction.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/utils/install.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/server.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/tool.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/interception/tunnel/prime.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judge.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/mcp/launch.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/mcp/toolset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/rollout.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/limiters.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/modal.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/prime.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/semantic.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/client.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/encoding.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/pool.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/server.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/serve/types.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/session.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/state.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/task.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/harbor/env.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/lean/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/lean/scoring.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/lean/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/trace.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/types.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/artifacts.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/decorators.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/loaders.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/paths.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/platform.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/prime.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/retries.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/score.py +0 -0
- {verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev67
|
|
4
4
|
Summary: Verifiers: Environments for LLM Reinforcement Learning
|
|
5
5
|
Project-URL: Homepage, https://github.com/primeintellect-ai/verifiers
|
|
6
6
|
Project-URL: Documentation, https://github.com/primeintellect-ai/verifiers
|
|
@@ -8,7 +8,6 @@ from verifiers.v1.configs.harness import HarnessConfig
|
|
|
8
8
|
from verifiers.v1.harness import Harness
|
|
9
9
|
from verifiers.v1.harnesses.utils.launch import (
|
|
10
10
|
CHAT_PROGRAM_SOURCE,
|
|
11
|
-
MCP_CHAT_PROGRAM_SOURCE,
|
|
12
11
|
launch_chat_program,
|
|
13
12
|
)
|
|
14
13
|
from verifiers.v1.runtimes import ProgramResult, Runtime
|
|
@@ -122,7 +121,6 @@ class BashHarness(Harness[BashHarnessConfig]):
|
|
|
122
121
|
mcp_urls,
|
|
123
122
|
system_prompt,
|
|
124
123
|
prompt,
|
|
125
|
-
source_with_mcp=MCP_CHAT_PROGRAM_SOURCE,
|
|
126
124
|
extra_args=args,
|
|
127
125
|
env=env,
|
|
128
126
|
activate=False,
|
{verifiers-0.3.2.dev65 → verifiers-0.3.2.dev67}/verifiers/v1/harnesses/browser_use/program.py
RENAMED
|
@@ -27,6 +27,7 @@ import subprocess
|
|
|
27
27
|
import sys
|
|
28
28
|
import time
|
|
29
29
|
import urllib.request
|
|
30
|
+
from contextlib import AsyncExitStack
|
|
30
31
|
from pathlib import Path
|
|
31
32
|
from typing import TYPE_CHECKING, Any, cast
|
|
32
33
|
from urllib.parse import urlsplit
|
|
@@ -226,63 +227,60 @@ async def main() -> None:
|
|
|
226
227
|
config = json.loads(args.mcp_config or "{}")
|
|
227
228
|
tools = [BROWSER_TOOL]
|
|
228
229
|
reserved = {"browser"}
|
|
229
|
-
|
|
230
|
-
await connect_mcp(config, reserved)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
230
|
+
async with AsyncExitStack() as mcp_stack:
|
|
231
|
+
mcp_tools, dispatch, servers = await connect_mcp(config, mcp_stack, reserved)
|
|
232
|
+
tools += mcp_tools
|
|
233
|
+
messages = (
|
|
234
|
+
[{"role": "system", "content": args.system_prompt}]
|
|
235
|
+
if args.system_prompt
|
|
236
|
+
else []
|
|
237
|
+
)
|
|
238
|
+
if initial:
|
|
239
|
+
messages.extend(initial)
|
|
240
|
+
elif args.prompt:
|
|
241
|
+
messages.append({"role": "user", "content": args.prompt})
|
|
242
|
+
while True:
|
|
243
|
+
message = await chat(client, args.model, messages, tools)
|
|
244
|
+
messages.append(message.model_dump(exclude_none=True))
|
|
245
|
+
if not message.tool_calls:
|
|
246
|
+
break
|
|
247
|
+
for call in message.tool_calls:
|
|
248
|
+
name = call.function.name
|
|
249
|
+
try:
|
|
250
|
+
tool_args = json.loads(call.function.arguments or "{}")
|
|
251
|
+
except json.JSONDecodeError as e:
|
|
252
|
+
messages.append(
|
|
253
|
+
{
|
|
254
|
+
"role": "tool",
|
|
255
|
+
"tool_call_id": call.id,
|
|
256
|
+
"content": f"error: invalid JSON in tool arguments ({e}); resend the call with valid JSON",
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
continue
|
|
260
|
+
# Valid JSON can still be a non-object (`[]`, `42`, `null`); the `.get(...)` calls
|
|
261
|
+
# below assume a dict, so reject anything else as a tool error rather than crashing.
|
|
262
|
+
if not isinstance(tool_args, dict):
|
|
263
|
+
messages.append(
|
|
264
|
+
{
|
|
265
|
+
"role": "tool",
|
|
266
|
+
"tool_call_id": call.id,
|
|
267
|
+
"content": f"error: tool arguments must be a JSON object, got {type(tool_args).__name__}; resend as an object",
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
continue
|
|
271
|
+
if name in dispatch:
|
|
272
|
+
content = await call_mcp(servers, dispatch, name, tool_args)
|
|
273
|
+
elif name == "browser":
|
|
274
|
+
content = await asyncio.to_thread(
|
|
275
|
+
run_browser,
|
|
276
|
+
tool_args.get("code", ""),
|
|
277
|
+
browser_env,
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
content = f"error: unknown tool {name!r}"
|
|
265
281
|
messages.append(
|
|
266
|
-
{
|
|
267
|
-
"role": "tool",
|
|
268
|
-
"tool_call_id": call.id,
|
|
269
|
-
"content": f"error: tool arguments must be a JSON object, got {type(tool_args).__name__}; resend as an object",
|
|
270
|
-
}
|
|
271
|
-
)
|
|
272
|
-
continue
|
|
273
|
-
if name in dispatch:
|
|
274
|
-
content = await call_mcp(servers, dispatch, name, tool_args)
|
|
275
|
-
elif name == "browser":
|
|
276
|
-
content = await asyncio.to_thread(
|
|
277
|
-
run_browser,
|
|
278
|
-
tool_args.get("code", ""),
|
|
279
|
-
browser_env,
|
|
282
|
+
{"role": "tool", "tool_call_id": call.id, "content": content}
|
|
280
283
|
)
|
|
281
|
-
else:
|
|
282
|
-
content = f"error: unknown tool {name!r}"
|
|
283
|
-
messages.append(
|
|
284
|
-
{"role": "tool", "tool_call_id": call.id, "content": content}
|
|
285
|
-
)
|
|
286
284
|
|
|
287
285
|
|
|
288
286
|
if __name__ == "__main__":
|
|
@@ -3,7 +3,6 @@ from verifiers.v1.configs.harness import HarnessConfig
|
|
|
3
3
|
from verifiers.v1.harness import Harness
|
|
4
4
|
from verifiers.v1.harnesses.utils.launch import (
|
|
5
5
|
CHAT_PROGRAM_SOURCE,
|
|
6
|
-
MCP_CHAT_PROGRAM_SOURCE,
|
|
7
6
|
launch_chat_program,
|
|
8
7
|
)
|
|
9
8
|
from verifiers.v1.runtimes import ProgramResult, Runtime
|
|
@@ -47,5 +46,4 @@ class NullHarness(Harness[NullHarnessConfig]):
|
|
|
47
46
|
mcp_urls,
|
|
48
47
|
system_prompt,
|
|
49
48
|
prompt,
|
|
50
|
-
source_with_mcp=MCP_CHAT_PROGRAM_SOURCE,
|
|
51
49
|
)
|
|
@@ -4,6 +4,7 @@ import argparse
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import json
|
|
6
6
|
import subprocess
|
|
7
|
+
from contextlib import AsyncExitStack
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import TYPE_CHECKING
|
|
9
10
|
|
|
@@ -361,35 +362,37 @@ async def main() -> None:
|
|
|
361
362
|
if args.search:
|
|
362
363
|
tools.append(SEARCH_TOOL)
|
|
363
364
|
reserved.add("search")
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
async with AsyncExitStack() as mcp_stack:
|
|
366
|
+
if config.get("mcpServers"):
|
|
367
|
+
mcp_tools, dispatch, servers = await asyncio.wait_for(
|
|
368
|
+
connect_mcp(config, mcp_stack, reserved),
|
|
369
|
+
timeout=None if args.bash else 60,
|
|
370
|
+
)
|
|
371
|
+
else:
|
|
372
|
+
mcp_tools, dispatch, servers = [], {}, {}
|
|
373
|
+
tools += mcp_tools
|
|
374
|
+
messages = (
|
|
375
|
+
[{"role": "system", "content": args.system_prompt}]
|
|
376
|
+
if args.system_prompt
|
|
377
|
+
else []
|
|
367
378
|
)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
args
|
|
385
|
-
args.summarize_at_tokens,
|
|
386
|
-
)
|
|
387
|
-
if compactor.enabled and compactor.threshold is None:
|
|
388
|
-
compactor.threshold = await discover_threshold(client, args.model)
|
|
389
|
-
# The initial conversation is the floor for checkpoint fallbacks: a first-turn
|
|
390
|
-
# checkpoint must never retry from an empty base.
|
|
391
|
-
compactor.note_good(messages)
|
|
392
|
-
await run_chat_loop(args, compactor, messages, dispatch, servers, tool_client)
|
|
379
|
+
if initial:
|
|
380
|
+
messages.extend(initial)
|
|
381
|
+
elif args.prompt:
|
|
382
|
+
messages.append({"role": "user", "content": args.prompt})
|
|
383
|
+
compactor = Compactor(
|
|
384
|
+
client,
|
|
385
|
+
args.model,
|
|
386
|
+
tools,
|
|
387
|
+
args.compaction,
|
|
388
|
+
args.summarize_at_tokens,
|
|
389
|
+
)
|
|
390
|
+
if compactor.enabled and compactor.threshold is None:
|
|
391
|
+
compactor.threshold = await discover_threshold(client, args.model)
|
|
392
|
+
# The initial conversation is the floor for checkpoint fallbacks: a first-turn
|
|
393
|
+
# checkpoint must never retry from an empty base.
|
|
394
|
+
compactor.note_good(messages)
|
|
395
|
+
await run_chat_loop(args, compactor, messages, dispatch, servers, tool_client)
|
|
393
396
|
if tool_client is not None:
|
|
394
397
|
await tool_client.aclose()
|
|
395
398
|
|
|
@@ -29,8 +29,7 @@ CHAT_PROGRAM = (
|
|
|
29
29
|
'# dependencies = ["openai", "mcp==2.0.0", "httpx", "httpx2", "tenacity"]\n'
|
|
30
30
|
"# ///\n"
|
|
31
31
|
)
|
|
32
|
-
CHAT_PROGRAM_SOURCE = bundle_program(CHAT_PROGRAM, compaction, core)
|
|
33
|
-
MCP_CHAT_PROGRAM_SOURCE = bundle_program(CHAT_PROGRAM, mcp, compaction, core)
|
|
32
|
+
CHAT_PROGRAM_SOURCE = bundle_program(CHAT_PROGRAM, mcp, compaction, core)
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
async def launch_chat_program(
|
|
@@ -45,7 +44,6 @@ async def launch_chat_program(
|
|
|
45
44
|
system_prompt: str | None,
|
|
46
45
|
prompt: str | Messages | None,
|
|
47
46
|
*,
|
|
48
|
-
source_with_mcp: str | None = None,
|
|
49
47
|
extra_args: Sequence[str] = (),
|
|
50
48
|
env: dict[str, str] | None = None,
|
|
51
49
|
activate: bool = True,
|
|
@@ -60,7 +58,6 @@ async def launch_chat_program(
|
|
|
60
58
|
if system_prompt:
|
|
61
59
|
args.append(f"--system-prompt={system_prompt}")
|
|
62
60
|
if mcp_urls:
|
|
63
|
-
source = source_with_mcp or source
|
|
64
61
|
args.append(
|
|
65
62
|
"--mcp-config="
|
|
66
63
|
+ json.dumps(
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
|
|
3
|
+
from contextlib import AsyncExitStack, asynccontextmanager, suppress
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
5
|
+
|
|
6
|
+
from anyio import CancelScope
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from mcp import Client
|
|
10
|
+
|
|
11
|
+
MCP_CALL_ATTEMPTS = 6
|
|
12
|
+
MCP_TIMEOUT = 600.0
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@asynccontextmanager
|
|
18
|
+
async def mcp_client(spec: dict[str, Any]) -> AsyncIterator["Client"]:
|
|
19
|
+
"""Open one fresh MCP client in the caller's task.
|
|
20
|
+
|
|
21
|
+
The client negotiates the newest protocol and falls back for older servers.
|
|
22
|
+
Teardown failures after the body completes are suppressed so closing noise cannot
|
|
23
|
+
fail or replay a call whose result is already available.
|
|
24
|
+
"""
|
|
25
|
+
# Bundled chat programs also run without tools; load MCP only when it is used.
|
|
26
|
+
import httpx2
|
|
27
|
+
from mcp import Client
|
|
28
|
+
from mcp.client.streamable_http import (
|
|
29
|
+
create_mcp_http_client,
|
|
30
|
+
streamable_http_client,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
stack = AsyncExitStack()
|
|
34
|
+
try:
|
|
35
|
+
http_client = await stack.enter_async_context(
|
|
36
|
+
create_mcp_http_client(
|
|
37
|
+
headers=spec.get("headers") or None,
|
|
38
|
+
timeout=httpx2.Timeout(
|
|
39
|
+
spec.get("timeout", MCP_TIMEOUT),
|
|
40
|
+
connect=spec.get("connect_timeout", 5.0),
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
transport = streamable_http_client(spec["url"], http_client=http_client)
|
|
45
|
+
yield await stack.enter_async_context(Client(transport))
|
|
46
|
+
finally:
|
|
47
|
+
with suppress(Exception):
|
|
48
|
+
await stack.aclose()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MCPConnection:
|
|
52
|
+
"""One rollout-owned client, with operations serialized across reconnects.
|
|
53
|
+
|
|
54
|
+
The SDK's AnyIO contexts enter and exit in the owner task, even when discovery
|
|
55
|
+
runs under wait_for or a tool call is cancelled by another task.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, spec: dict[str, Any]):
|
|
59
|
+
# Bundled programs without MCP should not import the retry machinery.
|
|
60
|
+
from tenacity import AsyncRetrying, stop_after_attempt, wait_exponential_jitter
|
|
61
|
+
|
|
62
|
+
self.spec = spec
|
|
63
|
+
self.task: asyncio.Task[None] | None = None
|
|
64
|
+
self.ready: asyncio.Future[Client] | None = None
|
|
65
|
+
self.cancel_scope: CancelScope | None = None
|
|
66
|
+
self.lock = asyncio.Lock()
|
|
67
|
+
self.run = AsyncRetrying(
|
|
68
|
+
stop=stop_after_attempt(MCP_CALL_ATTEMPTS),
|
|
69
|
+
wait=wait_exponential_jitter(initial=0.5, max=30),
|
|
70
|
+
reraise=True,
|
|
71
|
+
).wraps(self._run)
|
|
72
|
+
|
|
73
|
+
async def serve(
|
|
74
|
+
self, ready: asyncio.Future["Client"], cancel_scope: CancelScope
|
|
75
|
+
) -> None:
|
|
76
|
+
stack = AsyncExitStack()
|
|
77
|
+
try:
|
|
78
|
+
stack.enter_context(cancel_scope)
|
|
79
|
+
client = await stack.enter_async_context(mcp_client(self.spec))
|
|
80
|
+
ready.set_result(client)
|
|
81
|
+
await asyncio.Future()
|
|
82
|
+
except asyncio.CancelledError:
|
|
83
|
+
pass
|
|
84
|
+
except Exception as error: # noqa: BLE001 - deliver owner failures to the caller
|
|
85
|
+
if not ready.done():
|
|
86
|
+
ready.set_exception(error)
|
|
87
|
+
finally:
|
|
88
|
+
if not ready.done():
|
|
89
|
+
ready.cancel()
|
|
90
|
+
# Owner teardown must not replace the caller's error with cancellation.
|
|
91
|
+
with suppress(asyncio.CancelledError):
|
|
92
|
+
await stack.aclose()
|
|
93
|
+
|
|
94
|
+
async def _run(self, operation: Callable[["Client"], Awaitable[T]]) -> T:
|
|
95
|
+
await self.lock.acquire()
|
|
96
|
+
try:
|
|
97
|
+
if self.task is None or self.task.done():
|
|
98
|
+
self.ready = asyncio.get_running_loop().create_future()
|
|
99
|
+
self.cancel_scope = CancelScope()
|
|
100
|
+
self.task = asyncio.create_task(
|
|
101
|
+
self.serve(self.ready, self.cancel_scope)
|
|
102
|
+
)
|
|
103
|
+
assert self.ready is not None
|
|
104
|
+
client = await self.ready
|
|
105
|
+
return await operation(client)
|
|
106
|
+
except BaseException as error:
|
|
107
|
+
await self.aclose(abort=isinstance(error, asyncio.CancelledError))
|
|
108
|
+
raise
|
|
109
|
+
finally:
|
|
110
|
+
self.lock.release()
|
|
111
|
+
|
|
112
|
+
async def aclose(self, *, abort: bool = False) -> None:
|
|
113
|
+
if self.task is None:
|
|
114
|
+
return
|
|
115
|
+
task, self.task = self.task, None
|
|
116
|
+
cancel_scope = self.cancel_scope
|
|
117
|
+
assert cancel_scope is not None
|
|
118
|
+
caller = asyncio.current_task()
|
|
119
|
+
assert caller is not None
|
|
120
|
+
# Stack cleanup can follow cancellation while awaiting a model or local tool.
|
|
121
|
+
if abort or caller.cancelling():
|
|
122
|
+
cancel_scope.cancel()
|
|
123
|
+
else:
|
|
124
|
+
task.cancel()
|
|
125
|
+
try:
|
|
126
|
+
await asyncio.shield(task)
|
|
127
|
+
except asyncio.CancelledError:
|
|
128
|
+
cancel_scope.cancel()
|
|
129
|
+
await asyncio.shield(task)
|
|
130
|
+
raise
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def connect_mcp(
|
|
134
|
+
config: dict[str, Any], stack: AsyncExitStack, reserved: set[str] | None = None
|
|
135
|
+
) -> tuple[
|
|
136
|
+
list[dict[str, Any]],
|
|
137
|
+
dict[str, tuple[str, str]],
|
|
138
|
+
dict[str, MCPConnection],
|
|
139
|
+
]:
|
|
140
|
+
"""Enumerate MCP tools and return their schemas, dispatch map, and servers."""
|
|
141
|
+
tool_schemas: list[dict[str, Any]] = []
|
|
142
|
+
dispatch: dict[str, tuple[str, str]] = {}
|
|
143
|
+
servers: dict[str, MCPConnection] = {}
|
|
144
|
+
reserved = reserved or set()
|
|
145
|
+
for name, spec in config.get("mcpServers", {}).items():
|
|
146
|
+
server = servers[name] = MCPConnection(spec)
|
|
147
|
+
stack.push_async_callback(server.aclose)
|
|
148
|
+
result = await server.run(lambda client: client.list_tools())
|
|
149
|
+
for tool in result.tools:
|
|
150
|
+
full = f"{name}_{tool.name}" if name else tool.name
|
|
151
|
+
if full in reserved or full in dispatch:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
f"duplicate tool name {full!r}; keep MCP tool names qualified"
|
|
154
|
+
)
|
|
155
|
+
tool_schemas.append(
|
|
156
|
+
{
|
|
157
|
+
"type": "function",
|
|
158
|
+
"function": {
|
|
159
|
+
"name": full,
|
|
160
|
+
"description": tool.description or "",
|
|
161
|
+
"parameters": tool.input_schema,
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
dispatch[full] = (name, tool.name)
|
|
166
|
+
return tool_schemas, dispatch, servers
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def mcp_content_to_chat_content(
|
|
170
|
+
blocks: Sequence[Any],
|
|
171
|
+
) -> str | list[dict[str, Any]]:
|
|
172
|
+
"""Convert MCP content blocks to OpenAI chat tool-result content."""
|
|
173
|
+
parts = []
|
|
174
|
+
for block in blocks:
|
|
175
|
+
if block.type == "text":
|
|
176
|
+
parts.append({"type": "text", "text": block.text})
|
|
177
|
+
elif block.type == "image":
|
|
178
|
+
url = f"data:{block.mime_type};base64,{block.data}"
|
|
179
|
+
parts.append({"type": "image_url", "image_url": {"url": url}})
|
|
180
|
+
else:
|
|
181
|
+
parts.append({"type": "text", "text": str(block)})
|
|
182
|
+
if not parts:
|
|
183
|
+
return str(blocks)
|
|
184
|
+
if all(part["type"] == "text" for part in parts):
|
|
185
|
+
return "\n".join(cast(str, part["text"]) for part in parts)
|
|
186
|
+
return parts
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
async def call_mcp(
|
|
190
|
+
servers: dict[str, MCPConnection],
|
|
191
|
+
dispatch: dict[str, tuple[str, str]],
|
|
192
|
+
name: str,
|
|
193
|
+
arguments: dict[str, Any],
|
|
194
|
+
) -> str | list[dict[str, Any]]:
|
|
195
|
+
"""Reuse the rollout's client, reconnecting before retrying a failed call."""
|
|
196
|
+
server_name, raw = dispatch[name]
|
|
197
|
+
|
|
198
|
+
result = await servers[server_name].run(
|
|
199
|
+
lambda client: client.call_tool(raw, arguments)
|
|
200
|
+
)
|
|
201
|
+
return mcp_content_to_chat_content(result.content)
|
|
@@ -379,7 +379,13 @@ def task_resources(environment, multiplier: float) -> TaskResources:
|
|
|
379
379
|
memory=environment.memory_mb / 1024 * multiplier
|
|
380
380
|
if environment.memory_mb
|
|
381
381
|
else None,
|
|
382
|
-
gpu=
|
|
382
|
+
gpu=(
|
|
383
|
+
f"{environment.gpu_types[0]}:{environment.gpus}"
|
|
384
|
+
if environment.gpu_types
|
|
385
|
+
else str(environment.gpus)
|
|
386
|
+
)
|
|
387
|
+
if environment.gpus
|
|
388
|
+
else None,
|
|
383
389
|
disk=environment.storage_mb / 1024 * multiplier
|
|
384
390
|
if environment.storage_mb
|
|
385
391
|
else None,
|
|
@@ -694,7 +700,7 @@ def parse_verifier_environment(
|
|
|
694
700
|
)
|
|
695
701
|
unsupported = [
|
|
696
702
|
field
|
|
697
|
-
for field in ("mcp_servers", "skills_dir", "
|
|
703
|
+
for field in ("mcp_servers", "skills_dir", "tpu")
|
|
698
704
|
if getattr(environment, field, None)
|
|
699
705
|
]
|
|
700
706
|
if environment.os != TaskOS.LINUX or unsupported:
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
|
|
2
|
-
from contextlib import AsyncExitStack, asynccontextmanager, suppress
|
|
3
|
-
from typing import Any, TypeVar, cast
|
|
4
|
-
|
|
5
|
-
import httpx2
|
|
6
|
-
from mcp import Client
|
|
7
|
-
from mcp.client.streamable_http import create_mcp_http_client, streamable_http_client
|
|
8
|
-
from tenacity import AsyncRetrying, stop_after_attempt, wait_exponential_jitter
|
|
9
|
-
|
|
10
|
-
MCP_CALL_ATTEMPTS = 6
|
|
11
|
-
MCP_TIMEOUT = 600.0
|
|
12
|
-
|
|
13
|
-
T = TypeVar("T")
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@asynccontextmanager
|
|
17
|
-
async def mcp_client(spec: dict[str, Any]) -> AsyncIterator[Client]:
|
|
18
|
-
"""Open one fresh MCP client in the caller's task.
|
|
19
|
-
|
|
20
|
-
The client negotiates the newest protocol and falls back for older servers.
|
|
21
|
-
Teardown failures after the body completes are suppressed so closing noise cannot
|
|
22
|
-
fail or replay a call whose result is already available.
|
|
23
|
-
"""
|
|
24
|
-
stack = AsyncExitStack()
|
|
25
|
-
try:
|
|
26
|
-
http_client = await stack.enter_async_context(
|
|
27
|
-
create_mcp_http_client(
|
|
28
|
-
headers=spec.get("headers") or None,
|
|
29
|
-
timeout=httpx2.Timeout(
|
|
30
|
-
spec.get("timeout", MCP_TIMEOUT),
|
|
31
|
-
connect=spec.get("connect_timeout", 5.0),
|
|
32
|
-
),
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
transport = streamable_http_client(spec["url"], http_client=http_client)
|
|
36
|
-
yield await stack.enter_async_context(Client(transport))
|
|
37
|
-
finally:
|
|
38
|
-
with suppress(Exception):
|
|
39
|
-
await stack.aclose()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
async def with_retry(call: Callable[[], Awaitable[T]]) -> T:
|
|
43
|
-
"""Run one client operation with the existing at-least-once retries."""
|
|
44
|
-
async for attempt in AsyncRetrying(
|
|
45
|
-
stop=stop_after_attempt(MCP_CALL_ATTEMPTS),
|
|
46
|
-
wait=wait_exponential_jitter(initial=0.5, max=30),
|
|
47
|
-
reraise=True,
|
|
48
|
-
):
|
|
49
|
-
with attempt:
|
|
50
|
-
return await call()
|
|
51
|
-
raise RuntimeError("retrying stopped without returning or raising")
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
async def connect_mcp(
|
|
55
|
-
config: dict[str, Any], reserved: set[str] | None = None
|
|
56
|
-
) -> tuple[
|
|
57
|
-
list[dict[str, Any]],
|
|
58
|
-
dict[str, tuple[str, str]],
|
|
59
|
-
dict[str, dict[str, Any]],
|
|
60
|
-
]:
|
|
61
|
-
"""Enumerate MCP tools and return their schemas, dispatch map, and servers."""
|
|
62
|
-
tool_schemas: list[dict[str, Any]] = []
|
|
63
|
-
dispatch: dict[str, tuple[str, str]] = {}
|
|
64
|
-
servers: dict[str, dict[str, Any]] = {}
|
|
65
|
-
reserved = reserved or set()
|
|
66
|
-
for name, spec in config.get("mcpServers", {}).items():
|
|
67
|
-
servers[name] = spec
|
|
68
|
-
|
|
69
|
-
async def list_tools(spec: dict[str, Any] = spec):
|
|
70
|
-
async with mcp_client(spec) as client:
|
|
71
|
-
return (await client.list_tools()).tools
|
|
72
|
-
|
|
73
|
-
for tool in await with_retry(list_tools):
|
|
74
|
-
full = f"{name}_{tool.name}" if name else tool.name
|
|
75
|
-
if full in reserved or full in dispatch:
|
|
76
|
-
raise ValueError(
|
|
77
|
-
f"duplicate tool name {full!r}; keep MCP tool names qualified"
|
|
78
|
-
)
|
|
79
|
-
tool_schemas.append(
|
|
80
|
-
{
|
|
81
|
-
"type": "function",
|
|
82
|
-
"function": {
|
|
83
|
-
"name": full,
|
|
84
|
-
"description": tool.description or "",
|
|
85
|
-
"parameters": tool.input_schema,
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
)
|
|
89
|
-
dispatch[full] = (name, tool.name)
|
|
90
|
-
return tool_schemas, dispatch, servers
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def mcp_content_to_chat_content(
|
|
94
|
-
blocks: Sequence[Any],
|
|
95
|
-
) -> str | list[dict[str, Any]]:
|
|
96
|
-
"""Convert MCP content blocks to OpenAI chat tool-result content."""
|
|
97
|
-
parts = []
|
|
98
|
-
for block in blocks:
|
|
99
|
-
if block.type == "text":
|
|
100
|
-
parts.append({"type": "text", "text": block.text})
|
|
101
|
-
elif block.type == "image":
|
|
102
|
-
url = f"data:{block.mime_type};base64,{block.data}"
|
|
103
|
-
parts.append({"type": "image_url", "image_url": {"url": url}})
|
|
104
|
-
else:
|
|
105
|
-
parts.append({"type": "text", "text": str(block)})
|
|
106
|
-
if not parts:
|
|
107
|
-
return str(blocks)
|
|
108
|
-
if all(part["type"] == "text" for part in parts):
|
|
109
|
-
return "\n".join(cast(str, part["text"]) for part in parts)
|
|
110
|
-
return parts
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
async def call_mcp(
|
|
114
|
-
servers: dict[str, dict[str, Any]],
|
|
115
|
-
dispatch: dict[str, tuple[str, str]],
|
|
116
|
-
name: str,
|
|
117
|
-
arguments: dict[str, Any],
|
|
118
|
-
) -> str | list[dict[str, Any]]:
|
|
119
|
-
"""Call one MCP tool with a fresh client per retry attempt."""
|
|
120
|
-
server_name, raw = dispatch[name]
|
|
121
|
-
|
|
122
|
-
async def call():
|
|
123
|
-
async with mcp_client(servers[server_name]) as client:
|
|
124
|
-
return await client.call_tool(raw, arguments)
|
|
125
|
-
|
|
126
|
-
result = await with_retry(call)
|
|
127
|
-
return mcp_content_to_chat_content(result.content)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|