verifiers 0.3.2.dev128__tar.gz → 0.3.2.dev130__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/PKG-INFO +1 -1
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/debug.py +4 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/eval/runner.py +3 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/gepa.py +4 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/replay.py +4 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/validate.py +4 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/tunnel/prime.py +10 -6
- verifiers-0.3.2.dev130/verifiers/v1/runtimes/limiters.py +71 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/modal.py +5 -2
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/prime.py +6 -3
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/harbor/taskset.py +52 -39
- verifiers-0.3.2.dev130/verifiers/v1/utils/scope.py +27 -0
- verifiers-0.3.2.dev128/verifiers/v1/runtimes/limiters.py +0 -79
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/.gitignore +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/LICENSE +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/README.md +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/pyproject.toml +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/conftest.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/duet_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/echo_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/pyproject.toml +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_color_codeword_tasks.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_configs.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_e2e.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_envs.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_graph.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_judges.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_platform_run.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_scoring.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_serve_delta.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/test_trace.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/acp/runner.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/agent.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/dashboard/eval.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/eval/hint.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/eval/main.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/init.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/cli/resume.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/clients/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/clients/train.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/agent.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/eval.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/init.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/cli/validate.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/client.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/runtime.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/isolated_verifier/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/isolated_verifier/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/shared_agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/episode.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/errors.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/graph.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/bash/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/browser_use/program.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/node.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/null/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/rlm/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/compaction.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/core.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/install.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/launch.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/harnesses/utils/mcp.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/server.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judge.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/mcp/launch.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/mcp/toolset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/rollout.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/apptainer.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/container.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/semantic.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/client.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/delta.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/encoding.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/pool.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/server.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/serve/types.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/session.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/state.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/task.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/harbor/env.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/trace.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/types.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/artifacts.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/decorators.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/loaders.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/paths.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/platform.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/prime.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/retries.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/score.py +0 -0
- {verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/verifiers/v1/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev130
|
|
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
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import contextlib
|
|
5
5
|
import logging
|
|
6
|
+
import os
|
|
6
7
|
import shlex
|
|
7
8
|
import sys
|
|
8
9
|
import time
|
|
9
10
|
import traceback
|
|
11
|
+
import uuid
|
|
10
12
|
from collections.abc import Awaitable
|
|
11
13
|
from pathlib import Path
|
|
12
14
|
from typing import Any
|
|
@@ -316,6 +318,8 @@ async def run_debug(config: DebugConfig) -> list[Trace]:
|
|
|
316
318
|
|
|
317
319
|
|
|
318
320
|
def main(argv: list[str] | None = None) -> None:
|
|
321
|
+
# The run identity: every process this run spawns inherits it.
|
|
322
|
+
os.environ.setdefault("VF_RUN_ID", uuid.uuid4().hex)
|
|
319
323
|
argv = with_positional_taskset(
|
|
320
324
|
list(sys.argv[1:]) if argv is None else list(argv), flag="--taskset.id"
|
|
321
325
|
)
|
|
@@ -9,6 +9,7 @@ runs env servers); this CLI is the quick local path.
|
|
|
9
9
|
import asyncio
|
|
10
10
|
import contextlib
|
|
11
11
|
import logging
|
|
12
|
+
import os
|
|
12
13
|
import time
|
|
13
14
|
from collections.abc import AsyncIterator, Awaitable, Callable, Iterable
|
|
14
15
|
from typing import TypeVar, cast
|
|
@@ -139,6 +140,8 @@ async def run_eval(config: EvalConfig) -> list[Episode]:
|
|
|
139
140
|
|
|
140
141
|
# Opened before the first rollout so every episode streams as it lands.
|
|
141
142
|
run = open_run(config, push_state, num_examples=len(tasks))
|
|
143
|
+
# The run identity: every process this run spawns inherits it.
|
|
144
|
+
os.environ.setdefault("VF_RUN_ID", config.run.id)
|
|
142
145
|
# Resumed rollouts are part of this run too.
|
|
143
146
|
log_episodes(run, finished)
|
|
144
147
|
|
|
@@ -9,7 +9,9 @@ and the actual parse is `pydantic_config.cli`.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
|
+
import os
|
|
12
13
|
import sys
|
|
14
|
+
import uuid
|
|
13
15
|
|
|
14
16
|
from pydantic_config import cli
|
|
15
17
|
|
|
@@ -32,6 +34,8 @@ USAGE = "usage: uv run vf-gepa [<taskset-id>] [--env.id <id>] --model <model> [o
|
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
def main(argv: list[str] | None = None) -> None:
|
|
37
|
+
# The run identity: every process this run spawns inherits it.
|
|
38
|
+
os.environ.setdefault("VF_RUN_ID", uuid.uuid4().hex)
|
|
35
39
|
argv = with_positional_taskset(list(sys.argv[1:]) if argv is None else list(argv))
|
|
36
40
|
|
|
37
41
|
if not argv or any(arg in ("-h", "--help") for arg in argv):
|
|
@@ -12,8 +12,10 @@ import asyncio
|
|
|
12
12
|
import contextlib
|
|
13
13
|
import json
|
|
14
14
|
import logging
|
|
15
|
+
import os
|
|
15
16
|
import sys
|
|
16
17
|
import time
|
|
18
|
+
import uuid
|
|
17
19
|
from pathlib import Path
|
|
18
20
|
|
|
19
21
|
from pydantic_config import cli
|
|
@@ -197,6 +199,8 @@ async def run_replay(config: ReplayConfig, source: Path, out: Path) -> list[Trac
|
|
|
197
199
|
|
|
198
200
|
|
|
199
201
|
def main(argv: list[str] | None = None) -> None:
|
|
202
|
+
# The run identity: every process this run spawns inherits it.
|
|
203
|
+
os.environ.setdefault("VF_RUN_ID", uuid.uuid4().hex)
|
|
200
204
|
argv = list(sys.argv[1:]) if argv is None else list(argv)
|
|
201
205
|
if not argv or any(a in ("-h", "--help") for a in argv):
|
|
202
206
|
print(USAGE)
|
|
@@ -4,9 +4,11 @@ import asyncio
|
|
|
4
4
|
import contextlib
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
|
+
import os
|
|
7
8
|
import shutil
|
|
8
9
|
import sys
|
|
9
10
|
import time
|
|
11
|
+
import uuid
|
|
10
12
|
from collections import Counter, defaultdict
|
|
11
13
|
from collections.abc import Mapping, Sequence
|
|
12
14
|
from pathlib import Path
|
|
@@ -425,6 +427,8 @@ async def run_validate(config: ValidateConfig) -> list[dict]:
|
|
|
425
427
|
|
|
426
428
|
|
|
427
429
|
def main(argv: list[str] | None = None) -> None:
|
|
430
|
+
# The run identity: every process this run spawns inherits it.
|
|
431
|
+
os.environ.setdefault("VF_RUN_ID", uuid.uuid4().hex)
|
|
428
432
|
argv = with_positional_taskset(
|
|
429
433
|
list(sys.argv[1:]) if argv is None else list(argv), flag="--taskset.id"
|
|
430
434
|
)
|
|
@@ -9,15 +9,19 @@ from collections.abc import AsyncIterator
|
|
|
9
9
|
from typing import Literal
|
|
10
10
|
|
|
11
11
|
from verifiers.v1.interception.tunnel.base import BaseTunnelConfig, Tunnel
|
|
12
|
-
from verifiers.v1.runtimes.limiters import
|
|
12
|
+
from verifiers.v1.runtimes.limiters import CreationLimiter
|
|
13
13
|
from verifiers.v1.utils.aio import run_shielded
|
|
14
14
|
from verifiers.v1.utils.prime import ensure_prime_auth
|
|
15
|
+
from verifiers.v1.utils.scope import run_scope
|
|
15
16
|
|
|
16
17
|
# The prime_tunnel service caps tunnel starts at 512/min per API token — a property of the
|
|
17
|
-
# tunnel service, shared by every process
|
|
18
|
+
# tunnel service, shared by every process of a run that opens one. One run-scoped
|
|
18
19
|
# limiter, not a per-runtime config knob.
|
|
19
20
|
_TUNNELS_PER_MIN = 512
|
|
20
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def tunnel_limiter() -> CreationLimiter:
|
|
24
|
+
return CreationLimiter("prime-tunnel", run_scope(), _TUNNELS_PER_MIN / 60)
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class PrimeTunnelConfig(BaseTunnelConfig):
|
|
@@ -35,8 +39,8 @@ class PrimeTunnel(Tunnel[PrimeTunnelConfig]):
|
|
|
35
39
|
@contextlib.asynccontextmanager
|
|
36
40
|
async def expose(self, port: int) -> AsyncIterator[str]:
|
|
37
41
|
"""Bridge the host `port` to a public URL via prime_tunnel (frpc). Tunnel creation
|
|
38
|
-
is network-bound and
|
|
39
|
-
`
|
|
42
|
+
is network-bound and rate-capped (512/min, run-wide via the shared
|
|
43
|
+
`tunnel_limiter`), so transient failures are retried; a terminal one raises
|
|
40
44
|
`TunnelError`. The tunnel is torn down on exit."""
|
|
41
45
|
from prime_tunnel import Tunnel as TunnelClient
|
|
42
46
|
|
|
@@ -48,7 +52,7 @@ class PrimeTunnel(Tunnel[PrimeTunnelConfig]):
|
|
|
48
52
|
async for attempt in retrying(retries=3, label=label):
|
|
49
53
|
with attempt:
|
|
50
54
|
client = TunnelClient(local_port=port)
|
|
51
|
-
async with
|
|
55
|
+
async with tunnel_limiter():
|
|
52
56
|
url = str(await client.start()).rstrip("/")
|
|
53
57
|
except Exception as e:
|
|
54
58
|
raise TunnelError(f"{label} failed: {e}") from e
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Creation-rate limiters for the remote runtimes.
|
|
2
|
+
|
|
3
|
+
A leaky bucket backed by a lock file under the user cache (``~/.cache/verifiers``, falling
|
|
4
|
+
back to the temp dir when no home is resolvable), so a provider's creation rate (Modal
|
|
5
|
+
sandboxes, Prime sandboxes and tunnels) is enforced across EVERY process that shares the
|
|
6
|
+
bucket — the eval process and all the elastically-spawned env-server worker processes alike —
|
|
7
|
+
not just within one process. A bucket is named by the limiter's name and a scope the caller
|
|
8
|
+
picks; the runtimes pass the run id, so one run's backlog (or the reservations a killed run
|
|
9
|
+
left behind) never delays another run.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import fcntl
|
|
14
|
+
import os
|
|
15
|
+
import time
|
|
16
|
+
from typing import Self
|
|
17
|
+
|
|
18
|
+
from verifiers.v1.utils.paths import CACHE_DIR
|
|
19
|
+
|
|
20
|
+
LIMITER_DIR = CACHE_DIR / "limiter"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CreationLimiter:
|
|
24
|
+
"""An async leaky bucket shared across processes via a lock file: each `async with`
|
|
25
|
+
reserves the next `1/per_sec`-spaced slot (advancing the on-disk cursor under an exclusive
|
|
26
|
+
flock) and sleeps until it, so the aggregate creation rate across every process sharing
|
|
27
|
+
the bucket stays at `per_sec`. The reservation runs off the event loop; the wait does not
|
|
28
|
+
hold the lock. Reservations are never released, so a cancelled waiter still holds its
|
|
29
|
+
slot; the backlog drains at `per_sec` regardless."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, name: str, scope: str, per_sec: float) -> None:
|
|
32
|
+
self._interval = 1 / per_sec
|
|
33
|
+
self._path = LIMITER_DIR / f"{name}-{scope.replace('/', '--')}.bucket"
|
|
34
|
+
|
|
35
|
+
def _reserve(self) -> float:
|
|
36
|
+
os.makedirs(LIMITER_DIR, exist_ok=True)
|
|
37
|
+
# Shared buckets require a clock comparable across the run's hosts.
|
|
38
|
+
with open(self._path, "a+") as f:
|
|
39
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
|
|
40
|
+
try:
|
|
41
|
+
f.seek(0)
|
|
42
|
+
data = f.read().strip()
|
|
43
|
+
now = time.time()
|
|
44
|
+
slot = max(now, float(data) if data else 0.0)
|
|
45
|
+
f.seek(0)
|
|
46
|
+
f.truncate()
|
|
47
|
+
f.write(repr(slot + self._interval))
|
|
48
|
+
f.flush()
|
|
49
|
+
finally:
|
|
50
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
|
|
51
|
+
return slot - now
|
|
52
|
+
|
|
53
|
+
async def __aenter__(self) -> Self:
|
|
54
|
+
wait = await asyncio.to_thread(self._reserve)
|
|
55
|
+
if wait > 0:
|
|
56
|
+
await asyncio.sleep(wait)
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
async def __aexit__(self, *exc) -> bool:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def creation_limiter(
|
|
64
|
+
per_sec: float | None, name: str, scope: str
|
|
65
|
+
) -> CreationLimiter | None:
|
|
66
|
+
"""A limiter pacing `name`'s creation to `per_sec`/s within `scope` (None/<= 0
|
|
67
|
+
disables). All callers (and processes) sharing a name and scope share one bucket, so
|
|
68
|
+
use one rate per name."""
|
|
69
|
+
if not per_sec or per_sec <= 0:
|
|
70
|
+
return None
|
|
71
|
+
return CreationLimiter(name, scope, per_sec)
|
|
@@ -31,6 +31,7 @@ from verifiers.v1.runtimes.base import (
|
|
|
31
31
|
)
|
|
32
32
|
from verifiers.v1.runtimes.limiters import creation_limiter
|
|
33
33
|
from verifiers.v1.utils.aio import run_shielded
|
|
34
|
+
from verifiers.v1.utils.scope import run_scope
|
|
34
35
|
|
|
35
36
|
logger = logging.getLogger(__name__)
|
|
36
37
|
|
|
@@ -93,7 +94,7 @@ class ModalConfig(NetworkPolicyConfig):
|
|
|
93
94
|
"""Disk in GB. Modal sandboxes have no disk knob, so this is accepted (so a task can
|
|
94
95
|
declare it without a warning) but not enforced."""
|
|
95
96
|
creates_per_sec: float | None = 40.0
|
|
96
|
-
"""Pace sandbox creation to this many per second, enforced
|
|
97
|
+
"""Pace sandbox creation to this many per second, enforced run-wide across every
|
|
97
98
|
env-server worker process (None/<= 0 disables it)."""
|
|
98
99
|
|
|
99
100
|
@model_validator(mode="after")
|
|
@@ -181,7 +182,9 @@ class ModalRuntime(Runtime):
|
|
|
181
182
|
try:
|
|
182
183
|
app = await modal.App.lookup.aio(_APP_NAME, create_if_missing=True)
|
|
183
184
|
async with (
|
|
184
|
-
creation_limiter(
|
|
185
|
+
creation_limiter(
|
|
186
|
+
self.config.creates_per_sec, "modal-sandbox", run_scope()
|
|
187
|
+
)
|
|
185
188
|
or contextlib.nullcontext()
|
|
186
189
|
):
|
|
187
190
|
await run_shielded(self._create_sandbox(app))
|
|
@@ -28,6 +28,7 @@ from verifiers.v1.runtimes.base import (
|
|
|
28
28
|
from verifiers.v1.runtimes.limiters import creation_limiter
|
|
29
29
|
from verifiers.v1.utils.aio import run_shielded
|
|
30
30
|
from verifiers.v1.utils.prime import ensure_prime_auth
|
|
31
|
+
from verifiers.v1.utils.scope import run_scope
|
|
31
32
|
|
|
32
33
|
logger = logging.getLogger(__name__)
|
|
33
34
|
|
|
@@ -87,9 +88,9 @@ class PrimeConfig(NetworkPolicyConfig):
|
|
|
87
88
|
idle_timeout: float | None = 3600
|
|
88
89
|
"""Seconds of inactivity before the sandbox self-deletes (None disables)."""
|
|
89
90
|
creates_per_min: int | None = None
|
|
90
|
-
"""Pace sandbox creation to this many per minute, enforced
|
|
91
|
+
"""Pace sandbox creation to this many per minute, enforced run-wide across every
|
|
91
92
|
env-server worker process (None/<= 0 disables it). (Tunnel creation is limited separately
|
|
92
|
-
|
|
93
|
+
— see interception.tunnel.prime.tunnel_limiter.)"""
|
|
93
94
|
|
|
94
95
|
@model_validator(mode="after")
|
|
95
96
|
def _validate_egress(self) -> "PrimeConfig":
|
|
@@ -175,7 +176,9 @@ class PrimeRuntime(Runtime):
|
|
|
175
176
|
try:
|
|
176
177
|
async with (
|
|
177
178
|
creation_limiter(
|
|
178
|
-
(self.config.creates_per_min or 0) / 60,
|
|
179
|
+
(self.config.creates_per_min or 0) / 60,
|
|
180
|
+
"prime-sandbox",
|
|
181
|
+
run_scope(),
|
|
179
182
|
)
|
|
180
183
|
or contextlib.nullcontext()
|
|
181
184
|
):
|
|
@@ -121,9 +121,6 @@ class VerifierConfig(BaseModel):
|
|
|
121
121
|
`None` on `HarborData` means shared — grade where the agent worked, which is still
|
|
122
122
|
Harbor's default and every task that says nothing."""
|
|
123
123
|
|
|
124
|
-
image: str | None = None
|
|
125
|
-
"""Pullable ref from `[verifier.environment].docker_image`. None keeps the task's
|
|
126
|
-
own image, which is what Harbor's fresh copy of `[environment]` resolves to."""
|
|
127
124
|
resources: TaskResources = TaskResources()
|
|
128
125
|
workdir: str | None = None
|
|
129
126
|
env: dict[str, str] = Field(default_factory=dict)
|
|
@@ -159,6 +156,9 @@ class HarborData(TaskData):
|
|
|
159
156
|
healthcheck: dict | None = None
|
|
160
157
|
mcp_servers: list[dict] = Field(default_factory=list)
|
|
161
158
|
"""Task-declared MCP servers, preserved for served-task reconstruction."""
|
|
159
|
+
verifier_image: str | None = None
|
|
160
|
+
"""Pullable image for a separate verifier, containing the complete `/tests` suite.
|
|
161
|
+
None keeps the solver image and stages the task package's tests."""
|
|
162
162
|
verifier_env: dict[str, str] = Field(default_factory=dict)
|
|
163
163
|
"""Raw [verifier.env] entries (literals or `${VAR}`/`${VAR:-default}` templates).
|
|
164
164
|
Resolved against the host environment at scoring time, like `harbor run` — so a
|
|
@@ -297,7 +297,7 @@ class HarborTask(Task[HarborData, State, HarborTaskConfig]):
|
|
|
297
297
|
# Harbor's dedicated verifier image owns the complete test suite and its
|
|
298
298
|
# dependencies. Mixing it with packaged tests can retain obsolete helpers.
|
|
299
299
|
stage = "test -f /tests/test.sh"
|
|
300
|
-
if self.data.verifier is None or self.data.
|
|
300
|
+
if self.data.verifier is None or self.data.verifier_image is None:
|
|
301
301
|
await runtime.write(
|
|
302
302
|
"/tmp/tests.tgz", make_tar(Path(self.data.task_dir) / "tests")
|
|
303
303
|
)
|
|
@@ -391,10 +391,14 @@ def verifier_box_data(data: HarborData) -> HarborData:
|
|
|
391
391
|
return data.model_copy(
|
|
392
392
|
update={
|
|
393
393
|
"name": f"{data.name} (verifier)",
|
|
394
|
-
"image":
|
|
394
|
+
"image": data.verifier_image
|
|
395
|
+
if data.verifier_image is not None
|
|
396
|
+
else data.image,
|
|
395
397
|
"workdir": data.workdir if fresh else verifier.workdir,
|
|
396
398
|
"resources": data.resources if fresh else verifier.resources,
|
|
397
|
-
"upload_environment": data.upload_environment
|
|
399
|
+
"upload_environment": data.upload_environment
|
|
400
|
+
if fresh and data.verifier_image is None
|
|
401
|
+
else False,
|
|
398
402
|
"env": dict(verifier.env),
|
|
399
403
|
"healthcheck": verifier.healthcheck,
|
|
400
404
|
"skills": [],
|
|
@@ -524,27 +528,41 @@ def resolve_image(
|
|
|
524
528
|
image: str | None,
|
|
525
529
|
require_image: bool,
|
|
526
530
|
ignore_dockerfile: bool = False,
|
|
531
|
+
*,
|
|
532
|
+
verifier: bool = False,
|
|
527
533
|
) -> str | None:
|
|
528
534
|
"""Choose a pullable image without silently ignoring a declared Dockerfile.
|
|
529
535
|
|
|
530
|
-
``None``
|
|
531
|
-
|
|
532
|
-
|
|
536
|
+
``None`` keeps the harness image for the solver, or the solver image for a
|
|
537
|
+
separate verifier. A declared verifier environment without an image implies
|
|
538
|
+
a build from tests/Dockerfile, even if that file is absent.
|
|
533
539
|
"""
|
|
534
540
|
if image:
|
|
535
541
|
return image
|
|
536
|
-
|
|
542
|
+
section = "verifier.environment" if verifier else "environment"
|
|
543
|
+
dockerfile = "tests/Dockerfile" if verifier else "environment/Dockerfile"
|
|
544
|
+
if verifier or (task_dir / dockerfile).exists():
|
|
537
545
|
if ignore_dockerfile:
|
|
546
|
+
if verifier:
|
|
547
|
+
logger.warning(
|
|
548
|
+
"%s: [%s] names no docker_image — grading in the agent's "
|
|
549
|
+
"image rather than building %s, so the verifier runs somewhere "
|
|
550
|
+
"the task never declared",
|
|
551
|
+
task_dir.name,
|
|
552
|
+
section,
|
|
553
|
+
dockerfile,
|
|
554
|
+
)
|
|
538
555
|
return None
|
|
539
556
|
raise ValueError(
|
|
540
|
-
f"{task_dir.name}:
|
|
541
|
-
"
|
|
557
|
+
f"{task_dir.name}: [{section}] needs a pullable docker_image instead of "
|
|
558
|
+
f"building {dockerfile} — building Dockerfiles isn't supported, so this "
|
|
542
559
|
"task can't run (it would otherwise score against the wrong default image). "
|
|
543
|
-
"Pass --env.taskset.ignore-dockerfile to
|
|
560
|
+
"Pass --env.taskset.ignore-dockerfile to load it with a fallback image, "
|
|
561
|
+
"then override the task's image or verifier_image with a pre-built image."
|
|
544
562
|
)
|
|
545
563
|
if require_image:
|
|
546
564
|
raise ValueError(
|
|
547
|
-
f"{task_dir.name}: no [
|
|
565
|
+
f"{task_dir.name}: no [{section}].docker_image and require_image=True"
|
|
548
566
|
)
|
|
549
567
|
return None
|
|
550
568
|
|
|
@@ -559,10 +577,27 @@ def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborD
|
|
|
559
577
|
parsed = harbor_task.config
|
|
560
578
|
artifacts, hooks, verifier = parse_verifier_extras(task_dir, parsed, harbor_config)
|
|
561
579
|
environment = parsed.environment
|
|
580
|
+
image = resolve_image(
|
|
581
|
+
task_dir,
|
|
582
|
+
environment.docker_image,
|
|
583
|
+
harbor_config.require_image,
|
|
584
|
+
harbor_config.ignore_dockerfile,
|
|
585
|
+
)
|
|
586
|
+
verifier_image = (
|
|
587
|
+
resolve_image(
|
|
588
|
+
task_dir,
|
|
589
|
+
parsed.verifier.environment.docker_image,
|
|
590
|
+
require_image=True,
|
|
591
|
+
ignore_dockerfile=harbor_config.ignore_dockerfile,
|
|
592
|
+
verifier=True,
|
|
593
|
+
)
|
|
594
|
+
if verifier is not None and parsed.verifier.environment is not None
|
|
595
|
+
else None
|
|
596
|
+
)
|
|
562
597
|
environment_dir = task_dir / "environment"
|
|
563
598
|
upload_environment = should_upload_environment_dir(
|
|
564
599
|
environment_dir,
|
|
565
|
-
docker_image=
|
|
600
|
+
docker_image=image,
|
|
566
601
|
)
|
|
567
602
|
network = parsed.agent.explicit_phase_policy() or environment.resolve_baseline()
|
|
568
603
|
task, meta = parsed.task, parsed.metadata
|
|
@@ -590,12 +625,7 @@ def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborD
|
|
|
590
625
|
name=harbor_task.name,
|
|
591
626
|
description=task.description if task else None,
|
|
592
627
|
prompt=harbor_task.instruction.strip(),
|
|
593
|
-
image=
|
|
594
|
-
task_dir,
|
|
595
|
-
environment.docker_image,
|
|
596
|
-
harbor_config.require_image,
|
|
597
|
-
harbor_config.ignore_dockerfile,
|
|
598
|
-
),
|
|
628
|
+
image=image,
|
|
599
629
|
workdir=environment.workdir,
|
|
600
630
|
network_allow=(
|
|
601
631
|
["*"]
|
|
@@ -622,6 +652,7 @@ def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborD
|
|
|
622
652
|
**environment.model_dump(
|
|
623
653
|
include={"env", "healthcheck", "mcp_servers"}, mode="json"
|
|
624
654
|
),
|
|
655
|
+
verifier_image=verifier_image,
|
|
625
656
|
verifier_env=parsed.verifier.env,
|
|
626
657
|
artifacts=artifacts,
|
|
627
658
|
collect=hooks,
|
|
@@ -719,23 +750,6 @@ def parse_verifier_environment(
|
|
|
719
750
|
if environment is None: # unreachable while the mode is SEPARATE
|
|
720
751
|
raise ValueError(f"{task_dir.name}: separate verifier resolved no environment")
|
|
721
752
|
declared = parsed.verifier.environment is not None
|
|
722
|
-
|
|
723
|
-
if declared and environment.docker_image is None:
|
|
724
|
-
if not harbor_config.ignore_dockerfile:
|
|
725
|
-
raise ValueError(
|
|
726
|
-
f"{task_dir.name}: [verifier.environment] names no docker_image, so "
|
|
727
|
-
"Harbor would build the verifier image from tests/Dockerfile. Verifiers "
|
|
728
|
-
"pulls images and never builds them: build and push it yourself (e.g. "
|
|
729
|
-
"`prime images push`) and set [verifier.environment].docker_image to the "
|
|
730
|
-
"resulting ref, or pass --taskset.ignore-dockerfile to grade in the "
|
|
731
|
-
"agent's image instead."
|
|
732
|
-
)
|
|
733
|
-
logger.warning(
|
|
734
|
-
"%s: [verifier.environment] names no docker_image — grading in the agent's "
|
|
735
|
-
"image rather than building tests/Dockerfile, so the verifier runs somewhere "
|
|
736
|
-
"the task never declared",
|
|
737
|
-
task_dir.name,
|
|
738
|
-
)
|
|
739
753
|
unsupported = [field for field in ("tpu",) if getattr(environment, field, None)]
|
|
740
754
|
if environment.os != TaskOS.LINUX or unsupported:
|
|
741
755
|
raise ValueError(
|
|
@@ -746,7 +760,6 @@ def parse_verifier_environment(
|
|
|
746
760
|
|
|
747
761
|
network = parsed.verifier.explicit_phase_policy() or environment.resolve_baseline()
|
|
748
762
|
return VerifierConfig(
|
|
749
|
-
image=environment.docker_image if declared else None,
|
|
750
763
|
# A declared environment states its own resources; what it leaves out is the
|
|
751
764
|
# run's default, not the agent task's. A fresh copy is the task's environment,
|
|
752
765
|
# so it keeps whatever the agent box resolved to.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""The scope that state shared by a run's processes is keyed by."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
_process_scope: str | None = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def run_scope() -> str:
|
|
13
|
+
"""``$VF_RUN_ID``, set by every entrypoint (the `vf-*` CLIs and the prime-rl launchers)
|
|
14
|
+
and inherited by spawned env servers and pool workers. A process started without one
|
|
15
|
+
gets a scope of its own, minted once per process."""
|
|
16
|
+
global _process_scope
|
|
17
|
+
run_id = os.environ.get("VF_RUN_ID")
|
|
18
|
+
if run_id:
|
|
19
|
+
return run_id
|
|
20
|
+
if _process_scope is None:
|
|
21
|
+
_process_scope = uuid.uuid4().hex
|
|
22
|
+
logger.warning(
|
|
23
|
+
"VF_RUN_ID is unset - run-scoped state such as creation limiters covers only "
|
|
24
|
+
"this process (scope %s)",
|
|
25
|
+
_process_scope,
|
|
26
|
+
)
|
|
27
|
+
return _process_scope
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"""User-global creation-rate limiters for the remote runtimes.
|
|
2
|
-
|
|
3
|
-
A leaky bucket backed by a lock file under the user cache (``~/.cache/verifiers``, falling
|
|
4
|
-
back to the temp dir when no home is resolvable), so a provider's per-account creation rate
|
|
5
|
-
(Modal sandboxes, Prime tunnels) is enforced across EVERY process for the user —
|
|
6
|
-
the single-process eval and all the elastically-spawned env-server worker processes alike — not
|
|
7
|
-
just within one process. Keyed by name: one bucket file per name, shared by every process (and
|
|
8
|
-
run) for the user.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import asyncio
|
|
12
|
-
import fcntl
|
|
13
|
-
import os
|
|
14
|
-
import time
|
|
15
|
-
from typing import Self
|
|
16
|
-
|
|
17
|
-
from verifiers.v1.utils.paths import CACHE_DIR
|
|
18
|
-
|
|
19
|
-
LIMITER_DIR = CACHE_DIR / "limiter"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class CreationLimiter:
|
|
23
|
-
"""An async leaky bucket shared across processes via a lock file: each `async with`
|
|
24
|
-
reserves the next `1/per_sec`-spaced slot (advancing the on-disk cursor under an exclusive
|
|
25
|
-
flock) and sleeps until it, so the aggregate creation rate across all of the user's
|
|
26
|
-
processes stays at `per_sec`. The reservation runs off the event loop; the wait does not
|
|
27
|
-
hold the lock. Backlogs over five minutes fail rather than silently stalling creation."""
|
|
28
|
-
|
|
29
|
-
def __init__(self, name: str, per_sec: float) -> None:
|
|
30
|
-
self._interval = 1 / per_sec
|
|
31
|
-
self._path = LIMITER_DIR / f"{name}.bucket"
|
|
32
|
-
|
|
33
|
-
def _reserve(self) -> float:
|
|
34
|
-
os.makedirs(LIMITER_DIR, exist_ok=True)
|
|
35
|
-
# Shared buckets require a clock comparable across hosts and boots.
|
|
36
|
-
with open(self._path, "a+") as f:
|
|
37
|
-
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
|
|
38
|
-
try:
|
|
39
|
-
f.seek(0)
|
|
40
|
-
data = f.read().strip()
|
|
41
|
-
now = time.time()
|
|
42
|
-
slot = max(now, float(data) if data else 0.0)
|
|
43
|
-
wait = slot - now
|
|
44
|
-
if wait > 5 * 60:
|
|
45
|
-
raise TimeoutError(
|
|
46
|
-
f"{self._path.stem} creation limiter backlog of {wait:.1f}s "
|
|
47
|
-
f"exceeds 300s ({self._path})"
|
|
48
|
-
)
|
|
49
|
-
f.seek(0)
|
|
50
|
-
f.truncate()
|
|
51
|
-
f.write(repr(slot + self._interval))
|
|
52
|
-
f.flush()
|
|
53
|
-
return wait
|
|
54
|
-
finally:
|
|
55
|
-
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
|
|
56
|
-
|
|
57
|
-
async def __aenter__(self) -> Self:
|
|
58
|
-
wait = await asyncio.to_thread(self._reserve)
|
|
59
|
-
if wait > 0:
|
|
60
|
-
await asyncio.sleep(wait)
|
|
61
|
-
return self
|
|
62
|
-
|
|
63
|
-
async def __aexit__(self, *exc) -> bool:
|
|
64
|
-
return False
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
_creation_limiters: dict[str, CreationLimiter] = {}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def creation_limiter(per_sec: float | None, name: str) -> CreationLimiter | None:
|
|
71
|
-
"""A user-global limiter pacing `name`'s creation to `per_sec`/s (None/<= 0 disables).
|
|
72
|
-
|
|
73
|
-
All callers (and processes) sharing a `name` share one bucket, so use one rate per name."""
|
|
74
|
-
if not per_sec or per_sec <= 0:
|
|
75
|
-
return None
|
|
76
|
-
limiter = _creation_limiters.get(name)
|
|
77
|
-
if limiter is None:
|
|
78
|
-
limiter = _creation_limiters[name] = CreationLimiter(name, per_sec)
|
|
79
|
-
return limiter
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{verifiers-0.3.2.dev128 → verifiers-0.3.2.dev130}/tests/v1/fixtures/tool_response_image_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|