verifiers 0.4.1.dev40__tar.gz → 0.4.1.dev42__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.4.1.dev40 → verifiers-0.4.1.dev42}/PKG-INFO +2 -2
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/pyproject.toml +1 -1
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/conftest.py +4 -1
- verifiers-0.4.1.dev42/tests/integration/fixtures/fetch_tool_v1.py +36 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/pyproject.toml +1 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/grid.py +7 -1
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_shared_tool.py +1 -1
- verifiers-0.4.1.dev42/tests/integration/test_tool_vms.py +88 -0
- verifiers-0.4.1.dev42/tests/unit/runtimes/test_private_network.py +254 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/validate.py +66 -10
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/validate.py +3 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/mcp/launch.py +28 -9
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/mcp/toolset.py +3 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/rollout.py +25 -6
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/deployment.py +19 -5
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/prime.py +43 -16
- verifiers-0.4.1.dev42/verifiers/v1/runtimes/private_network.py +148 -0
- verifiers-0.4.1.dev42/verifiers/v1/runtimes/strategies.py +119 -0
- verifiers-0.4.1.dev40/verifiers/v1/runtimes/strategies.py +0 -64
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/.gitignore +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/LICENSE +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/README.md +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/agent_user_harness_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/agent_user_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/duet_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/echo_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/network_policy_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/skill_codeword_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_agent_user.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_agentic_judge.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_compose_scoring.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_examples.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_limits.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_multi_agent.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_multi_turn.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_multi_turn_tool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_multimodal_tool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_network_policy.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_resume_tool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_rubric_judge.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_sampling.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_single_turn.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_skills.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_stateful_tool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_user_echo.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/integration/test_user_sim.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/cli/test_replay.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/conftest.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/harnesses/test_core.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/harnesses/test_rlm.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/interception/test_tunnel.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/judges/conftest.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/judges/test_judge.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/judges/test_reference.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/judges/test_rubric.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/runtimes/test_e2b.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/serve/test_client.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/serve/test_delta.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/serve/test_pool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_agent.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_dialects.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_graph.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_semantic.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_task.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/test_trace.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/utils/test_compile.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/utils/test_loaders.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/utils/test_platform.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/tests/unit/utils/test_score.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/acp/runner.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/agent.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/dashboard/eval.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/debug.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/eval/hint.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/eval/main.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/eval/runner.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/gepa.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/replay.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/cli/resume.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/clients/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/clients/train.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/agent.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/eval.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/client.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/runtime.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/scoring.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/select.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/episode.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/errors.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/grading.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/graph.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/bash/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/browser_use/program.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/node.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/null/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/opencode/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/rlm/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/compaction.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/core.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/install.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/launch.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/mcp.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/harnesses/utils/replay.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/server.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/interception/tunnel/prime.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judge.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/decision.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/apptainer.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/compose.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/container.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/e2b.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/limiters.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/modal.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/runtime.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/semantic.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/client.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/delta.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/encoding.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/pool.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/server.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/serve/types.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/session.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/state.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/task.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/trace.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/types.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/artifacts.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/decorators.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/env.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/eval.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/loaders.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/paths.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/platform.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/prime.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/retries.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/scope.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/score.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/trace_store.py +0 -0
- {verifiers-0.4.1.dev40 → verifiers-0.4.1.dev42}/verifiers/v1/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.4.1.
|
|
3
|
+
Version: 0.4.1.dev42
|
|
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
|
|
@@ -36,7 +36,7 @@ Requires-Dist: numpy>=2.1.0
|
|
|
36
36
|
Requires-Dist: openai<3.0.0,>=2.54.0
|
|
37
37
|
Requires-Dist: prime-pydantic-config[toml]>=0.4.3
|
|
38
38
|
Requires-Dist: prime-runs>=0.1.4
|
|
39
|
-
Requires-Dist: prime-sandboxes>=0.4.
|
|
39
|
+
Requires-Dist: prime-sandboxes>=0.4.7
|
|
40
40
|
Requires-Dist: prime-tunnel>=0.1.14
|
|
41
41
|
Requires-Dist: pydantic>=2.12.3
|
|
42
42
|
Requires-Dist: pyzmq>=27.1.0
|
|
@@ -46,11 +46,14 @@ def harness_runtime(request) -> dict:
|
|
|
46
46
|
@pytest.fixture
|
|
47
47
|
def tool_runtime(request) -> dict:
|
|
48
48
|
"""A `taskset.task.tools` override placing the tool server: `colocated` (inside the harness's
|
|
49
|
-
runtime), `service` (in the task's `tools` Compose service)
|
|
49
|
+
runtime), `service` (in the task's `tools` Compose service), `service-vm` (in the task's
|
|
50
|
+
`tools-vm` service VM) or its own runtime, by type."""
|
|
50
51
|
if request.param == "colocated":
|
|
51
52
|
return {"colocated": True}
|
|
52
53
|
if request.param == "service":
|
|
53
54
|
return {"service": "tools"}
|
|
55
|
+
if request.param == "service-vm":
|
|
56
|
+
return {"service": "tools-vm"}
|
|
54
57
|
return {"runtime": {"type": request.param}}
|
|
55
58
|
|
|
56
59
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""fetch (v1, MCP tool): a tool server on a Prime VM of its own, under its own egress.
|
|
2
|
+
|
|
3
|
+
The integration test places a `FetchToolset` on a Prime runtime of its own
|
|
4
|
+
(`tools.runtime`) beside an offline workspace. The server's VM joins the workspace over
|
|
5
|
+
the rollout's private network and keeps the egress policy of its own runtime.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import urllib.request
|
|
9
|
+
|
|
10
|
+
import verifiers.v1 as vf
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FetchToolset(vf.Toolset[vf.ToolsetConfig]):
|
|
14
|
+
TOOL_PREFIX = "fetch"
|
|
15
|
+
|
|
16
|
+
@vf.tool
|
|
17
|
+
def fetch(self, url: str) -> str:
|
|
18
|
+
"""Fetch a URL; return its HTTP status, or the type of the error."""
|
|
19
|
+
try:
|
|
20
|
+
return str(urllib.request.urlopen(url, timeout=15).status)
|
|
21
|
+
except (OSError, ValueError) as error: # URLError and timeouts are OSErrors
|
|
22
|
+
return type(error).__name__
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FetchToolTaskConfig(vf.TaskConfig):
|
|
26
|
+
tools: vf.ToolsetConfig = vf.ToolsetConfig()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FetchToolTask(vf.Task[vf.TaskData, vf.State, FetchToolTaskConfig]):
|
|
30
|
+
@classmethod
|
|
31
|
+
def toolsets(cls, config: FetchToolTaskConfig) -> list[vf.Toolset]:
|
|
32
|
+
return [FetchToolset(config.tools)]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
FetchToolset.run()
|
|
@@ -240,9 +240,13 @@ def skip_harness(cells: list, harness: str, reason: str) -> list:
|
|
|
240
240
|
def placements(
|
|
241
241
|
harness_runtimes: tuple[str, ...] = tuple(RUNTIMES),
|
|
242
242
|
tool_runtimes: tuple[str, ...] = ("colocated", *RUNTIMES),
|
|
243
|
+
*,
|
|
244
|
+
shared: bool = False,
|
|
243
245
|
) -> list:
|
|
244
246
|
"""`(harness_runtime, tool_runtime)` cells for a tool server placed colocated in the
|
|
245
|
-
harness's box, in a Compose service beside it (`service`), or in its own runtime
|
|
247
|
+
harness's box, in a Compose service beside it (`service`), or in its own runtime
|
|
248
|
+
(on Prime beside a Prime harness, a VM on the rollout's private network). A `shared`
|
|
249
|
+
server runs once per eval, so it joins no rollout's network."""
|
|
246
250
|
cells = []
|
|
247
251
|
for harness_runtime in harness_runtimes:
|
|
248
252
|
for tool_runtime in tool_runtimes:
|
|
@@ -264,6 +268,8 @@ def placements(
|
|
|
264
268
|
elif (
|
|
265
269
|
tool_runtime not in ("colocated", "service")
|
|
266
270
|
and not runtime_cls(tool_runtime).supports_expose
|
|
271
|
+
# Beside a Prime harness, a rollout's Prime server joins its private network.
|
|
272
|
+
and not (not shared and tool_runtime == harness_runtime == "prime")
|
|
267
273
|
):
|
|
268
274
|
marks.append(
|
|
269
275
|
pytest.mark.skip(
|
|
@@ -8,7 +8,7 @@ from grid import HARNESS_RUNTIMES, placements
|
|
|
8
8
|
|
|
9
9
|
@pytest.mark.parametrize(
|
|
10
10
|
"harness_runtime,tool_runtime",
|
|
11
|
-
placements(tool_runtimes=tuple(HARNESS_RUNTIMES)),
|
|
11
|
+
placements(tool_runtimes=tuple(HARNESS_RUNTIMES), shared=True),
|
|
12
12
|
indirect=True,
|
|
13
13
|
)
|
|
14
14
|
async def test_shared_tool(run, harness_runtime, tool_runtime):
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""A tool server on a Prime runtime of its own runs on a VM of its own, reachable from
|
|
2
|
+
the restricted workspace over the rollout's private network, under the egress policy of
|
|
3
|
+
its own runtime: unrestricted, or none at all."""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from fetch_tool_v1 import FetchToolTask, FetchToolTaskConfig
|
|
10
|
+
|
|
11
|
+
import verifiers.v1 as vf
|
|
12
|
+
from verifiers.v1.configs.agent import TimeoutConfig
|
|
13
|
+
|
|
14
|
+
pytestmark = pytest.mark.skipif(
|
|
15
|
+
not os.environ.get("PRIME_API_KEY"), reason="needs PRIME_API_KEY"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
FETCH = """
|
|
19
|
+
import sys, urllib.error, urllib.request
|
|
20
|
+
try:
|
|
21
|
+
print(urllib.request.urlopen(sys.argv[1], timeout=15).status)
|
|
22
|
+
except urllib.error.HTTPError as error:
|
|
23
|
+
print(error.code)
|
|
24
|
+
except Exception as error:
|
|
25
|
+
print(type(error).__name__)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# The workspace reaches the tool server (any HTTP status) but not the internet.
|
|
29
|
+
PROBE = """
|
|
30
|
+
import json, sys, urllib.error, urllib.request
|
|
31
|
+
|
|
32
|
+
def fetch(url):
|
|
33
|
+
try:
|
|
34
|
+
return urllib.request.urlopen(url, timeout=15).status
|
|
35
|
+
except urllib.error.HTTPError as error:
|
|
36
|
+
return error.code
|
|
37
|
+
except Exception as error:
|
|
38
|
+
return type(error).__name__
|
|
39
|
+
|
|
40
|
+
json.dump(
|
|
41
|
+
{"tool": fetch(sys.argv[1]), "public": fetch("https://example.com")},
|
|
42
|
+
open("/tmp/probe.json", "w"),
|
|
43
|
+
)
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ProbeHarness(vf.Harness):
|
|
48
|
+
SUPPORTS_MCP = True
|
|
49
|
+
|
|
50
|
+
async def launch(self, ctx, trace, runtime, endpoint, secret, mcp_urls, data):
|
|
51
|
+
trace.info["url"] = mcp_urls["fetch"]
|
|
52
|
+
return await runtime.run_program(["python", "-c", PROBE, mcp_urls["fetch"]], {})
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ProbeTask(FetchToolTask):
|
|
56
|
+
async def finalize(self, trace, runtime, deployment):
|
|
57
|
+
trace.info["workspace"] = json.loads(await runtime.read("/tmp/probe.json"))
|
|
58
|
+
tool = await deployment.target("fetch").run(
|
|
59
|
+
["python", "-c", FETCH, "https://example.com"], {}
|
|
60
|
+
)
|
|
61
|
+
trace.info["tool"] = tool.stdout.strip()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.mark.parametrize(("allow", "egress"), [(["*"], "200"), ([], "URLError")])
|
|
65
|
+
async def test_a_tool_vm_keeps_its_own_egress_beside_a_restricted_workspace(
|
|
66
|
+
allow, egress
|
|
67
|
+
):
|
|
68
|
+
tools = vf.ToolsetConfig(
|
|
69
|
+
runtime=vf.PrimeConfig(labels=["vf-integration"], allow=allow)
|
|
70
|
+
)
|
|
71
|
+
task = ProbeTask(
|
|
72
|
+
vf.TaskData(prompt="Probe the network", network_allow=[]),
|
|
73
|
+
FetchToolTaskConfig(tools=tools),
|
|
74
|
+
)
|
|
75
|
+
config = vf.AgentConfig(
|
|
76
|
+
model="unused",
|
|
77
|
+
runtime=vf.PrimeConfig(labels=["vf-integration"]),
|
|
78
|
+
timeout=TimeoutConfig(setup=900, finalize=120, scoring=60),
|
|
79
|
+
)
|
|
80
|
+
async with vf.Agent(config) as agent:
|
|
81
|
+
agent.harness = ProbeHarness(vf.HarnessConfig())
|
|
82
|
+
trace = await agent.run(task)
|
|
83
|
+
assert trace.ok, trace.errors
|
|
84
|
+
assert ".sandbox.internal:" in trace.info["url"]
|
|
85
|
+
workspace = trace.info["workspace"]
|
|
86
|
+
assert isinstance(workspace["tool"], int), workspace
|
|
87
|
+
assert workspace["public"] == "URLError"
|
|
88
|
+
assert trace.info["tool"] == egress
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from contextlib import asynccontextmanager
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import verifiers.v1 as vf
|
|
8
|
+
from verifiers.v1.errors import ToolsetError
|
|
9
|
+
from verifiers.v1.mcp import launch
|
|
10
|
+
from verifiers.v1.runtimes import (
|
|
11
|
+
DockerConfig,
|
|
12
|
+
PrimeBackend,
|
|
13
|
+
PrimeConfig,
|
|
14
|
+
prime,
|
|
15
|
+
private_network,
|
|
16
|
+
)
|
|
17
|
+
from verifiers.v1.runtimes.strategies import (
|
|
18
|
+
_ColocatedDeployment,
|
|
19
|
+
_ContainerDeployment,
|
|
20
|
+
_deployment_strategy,
|
|
21
|
+
_PrivateNetworkDeployment,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
ATLAS = PrimeConfig(image="atlas:1", cpu=4, memory=10) # open egress by default
|
|
25
|
+
FORTH = PrimeConfig(image="forth:1", allow=[])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def toolset(name, **config):
|
|
29
|
+
return SimpleNamespace(server_name=name, config=vf.ToolsetConfig(**config))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_tool_servers_on_prime_runtimes_beside_a_prime_workspace_get_vms():
|
|
33
|
+
toolsets = [
|
|
34
|
+
toolset("atlas", runtime=ATLAS),
|
|
35
|
+
toolset("search"), # the evaluator
|
|
36
|
+
toolset("files", colocated=True, runtime=ATLAS), # the workspace
|
|
37
|
+
toolset("remote", url="https://tools.example/mcp"),
|
|
38
|
+
toolset("gym", service="tools"), # a Compose service
|
|
39
|
+
toolset("local", runtime=DockerConfig()), # a published port
|
|
40
|
+
]
|
|
41
|
+
vms = private_network.tool_vms
|
|
42
|
+
assert vms(toolsets, PrimeConfig(), composed=False, borrowed=False) == {
|
|
43
|
+
"atlas": ATLAS
|
|
44
|
+
}
|
|
45
|
+
# Without a Prime workspace of the rollout's own, servers keep their published port.
|
|
46
|
+
for workspace, composed, borrowed in [
|
|
47
|
+
(DockerConfig(), False, False),
|
|
48
|
+
(PrimeConfig(), True, False),
|
|
49
|
+
(PrimeConfig(), False, True),
|
|
50
|
+
]:
|
|
51
|
+
assert vms(toolsets, workspace, composed=composed, borrowed=borrowed) == {}
|
|
52
|
+
with pytest.raises(ValueError, match="cannot be named 'main'"):
|
|
53
|
+
vms(
|
|
54
|
+
[toolset("main", runtime=ATLAS)],
|
|
55
|
+
PrimeConfig(),
|
|
56
|
+
composed=False,
|
|
57
|
+
borrowed=False,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_the_deployment_joins_tool_vms_over_a_private_network():
|
|
62
|
+
assert isinstance(
|
|
63
|
+
_deployment_strategy(None, PrimeConfig(), None, {"atlas": ATLAS}),
|
|
64
|
+
_PrivateNetworkDeployment,
|
|
65
|
+
)
|
|
66
|
+
assert isinstance(
|
|
67
|
+
_deployment_strategy(None, PrimeConfig(), None, {}), _ColocatedDeployment
|
|
68
|
+
)
|
|
69
|
+
spec = vf.ComposeSpec("task")
|
|
70
|
+
assert isinstance(
|
|
71
|
+
_deployment_strategy(None, PrimeConfig(), spec), _ContainerDeployment
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_the_private_network_needs_a_prime_workspace():
|
|
76
|
+
workspace = SimpleNamespace(config=DockerConfig())
|
|
77
|
+
|
|
78
|
+
async def enter():
|
|
79
|
+
async with private_network.private_network(workspace, {"atlas": ATLAS}, None):
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
with pytest.raises(TypeError, match="needs the workspace on Prime, not docker"):
|
|
83
|
+
asyncio.run(enter())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class FakeLanClient:
|
|
87
|
+
def __init__(self, events):
|
|
88
|
+
self.events = events
|
|
89
|
+
|
|
90
|
+
async def create_lan_network(self, name, rules):
|
|
91
|
+
self.events.append(("network", [(rule.from_, rule.to) for rule in rules]))
|
|
92
|
+
return SimpleNamespace(id="net1")
|
|
93
|
+
|
|
94
|
+
async def delete_lan_network(self, network_id):
|
|
95
|
+
self.events.append("network deleted")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def boot(monkeypatch, members):
|
|
99
|
+
"""Enter `private_network` with a fake LAN client and Prime VMs that record their
|
|
100
|
+
boot and stop there."""
|
|
101
|
+
events = []
|
|
102
|
+
|
|
103
|
+
@asynccontextmanager
|
|
104
|
+
async def leased_client():
|
|
105
|
+
yield FakeLanClient(events)
|
|
106
|
+
|
|
107
|
+
async def start(self):
|
|
108
|
+
events.append(("boot", self.name, self.config, self.lan))
|
|
109
|
+
raise RuntimeError("booted")
|
|
110
|
+
|
|
111
|
+
monkeypatch.setattr(private_network, "leased_client", leased_client)
|
|
112
|
+
monkeypatch.setattr(prime, "ensure_prime_auth", lambda: None)
|
|
113
|
+
monkeypatch.setattr(PrimeBackend, "start", start)
|
|
114
|
+
workspace = PrimeBackend(PrimeConfig(allow=[]), name="ws")
|
|
115
|
+
|
|
116
|
+
async def enter():
|
|
117
|
+
async with private_network.private_network(workspace, members, workspace.start):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
with pytest.raises(RuntimeError, match="booted"):
|
|
121
|
+
asyncio.run(enter())
|
|
122
|
+
return events
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_each_vm_boots_its_server_runtime_as_given(monkeypatch):
|
|
126
|
+
events = boot(monkeypatch, {"atlas": ATLAS, "forth": FORTH})
|
|
127
|
+
vms = {e[1]: e[2] for e in events if isinstance(e, tuple) and e[0] == "boot"}
|
|
128
|
+
|
|
129
|
+
def shape(config):
|
|
130
|
+
return config.image, config.cpu, config.memory, config.allow
|
|
131
|
+
|
|
132
|
+
assert shape(vms["ws-vf-tool-0"]) == ("atlas:1", 4, 10, ["*"])
|
|
133
|
+
assert shape(vms["ws-vf-tool-1"]) == ("forth:1", FORTH.cpu, FORTH.memory, [])
|
|
134
|
+
assert vms["ws"].allow == [] # the workspace keeps its own policy
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_the_network_starts_with_its_rules_and_every_vm_joins_as_it_boots(monkeypatch):
|
|
138
|
+
events = boot(monkeypatch, {"atlas": ATLAS, "forth": FORTH})
|
|
139
|
+
assert events[0] == (
|
|
140
|
+
"network",
|
|
141
|
+
[("tag:vf-workspace", "tag:vf-tool-0"), ("tag:vf-workspace", "tag:vf-tool-1")],
|
|
142
|
+
)
|
|
143
|
+
boots = {name: lan for kind, name, _, lan in events[1:-1] if kind == "boot"}
|
|
144
|
+
assert boots == {
|
|
145
|
+
"ws": ("net1", ["vf-workspace"]),
|
|
146
|
+
"ws-vf-tool-0": ("net1", ["vf-tool-0"]),
|
|
147
|
+
"ws-vf-tool-1": ("net1", ["vf-tool-1"]),
|
|
148
|
+
}
|
|
149
|
+
assert events[-1] == "network deleted"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_a_tool_vm_keeps_only_its_state_channel_and_the_harness_its_routes():
|
|
153
|
+
applied = []
|
|
154
|
+
|
|
155
|
+
def backend(name):
|
|
156
|
+
async def prepare_execution(routes):
|
|
157
|
+
applied.append((name, routes))
|
|
158
|
+
|
|
159
|
+
def host_url(url):
|
|
160
|
+
return url.replace("http://127.0.0.1:9000", "https://tunnel.example")
|
|
161
|
+
|
|
162
|
+
return SimpleNamespace(prepare_execution=prepare_execution, host_url=host_url)
|
|
163
|
+
|
|
164
|
+
strategy = _PrivateNetworkDeployment()
|
|
165
|
+
strategy._service_backends = [backend("forth")]
|
|
166
|
+
deployment = SimpleNamespace(harness_backend=backend("main"))
|
|
167
|
+
# The harness reaches the model and a remote tool server; the tool VM needs neither.
|
|
168
|
+
routes = ["https://tunnel.example/v1", "https://tools.example/mcp"]
|
|
169
|
+
asyncio.run(
|
|
170
|
+
strategy.prepare_execution(
|
|
171
|
+
deployment, routes, state_route="http://127.0.0.1:9000/state"
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
assert sorted(applied) == [
|
|
175
|
+
("forth", ["https://tunnel.example/state"]),
|
|
176
|
+
("main", routes),
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_the_workspace_stops_before_tool_evidence_and_is_released_regardless():
|
|
181
|
+
events = []
|
|
182
|
+
|
|
183
|
+
async def stop():
|
|
184
|
+
events.append("workspace stopped")
|
|
185
|
+
|
|
186
|
+
async def aclose():
|
|
187
|
+
events.append("tool VMs released")
|
|
188
|
+
raise RuntimeError("network deletion failed")
|
|
189
|
+
|
|
190
|
+
strategy = _PrivateNetworkDeployment()
|
|
191
|
+
strategy._services = SimpleNamespace(aclose=aclose)
|
|
192
|
+
deployment = SimpleNamespace(execution_backend=SimpleNamespace(stop=stop))
|
|
193
|
+
|
|
194
|
+
# As Compose stops its workspace, before finalize_services reads the targets.
|
|
195
|
+
asyncio.run(strategy.stop_execution(deployment))
|
|
196
|
+
assert events == ["workspace stopped"]
|
|
197
|
+
|
|
198
|
+
# A failed tool VM or network release neither skips the workspace's nor raises.
|
|
199
|
+
events.clear()
|
|
200
|
+
asyncio.run(strategy.prepare_verifier(deployment))
|
|
201
|
+
assert events == ["workspace stopped", "tool VMs released"]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def served_url(monkeypatch, server, **kwargs):
|
|
205
|
+
async def serve_in_runtime(server, runtime, **options):
|
|
206
|
+
assert options["listen_all"]
|
|
207
|
+
return 1234
|
|
208
|
+
|
|
209
|
+
monkeypatch.setattr(launch, "serve_in_runtime", serve_in_runtime)
|
|
210
|
+
|
|
211
|
+
async def url():
|
|
212
|
+
async with launch._serve(server, **kwargs) as served:
|
|
213
|
+
return served.url
|
|
214
|
+
|
|
215
|
+
return asyncio.run(url())
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_a_tool_server_on_its_own_vm_is_reached_by_its_lan_name(monkeypatch):
|
|
219
|
+
runtime = SimpleNamespace(is_local=False, host_url=lambda url: url)
|
|
220
|
+
# Its restricted runtime is enforced on its own VM, so it is not refused.
|
|
221
|
+
server = toolset("forth", runtime=FORTH)
|
|
222
|
+
assert (
|
|
223
|
+
served_url(
|
|
224
|
+
monkeypatch,
|
|
225
|
+
server,
|
|
226
|
+
hosts={"forth": "sb1.sandbox.internal"},
|
|
227
|
+
placements={"forth": runtime},
|
|
228
|
+
)
|
|
229
|
+
== "http://sb1.sandbox.internal:1234/mcp"
|
|
230
|
+
)
|
|
231
|
+
# A Compose service keeps its name.
|
|
232
|
+
compose = toolset("echo", service="tools")
|
|
233
|
+
assert served_url(monkeypatch, compose, services={"tools": runtime}) == (
|
|
234
|
+
"http://tools:1234/mcp"
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@pytest.mark.parametrize("service", ["main", "forth"])
|
|
239
|
+
def test_an_explicit_service_names_only_a_compose_service(monkeypatch, service):
|
|
240
|
+
# The workspace and another server's VM are deployment targets, not services.
|
|
241
|
+
runtime = SimpleNamespace(is_local=False, host_url=lambda url: url)
|
|
242
|
+
with pytest.raises(ToolsetError, match="Compose services define it"):
|
|
243
|
+
served_url(
|
|
244
|
+
monkeypatch,
|
|
245
|
+
toolset("echo", service=service),
|
|
246
|
+
services={},
|
|
247
|
+
hosts={"forth": "sb1.sandbox.internal"},
|
|
248
|
+
placements={"forth": runtime},
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def test_a_restricted_runtime_without_a_private_network_is_refused(monkeypatch):
|
|
253
|
+
with pytest.raises(ToolsetError, match="joins the rollout's private network"):
|
|
254
|
+
served_url(monkeypatch, toolset("forth", runtime=FORTH))
|
|
@@ -31,11 +31,14 @@ from verifiers.v1.cli.resolve import (
|
|
|
31
31
|
from verifiers.v1.cli.resume import distribute
|
|
32
32
|
from verifiers.v1.configs.cli.validate import ValidateConfig
|
|
33
33
|
from verifiers.v1.errors import TaskError, boundary
|
|
34
|
+
from verifiers.v1.grading import bind_scoring_env, grade_task, verifier_runtime
|
|
34
35
|
from verifiers.v1.runtimes import make_backend
|
|
36
|
+
from verifiers.v1.runtimes.deployment import Deployment
|
|
35
37
|
from verifiers.v1.state import state_cls
|
|
36
38
|
from verifiers.v1.task import Task
|
|
37
39
|
from verifiers.v1.trace import Trace, TraceTask
|
|
38
40
|
from verifiers.v1.utils.aio import run_shielded
|
|
41
|
+
from verifiers.v1.utils.artifacts import collect
|
|
39
42
|
from verifiers.v1.utils.compile import resolve_runtime_config
|
|
40
43
|
from verifiers.v1.utils.decorators import invoke
|
|
41
44
|
from verifiers.v1.utils.interrupt import install_interrupt
|
|
@@ -244,17 +247,48 @@ async def _gold(task: Task, trace: Trace, runtime) -> bool | None:
|
|
|
244
247
|
return await task.validate(runtime)
|
|
245
248
|
|
|
246
249
|
|
|
247
|
-
async def _score_untouched(
|
|
250
|
+
async def _score_untouched(
|
|
251
|
+
task: Task, trace: Trace, runtime, deployment: Deployment, config: ValidateConfig
|
|
252
|
+
) -> bool | None:
|
|
248
253
|
"""Finalize and score the freshly set-up task exactly as a rollout would, with no
|
|
249
254
|
agent turn in between. Valid iff it does not already pass; `None` when the task
|
|
250
255
|
declares no reward to check."""
|
|
256
|
+
policy = task.scoring
|
|
257
|
+
isolated = policy.mode == "isolated"
|
|
258
|
+
grader = task.grading_task(runtime, scoring=policy)
|
|
259
|
+
grading_config = (
|
|
260
|
+
verifier_runtime(grader, runtime, config.runtime, policy) if isolated else None
|
|
261
|
+
)
|
|
262
|
+
if not isolated and policy.runtime is not None:
|
|
263
|
+
raise TaskError("verifier runtime overrides require isolated verification")
|
|
251
264
|
async with (
|
|
252
265
|
asyncio.timeout(task.data.timeout.finalize),
|
|
253
266
|
boundary(TaskError, "task finalize"),
|
|
254
267
|
):
|
|
255
|
-
await invoke(
|
|
256
|
-
|
|
257
|
-
|
|
268
|
+
await invoke(
|
|
269
|
+
task.finalize,
|
|
270
|
+
{"trace": trace, "runtime": runtime, "deployment": deployment},
|
|
271
|
+
)
|
|
272
|
+
if isolated:
|
|
273
|
+
if not trace.state.artifacts:
|
|
274
|
+
trace.state.artifacts = await collect(
|
|
275
|
+
runtime, task.data.artifacts, max_bytes=task.data.artifact_max_bytes
|
|
276
|
+
)
|
|
277
|
+
await deployment.stop_execution()
|
|
278
|
+
await task.finalize_services(
|
|
279
|
+
trace,
|
|
280
|
+
{name: deployment.target(name) for name in deployment.target_backends},
|
|
281
|
+
)
|
|
282
|
+
if isolated:
|
|
283
|
+
timeouts = task.data.timeout
|
|
284
|
+
if config.timeout.setup is not None:
|
|
285
|
+
timeouts = timeouts.model_copy(update={"setup": config.timeout.setup})
|
|
286
|
+
await grade_task(grader, trace, grading_config, timeouts, policy, deployment)
|
|
287
|
+
else:
|
|
288
|
+
async with asyncio.timeout(task.data.timeout.scoring):
|
|
289
|
+
runtime = bind_scoring_env(runtime, policy)
|
|
290
|
+
await invoke(grader.stage_verifier, {"trace": trace, "runtime": runtime})
|
|
291
|
+
await grader.score(trace, runtime, deployment)
|
|
258
292
|
if not trace.rewards:
|
|
259
293
|
return None
|
|
260
294
|
return trace.reward < SOLVED
|
|
@@ -278,8 +312,13 @@ async def _run_check(task: Task, config: ValidateConfig, mode: str) -> ResultRow
|
|
|
278
312
|
valid: bool | None = False
|
|
279
313
|
exc = None
|
|
280
314
|
trace: Trace | None = None
|
|
315
|
+
deployment: Deployment | None = None
|
|
281
316
|
try:
|
|
282
|
-
|
|
317
|
+
deployment = backend.deploy(
|
|
318
|
+
spec=task.deployment_spec(),
|
|
319
|
+
env=task.runtime_env(),
|
|
320
|
+
config=config.deployment,
|
|
321
|
+
)
|
|
283
322
|
trace = Trace(
|
|
284
323
|
task=TraceTask(
|
|
285
324
|
type=type(task).__name__, data=task.data, key=task.key, hash=task.hash
|
|
@@ -292,20 +331,37 @@ async def _run_check(task: Task, config: ValidateConfig, mode: str) -> ResultRow
|
|
|
292
331
|
trainable=False,
|
|
293
332
|
),
|
|
294
333
|
)
|
|
295
|
-
await
|
|
296
|
-
runtime =
|
|
334
|
+
await deployment.start()
|
|
335
|
+
runtime = deployment.workspace
|
|
336
|
+
await runtime.backend.prepare_setup()
|
|
297
337
|
await asyncio.wait_for(
|
|
298
|
-
invoke(
|
|
338
|
+
invoke(
|
|
339
|
+
task.setup,
|
|
340
|
+
{"trace": trace, "runtime": runtime, "deployment": deployment},
|
|
341
|
+
),
|
|
299
342
|
setup_timeout,
|
|
300
343
|
)
|
|
301
344
|
valid = await asyncio.wait_for(
|
|
302
|
-
|
|
345
|
+
invoke(
|
|
346
|
+
CHECKS[mode],
|
|
347
|
+
{
|
|
348
|
+
"task": task,
|
|
349
|
+
"trace": trace,
|
|
350
|
+
"runtime": runtime,
|
|
351
|
+
"deployment": deployment,
|
|
352
|
+
"config": config,
|
|
353
|
+
},
|
|
354
|
+
),
|
|
355
|
+
config.timeout.total,
|
|
303
356
|
)
|
|
304
357
|
except Exception as e: # noqa: BLE001 - validation reports plugin failures per task
|
|
305
358
|
exc = e
|
|
306
359
|
finally:
|
|
307
360
|
try:
|
|
308
|
-
|
|
361
|
+
if deployment is not None:
|
|
362
|
+
await deployment.close()
|
|
363
|
+
else:
|
|
364
|
+
await backend.stop()
|
|
309
365
|
except Exception:
|
|
310
366
|
logger.warning(
|
|
311
367
|
"runtime teardown failed (task %s)", task.data.idx, exc_info=True
|
|
@@ -10,6 +10,7 @@ from verifiers.v1.configs.cli.eval import RunConfig
|
|
|
10
10
|
from verifiers.v1.configs.select import SelectCLIConfig
|
|
11
11
|
from verifiers.v1.configs.taskset import TasksetConfig
|
|
12
12
|
from verifiers.v1.runtimes import PrimeConfig, RuntimeConfig
|
|
13
|
+
from verifiers.v1.runtimes.deployment import DeploymentConfig
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class CheckTimeoutConfig(BaseConfig):
|
|
@@ -30,6 +31,8 @@ class ValidateConfig(BaseConfig):
|
|
|
30
31
|
`select.limit`, `-s` sets `select.shuffle`)."""
|
|
31
32
|
runtime: RuntimeConfig = PrimeConfig()
|
|
32
33
|
"""Where each task's validation hooks run."""
|
|
34
|
+
deployment: DeploymentConfig = DeploymentConfig()
|
|
35
|
+
"""Task service deployment, including local Compose trust."""
|
|
33
36
|
timeout: CheckTimeoutConfig = CheckTimeoutConfig()
|
|
34
37
|
only_setup: bool = False
|
|
35
38
|
"""Run only the setup check: `Task.setup`."""
|