verifiers 0.3.2.dev99__tar.gz → 0.3.2.dev101__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.dev99 → verifiers-0.3.2.dev101}/PKG-INFO +1 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/pyproject.toml +6 -6
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/conftest.py +52 -15
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_configs.py +1 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_envs.py +1 -1
- verifiers-0.3.2.dev101/tests/v1/test_serve_delta.py +266 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/agent.py +8 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/dashboard/eval.py +14 -9
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/debug.py +1 -1
- verifiers-0.3.2.dev101/verifiers/v1/cli/eval/hint.py +5 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/eval/main.py +5 -7
- verifiers-0.3.2.dev101/verifiers/v1/cli/eval/runner.py +175 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/gepa.py +2 -2
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/init.py +3 -3
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/replay.py +1 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/validate.py +2 -2
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/agent.py +2 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/eval.py +3 -10
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/validate.py +1 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/client.py +1 -1
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/env.py +9 -2
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/graph.py +6 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/rlm/harness.py +17 -10
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/server.py +8 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/rollout.py +6 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/__init__.py +2 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/client.py +75 -34
- verifiers-0.3.2.dev101/verifiers/v1/serve/delta.py +281 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/pool.py +19 -10
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/server.py +29 -8
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/types.py +12 -6
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/harbor/taskset.py +4 -4
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/trace.py +29 -0
- verifiers-0.3.2.dev99/verifiers/v1/cli/eval/runner.py +0 -284
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/.gitignore +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/LICENSE +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/README.md +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/counter_tool_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/duet_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/echo_acp_resume_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/echo_agentic_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/echo_tool_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/echo_user_sim_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/echo_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/pyproject.toml +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/fixtures/tool_response_image_v1.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_color_codeword_tasks.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_e2e.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_graph.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_judges.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_platform_run.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_scoring.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/tests/v1/test_trace.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/cli/commands/init.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/acp/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/acp/runner.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/dashboard/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/dashboard/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/dashboard/replay.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/dashboard/validate.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/eval/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/eval/resume.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/output.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/resolve.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/cli/resume.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/clients/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/clients/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/clients/client.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/clients/eval.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/clients/train.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/debug.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/init.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/cli/replay.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/judge.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/retries.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/runtime.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/serve.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/task.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/configs/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/dialects/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/dialects/anthropic.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/dialects/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/dialects/chat.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/dialects/responses.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/agentic_judge/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/best_of_n/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/isolated_verifier/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/isolated_verifier/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/shared_agentic_judge/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/single_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/single_agent/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/user_sim/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/envs/user_sim/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/episode.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/errors.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/adapter.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/config.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/dataset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/reflection.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/gepa/runner.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/bash/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/bash/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/browser_use/program.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/codex/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/codex/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/node.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/null/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/null/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/pi/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/pi/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/compaction.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/core.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/install.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/launch.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/harnesses/utils/mcp.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/pool.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/tool.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/tunnel/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/tunnel/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/tunnel/custom.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/interception/tunnel/prime.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judge.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judges/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judges/reference.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judges/reference.txt +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judges/rubric.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/judges/rubric.txt +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/mcp/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/mcp/launch.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/mcp/server.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/mcp/toolset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/base.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/docker/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/docker/egress.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/limiters.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/modal.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/prime.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/runtimes/subprocess.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/semantic.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/serve/encoding.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/session.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/state.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/task.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/harbor/env.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/lean/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/lean/scoring.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/lean/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/types.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/__init__.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/aio.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/artifacts.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/compile.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/decorators.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/format.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/generic.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/git.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/image.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/interrupt.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/loaders.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/logging.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/memory.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/paths.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/platform.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/prime.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/retries.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/verifiers/v1/utils/score.py +0 -0
- {verifiers-0.3.2.dev99 → verifiers-0.3.2.dev101}/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.dev101
|
|
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
|
|
@@ -152,12 +152,12 @@ prime-pydantic-config = false
|
|
|
152
152
|
renderers = false
|
|
153
153
|
|
|
154
154
|
[project.scripts]
|
|
155
|
-
eval = "verifiers.v1.cli.eval.main:main"
|
|
156
|
-
validate = "verifiers.v1.cli.validate:main"
|
|
157
|
-
debug = "verifiers.v1.cli.debug:main"
|
|
158
|
-
replay = "verifiers.v1.cli.replay:main"
|
|
159
|
-
init = "verifiers.v1.cli.init:main"
|
|
160
|
-
gepa = "verifiers.v1.cli.gepa:main"
|
|
155
|
+
vf-eval = "verifiers.v1.cli.eval.main:main"
|
|
156
|
+
vf-validate = "verifiers.v1.cli.validate:main"
|
|
157
|
+
vf-debug = "verifiers.v1.cli.debug:main"
|
|
158
|
+
vf-replay = "verifiers.v1.cli.replay:main"
|
|
159
|
+
vf-init = "verifiers.v1.cli.init:main"
|
|
160
|
+
vf-gepa = "verifiers.v1.cli.gepa:main"
|
|
161
161
|
|
|
162
162
|
# hatchling configuration
|
|
163
163
|
[tool.hatch.version]
|
|
@@ -5,7 +5,8 @@ settings that still exercise the path, then assert on the resulting `Trace`(s)
|
|
|
5
5
|
not unit tests of individual components. They need a model API key (`PRIME_API_KEY`);
|
|
6
6
|
without one the `e2e`-marked tests skip (config parsing still runs).
|
|
7
7
|
|
|
8
|
-
`run_v1` mirrors the eval CLI
|
|
8
|
+
`run_v1` mirrors the eval CLI (`run_eval`, in-process); `run_v1_server` drives the same env
|
|
9
|
+
through an env-server worker pool, the path prime-rl trains through. Placement coverage (harness x harness runtime x tool
|
|
9
10
|
server runtime) is PAIRWISE, not a full cross product: each test carries a curated list of
|
|
10
11
|
combinations (in test_e2e.py) that hits every axis value and the cross-boundary pairs with
|
|
11
12
|
distinct networking. The full cross bought flake exposure and CI minutes, not coverage — add
|
|
@@ -32,6 +33,7 @@ prime/modal provision real remote sandboxes (slow, infra-flaky, need setup), so
|
|
|
32
33
|
CI runs deterministic tests across the Python matrix and the remaining live E2Es once.
|
|
33
34
|
"""
|
|
34
35
|
|
|
36
|
+
import asyncio
|
|
35
37
|
import os
|
|
36
38
|
from pathlib import Path
|
|
37
39
|
|
|
@@ -130,9 +132,7 @@ def _eval_config(
|
|
|
130
132
|
taskset_overrides: dict | None = None,
|
|
131
133
|
runtime: dict | None = None,
|
|
132
134
|
env: dict | None = None,
|
|
133
|
-
pool: dict | None = None,
|
|
134
135
|
reasoning_effort: str | None = None,
|
|
135
|
-
server: bool = False,
|
|
136
136
|
) -> EvalConfig:
|
|
137
137
|
"""Build the smallest `EvalConfig` that still exercises the path, shared by the in-process
|
|
138
138
|
(`run_v1`) and env-server (`run_v1_server`) fixtures. `taskset_overrides` merges onto the
|
|
@@ -184,7 +184,6 @@ def _eval_config(
|
|
|
184
184
|
"reasoning_effort": reasoning_effort,
|
|
185
185
|
},
|
|
186
186
|
rich=None,
|
|
187
|
-
serve=({"pool": pool} if pool else {}) if server else None,
|
|
188
187
|
output_dir=output_dir.parent,
|
|
189
188
|
run={"dir": output_dir.name},
|
|
190
189
|
model=CI_MODEL,
|
|
@@ -194,8 +193,7 @@ def _eval_config(
|
|
|
194
193
|
|
|
195
194
|
@pytest.fixture
|
|
196
195
|
def run_v1():
|
|
197
|
-
"""Run a v1 taskset end-to-end in-process (`run_eval`
|
|
198
|
-
its traces."""
|
|
196
|
+
"""Run a v1 taskset end-to-end in-process (`run_eval`) and return its traces."""
|
|
199
197
|
|
|
200
198
|
async def _run(taskset: str, **kwargs) -> list[Trace]:
|
|
201
199
|
config = _eval_config(taskset, **kwargs)
|
|
@@ -208,17 +206,56 @@ def run_v1():
|
|
|
208
206
|
|
|
209
207
|
@pytest.fixture
|
|
210
208
|
def run_v1_server():
|
|
211
|
-
"""Run a v1 taskset through
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
209
|
+
"""Run a v1 taskset through an env-server worker pool — the path prime-rl trains
|
|
210
|
+
through. Spawns the broker + a worker, so it's the only fixture that exercises
|
|
211
|
+
serving resources (shared tool servers, interception pool) being stood up by the
|
|
212
|
+
*server* rather than the in-process runner. Pinned to a single static worker for
|
|
213
|
+
determinism."""
|
|
214
|
+
import multiprocessing as mp
|
|
215
|
+
|
|
216
|
+
from verifiers.v1.serve import EnvClient, env_config_data, serve_env
|
|
217
|
+
from verifiers.v1.utils.loaders import load_taskset
|
|
216
218
|
|
|
217
219
|
async def _run(taskset: str, **kwargs) -> list[Trace]:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
config = _eval_config(taskset, **kwargs)
|
|
221
|
+
tasks = list(load_taskset(config.env.taskset).head(config.num_tasks))
|
|
222
|
+
mpctx = mp.get_context("spawn")
|
|
223
|
+
address_queue: mp.Queue = mpctx.Queue()
|
|
224
|
+
proc = mpctx.Process(
|
|
225
|
+
target=serve_env,
|
|
226
|
+
kwargs={
|
|
227
|
+
"max_workers": 1,
|
|
228
|
+
"elastic": False,
|
|
229
|
+
"address": "tcp://127.0.0.1:0",
|
|
230
|
+
"address_queue": address_queue,
|
|
231
|
+
"config_data": env_config_data(config.env),
|
|
232
|
+
"max_concurrent": config.max_concurrent,
|
|
233
|
+
},
|
|
234
|
+
)
|
|
235
|
+
proc.start()
|
|
236
|
+
try:
|
|
237
|
+
address = await asyncio.to_thread(address_queue.get, timeout=600)
|
|
238
|
+
client = EnvClient(address=address)
|
|
239
|
+
try:
|
|
240
|
+
await client.wait_for_server_startup(timeout=600)
|
|
241
|
+
episodes = await asyncio.gather(
|
|
242
|
+
*(
|
|
243
|
+
client.run(
|
|
244
|
+
client=config.client,
|
|
245
|
+
model=config.model,
|
|
246
|
+
sampling=config.sampling,
|
|
247
|
+
task_data=task.data.model_dump(mode="json"),
|
|
248
|
+
)
|
|
249
|
+
for task in tasks
|
|
250
|
+
for _ in range(config.num_rollouts)
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
finally:
|
|
254
|
+
await client.close()
|
|
255
|
+
finally:
|
|
256
|
+
proc.terminate()
|
|
257
|
+
await asyncio.to_thread(proc.join, 10)
|
|
258
|
+
return [t for e in episodes for t in e.traces]
|
|
222
259
|
|
|
223
260
|
return _run
|
|
224
261
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Every checked-in v1 eval config parses.
|
|
2
2
|
|
|
3
3
|
Mirrors prime-rl's config test: glob the configs and assert each validates into its config
|
|
4
|
-
type. The root `configs/*.toml` are the `uv run eval @ <file>` v1 configs (EvalConfig).
|
|
4
|
+
type. The root `configs/*.toml` are the `uv run vf-eval @ <file>` v1 configs (EvalConfig).
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import tomllib
|
|
@@ -66,7 +66,7 @@ def test_eval(taskset: str):
|
|
|
66
66
|
for flag in (f"--env.{seat}.max-turns", "4")
|
|
67
67
|
]
|
|
68
68
|
cmd = [
|
|
69
|
-
"uv", "run", "--no-sync", "eval", taskset,
|
|
69
|
+
"uv", "run", "--no-sync", "vf-eval", taskset,
|
|
70
70
|
*model,
|
|
71
71
|
"-n", "1", "-r", "1", *caps,
|
|
72
72
|
"--sampling.max-tokens", "512", "--no-rich", "--no-push",
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""The env-serve delta stream: a trace's changes leave once each and reassemble into
|
|
2
|
+
the episode the worker finished with."""
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import copy
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
import verifiers.v1 as vf
|
|
10
|
+
from verifiers.v1.episode import EnvInfo, Episode, WireEpisode
|
|
11
|
+
from verifiers.v1.graph import MessageNode
|
|
12
|
+
from verifiers.v1.semantic import ParentLink
|
|
13
|
+
from verifiers.v1.serve.delta import (
|
|
14
|
+
DeltaStreamer,
|
|
15
|
+
EpisodeAssembly,
|
|
16
|
+
TraceSummary,
|
|
17
|
+
dump,
|
|
18
|
+
pack,
|
|
19
|
+
unpack,
|
|
20
|
+
)
|
|
21
|
+
from verifiers.v1.trace import ModelCall, TimeSpan, TraceTask
|
|
22
|
+
from verifiers.v1.types import AssistantMessage, Usage, UserMessage
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MyTask(vf.TaskData):
|
|
26
|
+
prompt: str
|
|
27
|
+
answer: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Slot:
|
|
31
|
+
def __init__(self) -> None:
|
|
32
|
+
self.traces: list[vf.Trace] = []
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def settle() -> None:
|
|
36
|
+
"""Let a notified change reach the wire: the flush is a callback that starts a task."""
|
|
37
|
+
for _ in range(3):
|
|
38
|
+
await asyncio.sleep(0)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def make_trace() -> vf.Trace:
|
|
42
|
+
return vf.Trace(
|
|
43
|
+
agent=vf.AgentInfo(config=vf.AgentConfig()),
|
|
44
|
+
task=TraceTask(type="MyTask", data=MyTask(idx=0, prompt="q", answer="a")),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def add_turn(trace: vf.Trace, reply: str) -> None:
|
|
49
|
+
parent = len(trace.nodes) - 1 if trace.nodes else None
|
|
50
|
+
if parent is None:
|
|
51
|
+
trace.nodes.append(MessageNode(parent=None, message=UserMessage(content="q")))
|
|
52
|
+
parent = 0
|
|
53
|
+
trace.nodes.append(
|
|
54
|
+
MessageNode(
|
|
55
|
+
parent=parent,
|
|
56
|
+
message=AssistantMessage(content=reply),
|
|
57
|
+
sampled=True,
|
|
58
|
+
token_ids=[1, 2, 3],
|
|
59
|
+
mask=[False, True, True],
|
|
60
|
+
logprobs=[-0.1, -0.2],
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
trace.calls.append(
|
|
64
|
+
ModelCall(
|
|
65
|
+
node=len(trace.nodes) - 1,
|
|
66
|
+
usage=Usage(prompt_tokens=3, completion_tokens=2),
|
|
67
|
+
time=TimeSpan(start=1.0, end=2.0),
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
trace.notify()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_delta_fields_cover_every_serialized_trace_field():
|
|
74
|
+
"""A new Trace field must be routed through the stream, or it silently vanishes."""
|
|
75
|
+
from verifiers.v1.serve.delta import HEADER_FIELDS, LIST_FIELDS, SCALAR_FIELDS
|
|
76
|
+
|
|
77
|
+
streamed = set(HEADER_FIELDS) | set(LIST_FIELDS) | set(SCALAR_FIELDS)
|
|
78
|
+
serialized = {
|
|
79
|
+
name for name, info in vf.Trace.model_fields.items() if not info.exclude
|
|
80
|
+
}
|
|
81
|
+
assert streamed == serialized
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@pytest.mark.asyncio
|
|
85
|
+
async def test_failed_send_is_diffed_again():
|
|
86
|
+
"""A delta the wire refused is not lost: its cursor stays and the next flush
|
|
87
|
+
carries the same content, so the client still assembles the whole trace."""
|
|
88
|
+
slot = Slot()
|
|
89
|
+
frames: list[bytes] = []
|
|
90
|
+
fail = {"on": False}
|
|
91
|
+
|
|
92
|
+
async def send(data: bytes) -> None:
|
|
93
|
+
if fail["on"]:
|
|
94
|
+
raise OSError("host unreachable")
|
|
95
|
+
frames.append(data)
|
|
96
|
+
|
|
97
|
+
async with DeltaStreamer(slot, send) as streamer:
|
|
98
|
+
trace = make_trace()
|
|
99
|
+
slot.traces.append(trace)
|
|
100
|
+
streamer.watch(trace)
|
|
101
|
+
await settle()
|
|
102
|
+
fail["on"] = True
|
|
103
|
+
add_turn(trace, "a1")
|
|
104
|
+
await settle()
|
|
105
|
+
fail["on"] = False
|
|
106
|
+
add_turn(trace, "a2")
|
|
107
|
+
await settle()
|
|
108
|
+
slot.traces = [trace]
|
|
109
|
+
assembly = EpisodeAssembly()
|
|
110
|
+
for frame in frames:
|
|
111
|
+
assembly.apply(unpack(frame))
|
|
112
|
+
assert len(assembly.traces[trace.id]["nodes"]) == 3
|
|
113
|
+
assert len(assembly.traces[trace.id]["calls"]) == 2
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.asyncio
|
|
117
|
+
async def test_pending_preview_streams_and_clears_on_commit():
|
|
118
|
+
slot = Slot()
|
|
119
|
+
frames: list[bytes] = []
|
|
120
|
+
|
|
121
|
+
async def send(data: bytes) -> None:
|
|
122
|
+
frames.append(data)
|
|
123
|
+
|
|
124
|
+
async with DeltaStreamer(slot, send) as streamer:
|
|
125
|
+
trace = make_trace()
|
|
126
|
+
slot.traces.append(trace)
|
|
127
|
+
streamer.watch(trace)
|
|
128
|
+
add_turn(trace, "a1")
|
|
129
|
+
await settle()
|
|
130
|
+
# the harness sends its next request: the tool result is previewed at once
|
|
131
|
+
request, subagent = ["request"], ["sub-agent"] # unhashable, like a PendingTurn
|
|
132
|
+
trace.preview(request, [UserMessage(content="tool says 42")])
|
|
133
|
+
await settle()
|
|
134
|
+
preview = unpack(frames[-1])
|
|
135
|
+
assert preview["pending"][0]["content"] == "tool says 42"
|
|
136
|
+
assert "nodes" not in preview
|
|
137
|
+
# a concurrent request (a sub-agent) previews under its own key; its failure
|
|
138
|
+
# takes only its own messages back
|
|
139
|
+
trace.preview(subagent, [UserMessage(content="sub-agent asks")])
|
|
140
|
+
await settle()
|
|
141
|
+
assert [m["content"] for m in unpack(frames[-1])["pending"]] == [
|
|
142
|
+
"tool says 42",
|
|
143
|
+
"sub-agent asks",
|
|
144
|
+
]
|
|
145
|
+
trace.clear_preview(subagent)
|
|
146
|
+
trace.notify()
|
|
147
|
+
await settle()
|
|
148
|
+
assert [m["content"] for m in unpack(frames[-1])["pending"]] == ["tool says 42"]
|
|
149
|
+
# the model answers: the turn commits and the preview goes with it
|
|
150
|
+
trace.nodes.append(
|
|
151
|
+
MessageNode(parent=1, message=UserMessage(content="tool says 42"))
|
|
152
|
+
)
|
|
153
|
+
trace.clear_preview(request)
|
|
154
|
+
add_turn(trace, "a2")
|
|
155
|
+
await settle()
|
|
156
|
+
committed = unpack(frames[-1])
|
|
157
|
+
assert len(committed["nodes"]) == 2 and "pending" not in committed
|
|
158
|
+
trace.stop("agent_completed")
|
|
159
|
+
trace.ok = True
|
|
160
|
+
episode = Episode(
|
|
161
|
+
env=EnvInfo(id="my-env"), task=trace.task, ok=True, traces=[trace]
|
|
162
|
+
)
|
|
163
|
+
slot.traces = list(episode.traces)
|
|
164
|
+
assembly = EpisodeAssembly()
|
|
165
|
+
for frame in frames:
|
|
166
|
+
assembly.apply(unpack(frame))
|
|
167
|
+
if unpack(frame).get("pending"):
|
|
168
|
+
assert assembly.traces[trace.id]["pending"][0]["content"] == "tool says 42"
|
|
169
|
+
assert assembly.traces[trace.id]["pending"] == []
|
|
170
|
+
summaries = [
|
|
171
|
+
TraceSummary(id=trace.id, nodes=len(trace.nodes), calls=len(trace.calls))
|
|
172
|
+
]
|
|
173
|
+
record = assembly.finish(dump(episode, exclude={"traces"}), summaries)
|
|
174
|
+
assert "pending" not in record["traces"][0]
|
|
175
|
+
assert WireEpisode.model_validate(unpack(pack(record))).traces[0].id == trace.id
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@pytest.mark.asyncio
|
|
179
|
+
async def test_deltas_stream_once_and_reassemble_the_episode():
|
|
180
|
+
slot = Slot()
|
|
181
|
+
frames: list[bytes] = []
|
|
182
|
+
|
|
183
|
+
async def send(data: bytes) -> None:
|
|
184
|
+
frames.append(data)
|
|
185
|
+
|
|
186
|
+
async with DeltaStreamer(slot, send) as streamer:
|
|
187
|
+
trace = make_trace()
|
|
188
|
+
slot.traces.append(trace)
|
|
189
|
+
streamer.watch(trace)
|
|
190
|
+
trace.timing.boot.start = 1.0
|
|
191
|
+
trace.notify()
|
|
192
|
+
await settle()
|
|
193
|
+
assert len(frames) == 1, "the mint and the boot span coalesce into one delta"
|
|
194
|
+
add_turn(trace, "a1")
|
|
195
|
+
await settle()
|
|
196
|
+
add_turn(trace, "a2")
|
|
197
|
+
trace.nodes[0].semantic_parents.append(ParentLink(node=1, type="reply"))
|
|
198
|
+
await settle()
|
|
199
|
+
trace.record_reward("match", 1.0)
|
|
200
|
+
trace.stop("agent_completed")
|
|
201
|
+
trace.ok = True
|
|
202
|
+
episode = Episode(
|
|
203
|
+
env=EnvInfo(id="my-env"), task=trace.task, ok=True, traces=[trace]
|
|
204
|
+
)
|
|
205
|
+
slot.traces = list(episode.traces)
|
|
206
|
+
# The exit flushed the tail (reward, stop, ok) without re-sending any node.
|
|
207
|
+
deltas = [unpack(frame) for frame in frames]
|
|
208
|
+
sent_nodes = sum(len(delta.get("nodes", [])) for delta in deltas)
|
|
209
|
+
sent_calls = sum(len(delta.get("calls", [])) for delta in deltas)
|
|
210
|
+
assert (sent_nodes, sent_calls) == (3, 2)
|
|
211
|
+
assert sum("open" in delta for delta in deltas) == 1
|
|
212
|
+
assert any("links" in delta for delta in deltas)
|
|
213
|
+
assert deltas[-1]["set"]["stop_condition"] == "agent_completed"
|
|
214
|
+
|
|
215
|
+
handed = copy.deepcopy(deltas)
|
|
216
|
+
assembly = EpisodeAssembly()
|
|
217
|
+
for delta in deltas:
|
|
218
|
+
assembly.apply(delta)
|
|
219
|
+
assert deltas == handed, "assembling never mutates a delta the caller holds"
|
|
220
|
+
head = dump(episode, exclude={"traces"})
|
|
221
|
+
summaries = [
|
|
222
|
+
TraceSummary(id=trace.id, nodes=len(trace.nodes), calls=len(trace.calls))
|
|
223
|
+
]
|
|
224
|
+
rebuilt = WireEpisode.model_validate(unpack(pack(assembly.finish(head, summaries))))
|
|
225
|
+
assert rebuilt.ok and rebuilt.traces[0].id == trace.id
|
|
226
|
+
assert rebuilt.traces[0].messages == trace.messages
|
|
227
|
+
assert (
|
|
228
|
+
rebuilt.traces[0].nodes[0].semantic_parents == trace.nodes[0].semantic_parents
|
|
229
|
+
)
|
|
230
|
+
assert rebuilt.traces[0].rewards["match"].value == 1.0
|
|
231
|
+
assert rebuilt.traces[0].stop_condition == "agent_completed"
|
|
232
|
+
assert len(rebuilt.traces[0].calls) == 2
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@pytest.mark.asyncio
|
|
236
|
+
async def test_discarded_attempt_drops_its_trace():
|
|
237
|
+
slot = Slot()
|
|
238
|
+
frames: list[bytes] = []
|
|
239
|
+
|
|
240
|
+
async def send(data: bytes) -> None:
|
|
241
|
+
frames.append(data)
|
|
242
|
+
|
|
243
|
+
async with DeltaStreamer(slot, send) as streamer:
|
|
244
|
+
first = make_trace()
|
|
245
|
+
slot.traces.append(first)
|
|
246
|
+
streamer.watch(first)
|
|
247
|
+
add_turn(first, "a1")
|
|
248
|
+
await settle()
|
|
249
|
+
slot.traces = [] # the attempt is retried
|
|
250
|
+
second = make_trace()
|
|
251
|
+
slot.traces.append(second)
|
|
252
|
+
streamer.watch(second)
|
|
253
|
+
await settle()
|
|
254
|
+
deltas = [unpack(frame) for frame in frames]
|
|
255
|
+
assert {"trace": first.id, "discard": True} in deltas
|
|
256
|
+
assembly = EpisodeAssembly()
|
|
257
|
+
for delta in deltas:
|
|
258
|
+
assembly.apply(delta)
|
|
259
|
+
assert list(assembly.traces) == [second.id]
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_finish_refuses_a_gap():
|
|
263
|
+
assembly = EpisodeAssembly()
|
|
264
|
+
assembly.apply({"trace": "t", "open": {"id": "t"}, "nodes": [{}]})
|
|
265
|
+
with pytest.raises(RuntimeError, match="assembled 1 nodes"):
|
|
266
|
+
assembly.finish({}, [TraceSummary(id="t", nodes=2, calls=0)])
|
|
@@ -54,11 +54,19 @@ __all__ = ["Agent", "AgentConfig", "Agents", "TimeoutConfig", "make_agent"]
|
|
|
54
54
|
logger = logging.getLogger(__name__)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
DEFAULT_ROLLOUT_TIMEOUT = 4 * 3600.0
|
|
58
|
+
"""Agent solve-attempt budget when neither the eval config nor the task sets one."""
|
|
59
|
+
|
|
60
|
+
|
|
57
61
|
def resolve_rollout_timeouts(timeout: TimeoutConfig, task: Task) -> RolloutTimeouts:
|
|
58
62
|
"""Apply an agent's stage-timeout precedence to one task."""
|
|
59
63
|
agent_timeout = (
|
|
60
64
|
timeout.rollout if timeout.rollout is not None else task.data.timeout.agent
|
|
61
65
|
)
|
|
66
|
+
if agent_timeout is None:
|
|
67
|
+
agent_timeout = DEFAULT_ROLLOUT_TIMEOUT
|
|
68
|
+
elif agent_timeout == 0:
|
|
69
|
+
agent_timeout = None # explicit: unbounded
|
|
62
70
|
return RolloutTimeouts(
|
|
63
71
|
setup=timeout.setup if timeout.setup is not None else task.data.timeout.setup,
|
|
64
72
|
agent=agent_timeout,
|
|
@@ -16,6 +16,7 @@ from rich.table import Table
|
|
|
16
16
|
from rich.text import Text
|
|
17
17
|
|
|
18
18
|
from verifiers.v1.cli.dashboard.base import live_view
|
|
19
|
+
from verifiers.v1.cli.eval.hint import PRIME_RL_HINT
|
|
19
20
|
from verifiers.v1.cli.output import attempt_log_file, output_path
|
|
20
21
|
from verifiers.v1.configs.cli.eval import EvalConfig
|
|
21
22
|
from verifiers.v1.env import RunSlot
|
|
@@ -280,6 +281,10 @@ def Overview(config: EvalConfig) -> Table:
|
|
|
280
281
|
return grid
|
|
281
282
|
|
|
282
283
|
|
|
284
|
+
def _prime_rl_footer() -> Group:
|
|
285
|
+
return Group(Text(""), Text(PRIME_RL_HINT, style="dim", overflow="fold"))
|
|
286
|
+
|
|
287
|
+
|
|
283
288
|
def _push_footer(push: "PushState | None") -> Group | None:
|
|
284
289
|
"""The `--push` line under the rollouts: dim with the run's URL while it streams,
|
|
285
290
|
white once pushed, red when it failed. `None` when `--push` is off or the run stayed
|
|
@@ -833,13 +838,15 @@ def _render(
|
|
|
833
838
|
# The --push status line (and, on Ctrl-C, the cleanup notice) appear under the rollouts. Measure
|
|
834
839
|
# the fixed top (header + progress + rule) and the footer so the rollout rows fill what's left;
|
|
835
840
|
# page through them (timer / arrows) when they'd overflow (else rich truncates).
|
|
836
|
-
footers = [
|
|
837
|
-
|
|
841
|
+
footers = [
|
|
842
|
+
f
|
|
843
|
+
for f in (_push_footer(push), _interrupt_footer(), _prime_rl_footer())
|
|
844
|
+
if f is not None
|
|
845
|
+
]
|
|
846
|
+
footer = Group(*footers)
|
|
838
847
|
progress = Progress(slots, start, completed)
|
|
839
848
|
top = Group(header, progress, Rule(style="dim"))
|
|
840
|
-
reserved = len(_CONSOLE.render_lines(top))
|
|
841
|
-
if footer is not None:
|
|
842
|
-
reserved += len(_CONSOLE.render_lines(footer))
|
|
849
|
+
reserved = len(_CONSOLE.render_lines(top)) + len(_CONSOLE.render_lines(footer))
|
|
843
850
|
rows_per_page = max(1, _CONSOLE.size.height - reserved - 1)
|
|
844
851
|
if tail is not None: # --show-logs: the run's log stream in place of rollout rows
|
|
845
852
|
parts = [
|
|
@@ -847,9 +854,8 @@ def _render(
|
|
|
847
854
|
progress,
|
|
848
855
|
Rule(style="dim"),
|
|
849
856
|
tail.view(rows_per_page),
|
|
857
|
+
footer,
|
|
850
858
|
]
|
|
851
|
-
if footer is not None:
|
|
852
|
-
parts.append(footer)
|
|
853
859
|
return Group(*parts)
|
|
854
860
|
page_groups, index, count = _paginate(_groups(slots), rows_per_page, pager, now)
|
|
855
861
|
if count > 1:
|
|
@@ -859,9 +865,8 @@ def _render(
|
|
|
859
865
|
progress,
|
|
860
866
|
Rule(style="dim"),
|
|
861
867
|
Rows(page_groups, now, runtime_type, completed),
|
|
868
|
+
footer,
|
|
862
869
|
]
|
|
863
|
-
if footer is not None:
|
|
864
|
-
parts.append(footer)
|
|
865
870
|
return Group(*parts)
|
|
866
871
|
|
|
867
872
|
|
|
@@ -36,7 +36,7 @@ from verifiers.v1.utils.logging import setup_logging
|
|
|
36
36
|
logger = logging.getLogger(__name__)
|
|
37
37
|
|
|
38
38
|
USAGE = (
|
|
39
|
-
"usage: uv run debug [<taskset-id>] (--command <cmd> | --script-path <path>) "
|
|
39
|
+
"usage: uv run vf-debug [<taskset-id>] (--command <cmd> | --script-path <path>) "
|
|
40
40
|
"[--runtime.type subprocess] [options] [@ file.toml]\n"
|
|
41
41
|
" runs setup, then one command or uploaded host script, and saves traces"
|
|
42
42
|
)
|
|
@@ -30,8 +30,8 @@ from verifiers.v1.utils.logging import setup_logging
|
|
|
30
30
|
logger = logging.getLogger(__name__)
|
|
31
31
|
|
|
32
32
|
USAGE = (
|
|
33
|
-
"usage: uv run eval [<taskset-id>] [--env.id <id>] [options] [@ file.toml]\n"
|
|
34
|
-
" uv run eval @ <run-dir>/configs/resolved/eval.json --resume (re-run the run's missing/errored rollouts)"
|
|
33
|
+
"usage: uv run vf-eval [<taskset-id>] [--env.id <id>] [options] [@ file.toml]\n"
|
|
34
|
+
" uv run vf-eval @ <run-dir>/configs/resolved/eval.json --resume (re-run the run's missing/errored rollouts)"
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
|
|
@@ -48,7 +48,7 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
48
48
|
return
|
|
49
49
|
# An env-block flag skips the usage gate so the typed parse renders its
|
|
50
50
|
# did-you-mean instead of a bare usage line.
|
|
51
|
-
typed_axis = any(a.startswith(
|
|
51
|
+
typed_axis = any(a.startswith("--env.") for a in argv)
|
|
52
52
|
if (
|
|
53
53
|
not extract_id(argv, "env.taskset")
|
|
54
54
|
and not references_config_file(argv)
|
|
@@ -108,7 +108,7 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
108
108
|
raise SystemExit(
|
|
109
109
|
f"--resume requires the exact config the run was started with - it "
|
|
110
110
|
f"differs in [{', '.join(changed)}]. Resumed rollouts would not be "
|
|
111
|
-
f"comparable; re-run with `uv run eval @ {saved_path} --resume`, or "
|
|
111
|
+
f"comparable; re-run with `uv run vf-eval @ {saved_path} --resume`, or "
|
|
112
112
|
"start a fresh run"
|
|
113
113
|
)
|
|
114
114
|
if config.dry_run: # resolved + validated; write it to the output dir and exit
|
|
@@ -116,8 +116,7 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
116
116
|
logger.info("wrote config to %s", write_config(config, run_path))
|
|
117
117
|
return
|
|
118
118
|
# Always tee this attempt's logs to `logs/attempt_<n>/eval.log` (`logs/latest`
|
|
119
|
-
# points there)
|
|
120
|
-
# `--rich.show-logs` tails it live.
|
|
119
|
+
# points there); `--rich.show-logs` tails it live.
|
|
121
120
|
log_file = str(create_attempt_log_dir(run_path) / "eval.log")
|
|
122
121
|
level = "DEBUG" if config.verbose else "INFO"
|
|
123
122
|
setup_logging(level, log_file=log_file, console=config.rich is None)
|
|
@@ -128,7 +127,6 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
128
127
|
install_interrupt()
|
|
129
128
|
|
|
130
129
|
try:
|
|
131
|
-
# Through the env-server worker pool by default; in-process with --no-serve.
|
|
132
130
|
episodes = asyncio.run(run_eval(config))
|
|
133
131
|
except KeyboardInterrupt:
|
|
134
132
|
# Graceful cleanup has already run (each rollout's `finally`); partial results are on
|