verifiers 0.4.1.dev41__tar.gz → 0.4.1.dev44__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.dev41 → verifiers-0.4.1.dev44}/PKG-INFO +2 -2
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/pyproject.toml +1 -1
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/conftest.py +4 -1
- verifiers-0.4.1.dev44/tests/integration/fixtures/fetch_tool_v1.py +36 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/pyproject.toml +1 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/grid.py +7 -1
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_shared_tool.py +1 -1
- verifiers-0.4.1.dev44/tests/integration/test_tool_vms.py +88 -0
- verifiers-0.4.1.dev44/tests/unit/runtimes/test_private_network.py +254 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/clients/train.py +4 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/graph.py +6 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/mcp/launch.py +28 -9
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/mcp/toolset.py +3 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/rollout.py +25 -6
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/deployment.py +19 -5
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/prime.py +43 -16
- verifiers-0.4.1.dev44/verifiers/v1/runtimes/private_network.py +148 -0
- verifiers-0.4.1.dev44/verifiers/v1/runtimes/strategies.py +119 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/types.py +11 -0
- verifiers-0.4.1.dev41/verifiers/v1/runtimes/strategies.py +0 -64
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/.gitignore +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/LICENSE +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/README.md +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/agent_user_harness_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/agent_user_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/duet_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/echo_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/network_policy_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/skill_codeword_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_agent_user.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_agentic_judge.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_compose_scoring.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_examples.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_limits.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_multi_agent.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_multi_turn.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_multi_turn_tool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_multimodal_tool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_network_policy.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_resume_tool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_rubric_judge.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_sampling.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_single_turn.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_skills.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_stateful_tool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_user_echo.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/integration/test_user_sim.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/cli/test_replay.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/conftest.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/harnesses/test_core.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/harnesses/test_rlm.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/interception/test_tunnel.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/judges/conftest.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/judges/test_judge.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/judges/test_reference.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/judges/test_rubric.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/runtimes/test_e2b.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/serve/test_client.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/serve/test_delta.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/serve/test_pool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_agent.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_dialects.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_graph.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_semantic.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_task.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/test_trace.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/utils/test_compile.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/utils/test_loaders.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/utils/test_platform.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/tests/unit/utils/test_score.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/acp/runner.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/agent.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/dashboard/eval.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/debug.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/eval/hint.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/eval/main.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/eval/runner.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/gepa.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/replay.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/resume.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/cli/validate.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/clients/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/agent.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/eval.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/cli/validate.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/client.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/runtime.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/scoring.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/select.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/episode.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/errors.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/grading.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/bash/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/browser_use/program.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/node.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/null/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/opencode/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/rlm/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/compaction.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/core.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/install.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/launch.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/mcp.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/harnesses/utils/replay.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/server.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/interception/tunnel/prime.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judge.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/decision.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/apptainer.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/compose.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/container.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/e2b.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/limiters.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/modal.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/runtime.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/semantic.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/client.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/delta.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/encoding.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/pool.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/server.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/serve/types.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/session.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/state.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/task.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/trace.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/artifacts.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/decorators.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/env.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/eval.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/loaders.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/paths.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/platform.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/prime.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/retries.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/scope.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/score.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/verifiers/v1/utils/trace_store.py +0 -0
- {verifiers-0.4.1.dev41 → verifiers-0.4.1.dev44}/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.dev44
|
|
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))
|
|
@@ -30,6 +30,7 @@ from verifiers.v1.types import (
|
|
|
30
30
|
ToolCall,
|
|
31
31
|
TurnTokens,
|
|
32
32
|
Usage,
|
|
33
|
+
WeightVersionSpan,
|
|
33
34
|
)
|
|
34
35
|
|
|
35
36
|
logger = logging.getLogger(__name__)
|
|
@@ -181,6 +182,9 @@ def response_from_generate(
|
|
|
181
182
|
sampling_mask=SamplingMask.from_sampling_mask(mask)
|
|
182
183
|
if (mask := result.get("sampling_mask"))
|
|
183
184
|
else None,
|
|
185
|
+
weight_versions=[WeightVersionSpan(**span) for span in spans]
|
|
186
|
+
if (spans := result.get("weight_versions"))
|
|
187
|
+
else None,
|
|
184
188
|
),
|
|
185
189
|
)
|
|
186
190
|
|
|
@@ -49,6 +49,7 @@ from verifiers.v1.types import (
|
|
|
49
49
|
TextContentPart,
|
|
50
50
|
Tool,
|
|
51
51
|
ToolMessage,
|
|
52
|
+
WeightVersionSpan,
|
|
52
53
|
)
|
|
53
54
|
|
|
54
55
|
if TYPE_CHECKING:
|
|
@@ -164,6 +165,10 @@ class MessageNode(BaseModel):
|
|
|
164
165
|
`ids` stores the flat token ids and `counts` stores each token's row size. Assistant
|
|
165
166
|
nodes only. The arrays serialize as raw-byte `__nd__` dictionaries.
|
|
166
167
|
"""
|
|
168
|
+
weight_versions: list[WeightVersionSpan] | None = None
|
|
169
|
+
"""Engine weight-version spans over this node's sampled tokens (indexes into the
|
|
170
|
+
completion, as vLLM returns them). Assistant nodes only; None when the engine labels
|
|
171
|
+
none."""
|
|
167
172
|
|
|
168
173
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
169
174
|
|
|
@@ -997,6 +1002,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
|
|
|
997
1002
|
else [],
|
|
998
1003
|
# TurnTokens is discarded after commit, so transfer its logprobs without copying.
|
|
999
1004
|
logprobs=tokens.completion_logprobs if tokens else [],
|
|
1005
|
+
weight_versions=tokens.weight_versions if tokens else None,
|
|
1000
1006
|
)
|
|
1001
1007
|
)
|
|
1002
1008
|
assistant_id = len(trace.nodes) - 1
|
|
@@ -434,17 +434,27 @@ async def _serve(
|
|
|
434
434
|
state_secret: str = "",
|
|
435
435
|
state_base: str | None = None,
|
|
436
436
|
services: Mapping[str, Runtime] | None = None,
|
|
437
|
+
hosts: Mapping[str, str] | None = None,
|
|
438
|
+
placements: Mapping[str, Runtime] | None = None,
|
|
437
439
|
):
|
|
438
440
|
cfg = server.config
|
|
439
441
|
colocated = getattr(cfg, "colocated", False)
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
442
|
+
service = getattr(cfg, "service", None)
|
|
443
|
+
own_vm = (placements or {}).get(server.server_name)
|
|
444
|
+
if service is not None or own_vm is not None:
|
|
445
|
+
# The harness reaches the server over the deployment's network: a Compose
|
|
446
|
+
# service by its name, a VM of its own by its LAN name.
|
|
447
|
+
if own_vm is not None:
|
|
448
|
+
runtime = own_vm
|
|
449
|
+
host = (hosts or {})[server.server_name]
|
|
450
|
+
elif services is None or service not in services:
|
|
443
451
|
raise ToolsetError(
|
|
444
|
-
f"server {server.server_name!r} runs in
|
|
452
|
+
f"server {server.server_name!r} runs in service {service!r}, "
|
|
445
453
|
"which needs a task whose Compose services define it"
|
|
446
454
|
)
|
|
447
|
-
|
|
455
|
+
else:
|
|
456
|
+
runtime = services[service]
|
|
457
|
+
host = (hosts or {}).get(service, service)
|
|
448
458
|
if runtime.is_local:
|
|
449
459
|
# A local service cannot reach the host-loopback state channel.
|
|
450
460
|
raise ToolsetError(
|
|
@@ -463,7 +473,7 @@ async def _serve(
|
|
|
463
473
|
),
|
|
464
474
|
state_secret=state_secret,
|
|
465
475
|
)
|
|
466
|
-
yield _ServedServer(f"http://{
|
|
476
|
+
yield _ServedServer(f"http://{host}:{port}/mcp", runtime)
|
|
467
477
|
return
|
|
468
478
|
async with contextlib.AsyncExitStack() as stack:
|
|
469
479
|
# Colocated servers inherit the harness cut. A separately provisioned filtered
|
|
@@ -475,9 +485,10 @@ async def _serve(
|
|
|
475
485
|
and not (colocated and harness_runtime is not None)
|
|
476
486
|
):
|
|
477
487
|
raise ToolsetError(
|
|
478
|
-
"
|
|
479
|
-
|
|
480
|
-
"
|
|
488
|
+
f"server {server.server_name!r} restricts its runtime's network, which "
|
|
489
|
+
"needs the server colocated with the harness, or on a Prime runtime "
|
|
490
|
+
"of its own beside a Prime workspace without Compose services (it then "
|
|
491
|
+
"joins the rollout's private network)"
|
|
481
492
|
)
|
|
482
493
|
if colocated and harness_runtime is not None:
|
|
483
494
|
runtime = harness_runtime
|
|
@@ -532,6 +543,8 @@ async def serve(
|
|
|
532
543
|
state_secret: str = "",
|
|
533
544
|
state_base: str | None = None,
|
|
534
545
|
services: Mapping[str, Runtime] | None = None,
|
|
546
|
+
hosts: Mapping[str, str] | None = None,
|
|
547
|
+
placements: Mapping[str, Runtime] | None = None,
|
|
535
548
|
):
|
|
536
549
|
"""Serve one MCP server and yield the URL visible to its consumer."""
|
|
537
550
|
async with _serve(
|
|
@@ -541,6 +554,8 @@ async def serve(
|
|
|
541
554
|
state_secret=state_secret,
|
|
542
555
|
state_base=state_base,
|
|
543
556
|
services=services,
|
|
557
|
+
hosts=hosts,
|
|
558
|
+
placements=placements,
|
|
544
559
|
) as served:
|
|
545
560
|
yield served.url
|
|
546
561
|
|
|
@@ -649,6 +664,8 @@ async def serve_tools(
|
|
|
649
664
|
state_route: str = "",
|
|
650
665
|
state_base: str | None = None,
|
|
651
666
|
services: Mapping[str, Runtime] | None = None,
|
|
667
|
+
hosts: Mapping[str, str] | None = None,
|
|
668
|
+
placements: Mapping[str, Runtime] | None = None,
|
|
652
669
|
):
|
|
653
670
|
"""Bring up a rollout's tool servers and yield `{name: url}` the harness reaches: the
|
|
654
671
|
task-scoped `toolsets` are launched by `serve` (placement off each one's `config`; the
|
|
@@ -690,6 +707,8 @@ async def serve_tools(
|
|
|
690
707
|
state_secret=state_secret,
|
|
691
708
|
state_base=state_base,
|
|
692
709
|
services=services,
|
|
710
|
+
hosts=hosts,
|
|
711
|
+
placements=placements,
|
|
693
712
|
)
|
|
694
713
|
)
|
|
695
714
|
logger.info("tool server '%s': %s", name, urls[name])
|
|
@@ -17,6 +17,9 @@ if TYPE_CHECKING:
|
|
|
17
17
|
class ToolsetConfig(BaseConfig):
|
|
18
18
|
colocated: bool = False
|
|
19
19
|
runtime: RuntimeConfig = SubprocessConfig()
|
|
20
|
+
"""Where the server runs: the evaluator by default. A Prime runtime beside a Prime
|
|
21
|
+
workspace without Compose services is a VM of the server's own that joins the
|
|
22
|
+
workspace over the rollout's private network, under its own egress policy."""
|
|
20
23
|
url: str | None = None
|
|
21
24
|
service: str | None = None
|
|
22
25
|
"""Run the server in this service of the task's Compose services (on a Prime or
|