verifiers 0.4.1.dev50__tar.gz → 0.4.1.dev52__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.
Files changed (283) hide show
  1. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/PKG-INFO +1 -5
  2. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/pyproject.toml +0 -12
  3. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/conftest.py +5 -5
  4. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/agent_user.py +1 -1
  5. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/grid.py +108 -92
  6. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_agent_user.py +2 -7
  7. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_agentic_judge.py +3 -3
  8. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_compose_scoring.py +51 -54
  9. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_limits.py +2 -2
  10. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_multi_turn.py +6 -6
  11. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_multi_turn_tool.py +3 -3
  12. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_multimodal_tool.py +1 -1
  13. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_network_policy.py +3 -10
  14. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_resume_tool.py +2 -2
  15. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_rubric_judge.py +1 -1
  16. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_sampling.py +1 -3
  17. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_scoring_network.py +1 -1
  18. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_shared_tool.py +2 -2
  19. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_single_turn.py +2 -2
  20. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_skills.py +2 -2
  21. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_tool_vms.py +1 -1
  22. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_user_echo.py +2 -2
  23. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/conftest.py +8 -0
  24. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/runtimes/test_private_network.py +4 -4
  25. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_agent.py +50 -17
  26. verifiers-0.4.1.dev52/tests/unit/test_runtimes.py +543 -0
  27. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_scoring_network.py +1 -1
  28. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/utils/test_compile.py +1 -1
  29. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/__init__.py +2 -4
  30. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/acp/__init__.py +1 -5
  31. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/agent.py +11 -12
  32. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/grading.py +6 -3
  33. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/mini_swe_agent/harness.py +1 -1
  34. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/openclaw/harness.py +41 -8
  35. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/terminus_2/harness.py +1 -1
  36. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/launch.py +1 -1
  37. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/tunnel/prime.py +1 -2
  38. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/mcp/launch.py +22 -6
  39. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/mcp/toolset.py +3 -3
  40. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/rollout.py +9 -6
  41. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/__init__.py +32 -56
  42. verifiers-0.4.1.dev52/verifiers/v1/runtimes/backends/custom.py +93 -0
  43. verifiers-0.4.1.dev52/verifiers/v1/runtimes/backends/docker.py +874 -0
  44. {verifiers-0.4.1.dev50/verifiers/v1/runtimes → verifiers-0.4.1.dev52/verifiers/v1/runtimes/backends}/prime.py +13 -16
  45. {verifiers-0.4.1.dev50/verifiers/v1/runtimes → verifiers-0.4.1.dev52/verifiers/v1/runtimes/backends}/subprocess.py +23 -37
  46. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/base.py +87 -63
  47. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/compose.py +53 -56
  48. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/deployment.py +1 -3
  49. {verifiers-0.4.1.dev50/verifiers/v1/runtimes/docker → verifiers-0.4.1.dev52/verifiers/v1/runtimes}/egress.py +0 -25
  50. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/limiters.py +2 -2
  51. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/private_network.py +1 -1
  52. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/runtime.py +21 -26
  53. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/runtimes/strategies.py +6 -4
  54. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/task.py +1 -1
  55. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/compile.py +22 -35
  56. verifiers-0.4.1.dev50/tests/unit/runtimes/test_e2b.py +0 -79
  57. verifiers-0.4.1.dev50/verifiers/v1/runtimes/apptainer.py +0 -216
  58. verifiers-0.4.1.dev50/verifiers/v1/runtimes/container.py +0 -336
  59. verifiers-0.4.1.dev50/verifiers/v1/runtimes/docker/__init__.py +0 -589
  60. verifiers-0.4.1.dev50/verifiers/v1/runtimes/e2b.py +0 -724
  61. verifiers-0.4.1.dev50/verifiers/v1/runtimes/modal.py +0 -443
  62. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/.gitignore +0 -0
  63. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/LICENSE +0 -0
  64. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/README.md +0 -0
  65. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/agent_user_harness.py +0 -0
  66. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/counter_tool.py +0 -0
  67. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/duet.py +0 -0
  68. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo.py +0 -0
  69. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo_acp_resume.py +0 -0
  70. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo_agentic.py +0 -0
  71. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo_tool.py +0 -0
  72. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
  73. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/echo_user_sim.py +0 -0
  74. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/fetch_tool.py +0 -0
  75. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/network_policy.py +0 -0
  76. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/parallel.py +0 -0
  77. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/pyproject.toml +0 -0
  78. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/skill_codeword.py +0 -0
  79. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
  80. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/fixtures/tool_response_image.py +0 -0
  81. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_examples.py +0 -0
  82. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_multi_agent.py +0 -0
  83. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_parallel.py +0 -0
  84. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_stateful_tool.py +0 -0
  85. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/integration/test_user_sim.py +0 -0
  86. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/cli/test_replay.py +0 -0
  87. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/harnesses/test_core.py +0 -0
  88. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/harnesses/test_rlm.py +0 -0
  89. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/interception/test_tunnel.py +0 -0
  90. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/judges/conftest.py +0 -0
  91. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/judges/test_judge.py +0 -0
  92. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/judges/test_reference.py +0 -0
  93. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/judges/test_rubric.py +0 -0
  94. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/serve/test_client.py +0 -0
  95. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/serve/test_delta.py +0 -0
  96. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/serve/test_pool.py +0 -0
  97. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_dialects.py +0 -0
  98. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_graph.py +0 -0
  99. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_harbor_grading_network.py +0 -0
  100. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_semantic.py +0 -0
  101. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_task.py +0 -0
  102. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_taskset.py +0 -0
  103. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/test_trace.py +0 -0
  104. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/utils/test_loaders.py +0 -0
  105. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/utils/test_platform.py +0 -0
  106. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/tests/unit/utils/test_score.py +0 -0
  107. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/__init__.py +0 -0
  108. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/acp/runner.py +0 -0
  109. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/__init__.py +0 -0
  110. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/dashboard/__init__.py +0 -0
  111. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/dashboard/base.py +0 -0
  112. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/dashboard/eval.py +0 -0
  113. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/dashboard/replay.py +0 -0
  114. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/dashboard/validate.py +0 -0
  115. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/debug.py +0 -0
  116. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/eval/__init__.py +0 -0
  117. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/eval/hint.py +0 -0
  118. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/eval/main.py +0 -0
  119. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/eval/resume.py +0 -0
  120. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/eval/runner.py +0 -0
  121. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/gepa.py +0 -0
  122. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/output.py +0 -0
  123. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/replay.py +0 -0
  124. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/resolve.py +0 -0
  125. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/resume.py +0 -0
  126. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/cli/validate.py +0 -0
  127. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/clients/__init__.py +0 -0
  128. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/clients/base.py +0 -0
  129. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/clients/client.py +0 -0
  130. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/clients/eval.py +0 -0
  131. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/clients/train.py +0 -0
  132. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/__init__.py +0 -0
  133. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/agent.py +0 -0
  134. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/__init__.py +0 -0
  135. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/debug.py +0 -0
  136. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/env.py +0 -0
  137. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/eval.py +0 -0
  138. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/replay.py +0 -0
  139. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/cli/validate.py +0 -0
  140. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/client.py +0 -0
  141. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/env.py +0 -0
  142. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/harness.py +0 -0
  143. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/judge.py +0 -0
  144. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/retries.py +0 -0
  145. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/runtime.py +0 -0
  146. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/scoring.py +0 -0
  147. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/select.py +0 -0
  148. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/serve.py +0 -0
  149. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/task.py +0 -0
  150. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/configs/taskset.py +0 -0
  151. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/dialects/__init__.py +0 -0
  152. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/dialects/anthropic.py +0 -0
  153. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/dialects/base.py +0 -0
  154. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/dialects/chat.py +0 -0
  155. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/dialects/responses.py +0 -0
  156. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/env.py +0 -0
  157. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/__init__.py +0 -0
  158. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
  159. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/agentic_judge/env.py +0 -0
  160. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
  161. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/best_of_n/env.py +0 -0
  162. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/single_agent/__init__.py +0 -0
  163. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/single_agent/env.py +0 -0
  164. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/user_sim/__init__.py +0 -0
  165. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/envs/user_sim/env.py +0 -0
  166. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/episode.py +0 -0
  167. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/errors.py +0 -0
  168. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/__init__.py +0 -0
  169. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/adapter.py +0 -0
  170. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/config.py +0 -0
  171. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/dataset.py +0 -0
  172. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/reflection.py +0 -0
  173. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/gepa/runner.py +0 -0
  174. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/graph.py +0 -0
  175. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harness.py +0 -0
  176. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/__init__.py +0 -0
  177. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/bash/__init__.py +0 -0
  178. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/bash/harness.py +0 -0
  179. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
  180. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
  181. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/browser_use/program.py +0 -0
  182. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
  183. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
  184. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/codex/__init__.py +0 -0
  185. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
  186. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/codex/harness.py +0 -0
  187. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
  188. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
  189. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
  190. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
  191. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
  192. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
  193. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
  194. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
  195. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
  196. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
  197. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
  198. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/node.py +0 -0
  199. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/null/__init__.py +0 -0
  200. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/null/harness.py +0 -0
  201. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
  202. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
  203. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/opencode/harness.py +0 -0
  204. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
  205. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/pi/__init__.py +0 -0
  206. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
  207. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/pi/harness.py +0 -0
  208. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
  209. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
  210. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
  211. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/rlm/harness.py +0 -0
  212. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
  213. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
  214. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/__init__.py +0 -0
  215. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/compaction.py +0 -0
  216. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/core.py +0 -0
  217. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/install.py +0 -0
  218. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/mcp.py +0 -0
  219. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/harnesses/utils/replay.py +0 -0
  220. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/__init__.py +0 -0
  221. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/base.py +0 -0
  222. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/pool.py +0 -0
  223. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/server.py +0 -0
  224. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/tunnel/__init__.py +0 -0
  225. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/tunnel/base.py +0 -0
  226. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/interception/tunnel/custom.py +0 -0
  227. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judge.py +0 -0
  228. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/__init__.py +0 -0
  229. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/decision.py +0 -0
  230. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/reference.py +0 -0
  231. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/reference.txt +0 -0
  232. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/rubric.py +0 -0
  233. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/judges/rubric.txt +0 -0
  234. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/mcp/__init__.py +0 -0
  235. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/mcp/server.py +0 -0
  236. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/semantic.py +0 -0
  237. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/__init__.py +0 -0
  238. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/client.py +0 -0
  239. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/delta.py +0 -0
  240. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/encoding.py +0 -0
  241. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/pool.py +0 -0
  242. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/server.py +0 -0
  243. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/serve/types.py +0 -0
  244. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/session.py +0 -0
  245. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/state.py +0 -0
  246. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/taskset.py +0 -0
  247. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/__init__.py +0 -0
  248. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
  249. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
  250. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
  251. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
  252. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
  253. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
  254. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
  255. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
  256. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
  257. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
  258. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
  259. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
  260. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/trace.py +0 -0
  261. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/types.py +0 -0
  262. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/__init__.py +0 -0
  263. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/aio.py +0 -0
  264. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/artifacts.py +0 -0
  265. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/decorators.py +0 -0
  266. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/env.py +0 -0
  267. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/eval.py +0 -0
  268. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/format.py +0 -0
  269. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/generic.py +0 -0
  270. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/git.py +0 -0
  271. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/image.py +0 -0
  272. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/interrupt.py +0 -0
  273. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/loaders.py +0 -0
  274. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/logging.py +0 -0
  275. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/memory.py +0 -0
  276. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/paths.py +0 -0
  277. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/platform.py +0 -0
  278. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/prime.py +0 -0
  279. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/retries.py +0 -0
  280. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/scope.py +0 -0
  281. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/score.py +0 -0
  282. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/trace_store.py +0 -0
  283. {verifiers-0.4.1.dev50 → verifiers-0.4.1.dev52}/verifiers/v1/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.4.1.dev50
3
+ Version: 0.4.1.dev52
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
@@ -46,12 +46,8 @@ Requires-Dist: tenacity>=8.5.0
46
46
  Requires-Dist: tomli-w>=1.0.0
47
47
  Requires-Dist: typing-extensions>=4.12.2
48
48
  Requires-Dist: uvicorn>=0.52.0
49
- Provides-Extra: e2b
50
- Requires-Dist: e2b<3,>=2.35.0; extra == 'e2b'
51
49
  Provides-Extra: harbor
52
50
  Requires-Dist: harbor==0.24.0; (python_full_version >= '3.12') and extra == 'harbor'
53
- Provides-Extra: modal
54
- Requires-Dist: modal>=1.5.4; extra == 'modal'
55
51
  Provides-Extra: openenv
56
52
  Requires-Dist: openenv>=0.4.1; extra == 'openenv'
57
53
  Provides-Extra: ta
@@ -96,14 +96,6 @@ harbor = [
96
96
  # Harbor currently publishes Python 3.12+ packages; keep core verifiers installable on 3.11.
97
97
  "harbor==0.24.0 ; python_full_version >= '3.12'",
98
98
  ]
99
- modal = [
100
- "modal>=1.5.4",
101
- ]
102
- e2b = [
103
- # <3: the runtime swaps the SDK command handle's private stream decoders for
104
- # byte-accurate live output (see runtimes/e2b.py _byte_handle).
105
- "e2b>=2.35.0,<3",
106
- ]
107
99
  openenv = [
108
100
  "openenv>=0.4.1",
109
101
  ]
@@ -225,11 +217,7 @@ markers = [
225
217
  # is applied per axis, so it matches every cell touching that value on any axis.
226
218
  "subprocess: integration cells touching the subprocess (host) runtime",
227
219
  "docker: integration cells touching the docker runtime",
228
- "podman: integration cells touching the podman runtime (needs the engine on the host; local-only)",
229
- "apptainer: integration cells touching the apptainer runtime (needs the engine on the host; local-only)",
230
220
  "prime: integration cells touching the prime runtime (real sandbox + tunnel)",
231
- "modal: integration cells touching the modal runtime (external sandbox; local-only, excluded in CI)",
232
- "e2b: integration cells touching the e2b runtime (external sandbox; local-only, excluded in CI)",
233
221
  "colocated: integration cells with a tool server colocated in the harness runtime",
234
222
  "service: integration cells with a tool server in a Compose service beside the harness",
235
223
  "null: integration cells on the null harness",
@@ -5,8 +5,8 @@ model-driven tests skip.
5
5
 
6
6
  Each behavior module fixes one task and fans it across the harness x runtime grid in
7
7
  `grid.py`, which also says why a cell is skipped. `run` drives the `Env` API in-process,
8
- the calls the eval CLI makes. The placement fixtures below are indirect-only: they translate a parametrized value, and using one without
9
- `indirect=True` fails loudly.
8
+ the calls the eval CLI makes. The placement fixtures below are indirect-only: they
9
+ translate a parametrized value, and using one without `indirect=True` fails loudly.
10
10
  """
11
11
 
12
12
  import asyncio
@@ -54,7 +54,7 @@ def tool_runtime(request) -> dict:
54
54
  return {"service": "tools"}
55
55
  if request.param == "service-vm":
56
56
  return {"service": "tools-vm"}
57
- return {"runtime": {"type": request.param}}
57
+ return {"runtime": runtime_config(request.param)}
58
58
 
59
59
 
60
60
  # Built-in harnesses are bundled in the `harnesses` package; the agent CLIs (`rlm` /
@@ -180,7 +180,7 @@ def run():
180
180
  makes (`serving`, `slots`, `run_slot`, retries included), without its run
181
181
  directory, platform push, or dashboard. The Examples job covers that CLI layer."""
182
182
 
183
- async def _run(taskset: str, **kwargs) -> list[Episode]:
183
+ async def _episodes(taskset: str, **kwargs) -> list[Episode]:
184
184
  config = _eval_config(taskset, **kwargs)
185
185
  env = load_environment(config.env)
186
186
  tasks = list(env.taskset.select(config.select))
@@ -198,7 +198,7 @@ def run():
198
198
  )
199
199
  )
200
200
 
201
- return _run
201
+ return _episodes
202
202
 
203
203
 
204
204
  @pytest.fixture
@@ -90,7 +90,7 @@ class ScriptedAgentUserHarness(Harness[HarnessConfig]):
90
90
  "uv_script": script[-1],
91
91
  "read_secret_api": read_api,
92
92
  }
93
- return await runtime.run_program(["sh", "-c", PROBE], {})
93
+ return await runtime.run(["sh", "-c", PROBE], {})
94
94
 
95
95
 
96
96
  class AgentUserData(vf.TaskData):
@@ -2,35 +2,31 @@
2
2
  cell is skipped.
3
3
 
4
4
  Each behavior module fixes one task and fans it over `grid(...)`: every bundled harness
5
- x every runtime kind. The harness grid runs one local container engine (`docker`);
6
- `podman` / `apptainer` share its container runtime code and are exercised by the
7
- runtime-only grids (`placements`, `runtimes_grid`), where the harness is fixed. A cell
8
- the stack cannot run is collected as a skip with its reason. Every reason derives from a
9
- capability the code declares, never from a list of names, so the grid follows the code:
10
-
11
- - `Harness.NEEDS_CONTAINER`: the harness never runs on the host (`subprocess`)
12
- - `Harness.EXECUTES_CODE`, `SUPPORTS_MCP`, `SUPPORTS_SKILLS`, resume support
13
- (`SUPPORTS_RESUME` or a native session): the behavior needs a shell, MCP tools,
14
- skills, or a resumable exchange
15
- - `RuntimeBackend.supports_user`, `RuntimeBackend.supports_expose`, `NetworkPolicyConfig`: the
16
- behavior needs a user switch, a tool server reachable from another runtime, or a
17
- network policy
18
- - `podman` / `apptainer` need their engine on the host
19
-
20
- CI deselects `podman`, `apptainer`, `modal` and `e2b` by mark: local engines and external
21
- sandboxes.
5
+ on Prime, the production runtime. The basic single- and multi-turn behaviors also run
6
+ on the host (`DEBUG_RUNTIMES`), which needs no container. Docker cells run on the CI
7
+ runner itself and make the jobs too slow, so the Docker runtime is covered by
8
+ `tests/unit/test_runtimes.py` instead. Every reason a cell cannot run derives
9
+ from a capability the code declares, never from a list of names, so the grid follows
10
+ the code.
11
+
12
+ A harness without a capability the behavior needs is collected as a skip with its
13
+ reason (`Harness.EXECUTES_CODE`, `SUPPORTS_MCP`, `SUPPORTS_SKILLS`, resume support via
14
+ `SUPPORTS_RESUME` or a native session).
15
+
16
+ A runtime without a feature the behavior needs (`RuntimeBackend.SUPPORTS_*`, or a
17
+ `NetworkPolicyConfig` for a network policy) skips the cell the same way. That a runtime
18
+ refuses an undeclared feature, with a message naming it, is tested in
19
+ `tests/unit/test_runtimes.py`.
22
20
 
23
21
  Every cell carries its axes' marks, so `-m` selects subsets:
24
22
 
25
- uv run pytest tests/integration -n 8 -m "not podman and not apptainer and not modal and not e2b" # CI
26
- uv run pytest tests/integration -n 8 -m "docker and codex"
27
- uv run pytest tests/integration -n 8 -m e2b # local
23
+ uv run pytest tests/integration -n 8 -m "prime and codex"
24
+ uv run pytest tests/integration -n 8 -m prime
28
25
 
29
26
  `terminus-2` (drives the host tmux) and `browser-use` (needs its Playwright image, which
30
27
  prime cannot pull) stay outside the grid.
31
28
  """
32
29
 
33
- import shutil
34
30
  from collections.abc import Sequence
35
31
  from typing import get_args
36
32
 
@@ -40,7 +36,7 @@ from pydantic import TypeAdapter
40
36
  import verifiers.v1 as vf
41
37
  from verifiers.v1.configs.runtime import NetworkPolicyConfig
42
38
  from verifiers.v1.harness import Harness
43
- from verifiers.v1.runtimes import RuntimeConfig, _backend_cls
39
+ from verifiers.v1.runtimes import RuntimeConfig, backend_cls
44
40
  from verifiers.v1.utils.loaders import harness_class, harness_config_type
45
41
 
46
42
  HARNESSES: list[str | dict] = [
@@ -58,20 +54,48 @@ HARNESSES: list[str | dict] = [
58
54
  "mini-swe-agent",
59
55
  "prime-agent",
60
56
  ]
61
- RUNTIMES = ["subprocess", "docker", "podman", "apptainer", "prime", "modal", "e2b"]
62
- ENGINES = ("podman", "apptainer")
63
- HARNESS_RUNTIMES = [runtime for runtime in RUNTIMES if runtime not in ENGINES]
64
- # Runtimes whose VMs run a task's Compose services.
65
- COMPOSE_VMS = ("prime", "modal")
57
+ DEBUG_RUNTIMES = ("subprocess",)
58
+ RUNTIMES = (*DEBUG_RUNTIMES, "prime")
59
+
60
+ # The runtime features a behavior can need, as `needs` names them.
61
+ RUNTIME_FEATURES = {
62
+ "container": "task images",
63
+ "user": "running as another user",
64
+ "network": "network policies",
65
+ "expose": "port exposure",
66
+ "compose": "Compose services",
67
+ }
66
68
 
67
69
  # Harnesses that cannot run against the CI model yet.
68
70
  # TODO: drop each entry once its fix lands.
69
71
  CI_MODEL_GAPS = {
70
72
  "kimi-code": "Prime chat completions rejects kimi-code's prompt_cache_key",
71
- "openclaw": "openclaw cannot load the custom `internal/` model provider",
72
73
  }
73
74
 
74
75
 
76
+ # Harnesses whose program rewrites earlier turns by design, so a rollout can record
77
+ # several branches. Each test names the ones it lets fork. Recheck on version bumps.
78
+ FORKS = {
79
+ # Acts only through tool calls: it drops a tool-less reply from its history and
80
+ # resends only its format error.
81
+ "mini-swe-agent": "https://github.com/SWE-agent/mini-swe-agent/blob/v2.4.6/src/minisweagent/agents/default.py#L114",
82
+ # Moves its runtime-context message to the tail of every request and drops the
83
+ # earlier one, unless the provider's replay policy is append-only.
84
+ "openclaw": "https://github.com/openclaw/openclaw/blob/v2026.9.5/src/agents/internal-runtime-context.ts#L402-L408",
85
+ }
86
+
87
+
88
+ def assert_one_branch(
89
+ trace: vf.Trace, harness: vf.HarnessConfig, forks: Sequence[str] = ()
90
+ ) -> None:
91
+ """A rollout records one branch, unless its harness is one of `forks` (see `FORKS`)."""
92
+ assert set(forks) <= FORKS.keys(), (
93
+ f"no FORKS reason for {set(forks) - FORKS.keys()}"
94
+ )
95
+ if harness.id not in forks:
96
+ assert trace.num_branches == 1, f"{trace.num_branches} branches"
97
+
98
+
75
99
  def agent_seats(taskset: str, env_id: str = "") -> list[str]:
76
100
  """The agent seats the env declares for `taskset`: `agent` for a plain taskset, its
77
101
  own roles for a recipe env."""
@@ -94,26 +118,31 @@ def mark(name: str) -> pytest.MarkDecorator:
94
118
  def runtime_config(runtime: str, harness: str | dict | None = None) -> dict:
95
119
  config: dict = {"type": runtime}
96
120
  program = harness is not None and harness_class(harness_id(harness)).NEEDS_CONTAINER
97
- # The default sandboxes are too small to install and run an agent CLI: e2b's box
98
- # starves rlm's ACP startup, and prime's 1 CPU / 2 GB gets openclaw terminated.
99
- if runtime == "e2b":
100
- config["memory"] = 2.0
121
+ # Prime's default 1 CPU / 2 GB is too small to install and run an agent CLI.
101
122
  if runtime == "prime" and program:
102
123
  config.update(cpu=2.0, memory=4.0)
103
124
  return config
104
125
 
105
126
 
106
127
  def runtime_cls(runtime: str) -> type:
107
- return _backend_cls(TypeAdapter(RuntimeConfig).validate_python({"type": runtime}))
108
-
109
-
110
- def runtime_supports_user(runtime: str) -> bool:
111
- return runtime_cls(runtime).supports_user
128
+ return backend_cls(
129
+ TypeAdapter(RuntimeConfig).validate_python(runtime_config(runtime))
130
+ )
112
131
 
113
132
 
114
- def runtime_supports_network_policy(runtime: str) -> bool:
115
- config = TypeAdapter(RuntimeConfig).validate_python({"type": runtime})
116
- return isinstance(config, NetworkPolicyConfig)
133
+ def supports(runtime: str, feature: str) -> bool:
134
+ """Whether the runtime declares `feature`: a backend flag, or, for a network policy,
135
+ a config that inherits `NetworkPolicyConfig`."""
136
+ if feature == "network":
137
+ config = TypeAdapter(RuntimeConfig).validate_python(runtime_config(runtime))
138
+ return isinstance(config, NetworkPolicyConfig)
139
+ flag = {
140
+ "container": "SUPPORTS_TASK_IMAGES",
141
+ "user": "SUPPORTS_USER_SWITCHING",
142
+ "expose": "SUPPORTS_PORT_EXPOSURE",
143
+ "compose": "SUPPORTS_COMPOSE",
144
+ }[feature]
145
+ return getattr(runtime_cls(runtime), flag)
117
146
 
118
147
 
119
148
  def resumes(cls: type[Harness]) -> bool:
@@ -129,13 +158,10 @@ def resumes(cls: type[Harness]) -> bool:
129
158
  def unsupported(
130
159
  harness: str | dict, runtime: str, needs: tuple[str, ...]
131
160
  ) -> str | None:
132
- """Why this cell cannot run, or None when it can."""
161
+ """Why this cell cannot run, or None when it can: a capability the behavior needs
162
+ that the harness or the runtime does not declare."""
133
163
  name = harness_id(harness)
134
164
  cls = harness_class(name)
135
- if runtime in ENGINES and shutil.which(runtime) is None:
136
- return f"needs {runtime} on the host"
137
- if runtime == "subprocess" and cls.NEEDS_CONTAINER:
138
- return f"{name} needs a container runtime"
139
165
  if "shell" in needs and not cls.EXECUTES_CODE:
140
166
  return f"{name} gives the model no shell"
141
167
  if "mcp" in needs and not cls.SUPPORTS_MCP:
@@ -144,43 +170,48 @@ def unsupported(
144
170
  return f"{name} has no native skill support"
145
171
  if "resume" in needs and not resumes(cls):
146
172
  return f"{name} cannot resume an exchange"
147
- if "user" in needs and not runtime_supports_user(runtime):
148
- return f"{runtime} cannot run commands as another user"
149
- if "network" in needs and not runtime_supports_network_policy(runtime):
150
- return f"{runtime} has no network policy"
151
- return None
173
+ runtime_needs = (*(("container",) if cls.NEEDS_CONTAINER else ()), *needs)
174
+ for feature in runtime_needs:
175
+ if feature in RUNTIME_FEATURES and not supports(runtime, feature):
176
+ return f"{runtime} does not support {RUNTIME_FEATURES[feature]}"
177
+ return CI_MODEL_GAPS.get(name)
178
+
179
+
180
+ def cell_marks(
181
+ harness: str | dict, runtime: str, needs: tuple[str, ...]
182
+ ) -> list[pytest.MarkDecorator]:
183
+ if reason := unsupported(harness, runtime, needs):
184
+ return [pytest.mark.skip(reason=reason)]
185
+ return []
152
186
 
153
187
 
154
188
  def runtimes_grid(
155
- runtimes: Sequence[str] = RUNTIMES, *, needs: tuple[str, ...] = ()
189
+ runtimes: Sequence[str] = ("prime",), *, needs: tuple[str, ...] = ()
156
190
  ) -> list:
157
191
  """`harness_runtime` cells for a behavior with no harness axis."""
158
192
  cells = []
159
193
  for runtime in runtimes:
160
- marks = [mark(runtime)]
161
- if reason := unsupported("null", runtime, needs):
162
- marks.append(pytest.mark.skip(reason=reason))
194
+ marks = [mark(runtime), *cell_marks("null", runtime, needs)]
163
195
  cells.append(pytest.param(runtime, marks=marks, id=f"harness-in-{runtime}"))
164
196
  return cells
165
197
 
166
198
 
167
199
  def grid(
168
200
  harnesses: Sequence[str | dict] = HARNESSES,
169
- runtimes: Sequence[str] = HARNESS_RUNTIMES,
201
+ runtimes: Sequence[str] = ("prime",),
170
202
  *,
171
203
  needs: tuple[str, ...] = (),
172
204
  ) -> list:
173
- """`(harness, harness_runtime)` cells, each marked by its axes and skipped with a
174
- reason where the behavior's `needs` or the runtime rule it out."""
205
+ """`(harness, harness_runtime)` cells, each marked by its axes, skipped where the
206
+ harness or the runtime rules the behavior out."""
175
207
  cells = []
176
208
  for harness in harnesses:
177
209
  for runtime in runtimes:
178
- marks = [mark(harness_id(harness)), mark(runtime)]
179
- reason = unsupported(harness, runtime, needs) or CI_MODEL_GAPS.get(
180
- harness_id(harness)
181
- )
182
- if reason:
183
- marks.append(pytest.mark.skip(reason=reason))
210
+ marks = [
211
+ mark(harness_id(harness)),
212
+ mark(runtime),
213
+ *cell_marks(harness, runtime, needs),
214
+ ]
184
215
  cells.append(
185
216
  pytest.param(
186
217
  harness,
@@ -239,45 +270,30 @@ def skip_harness(cells: list, harness: str, reason: str) -> list:
239
270
 
240
271
 
241
272
  def placements(
242
- harness_runtimes: tuple[str, ...] = tuple(RUNTIMES),
243
- tool_runtimes: tuple[str, ...] = ("colocated", *RUNTIMES),
273
+ harness_runtimes: tuple[str, ...] = ("prime",),
274
+ tool_runtimes: tuple[str, ...] = ("colocated", "subprocess", "prime"),
244
275
  *,
245
276
  shared: bool = False,
246
277
  ) -> list:
247
278
  """`(harness_runtime, tool_runtime)` cells for a tool server placed colocated in the
248
279
  harness's box, in a Compose service beside it (`service`), or in its own runtime
249
- (on Prime beside a Prime harness, a VM on the rollout's private network). A `shared`
250
- server runs once per eval, so it joins no rollout's network."""
280
+ (on Prime beside a Prime harness, a VM on the rollout's private network). A
281
+ `subprocess` tool runtime is a server on the host, reached from the sandbox through
282
+ the tunnel. A `shared` server runs once per eval, so it joins no rollout's network."""
251
283
  cells = []
252
284
  for harness_runtime in harness_runtimes:
253
285
  for tool_runtime in tool_runtimes:
254
286
  marks = [mark(harness_runtime), mark(tool_runtime)]
255
- missing = [
256
- engine
257
- for engine in {harness_runtime, tool_runtime} & set(ENGINES)
258
- if shutil.which(engine) is None
259
- ]
260
- if missing:
261
- marks.append(pytest.mark.skip(reason=f"needs {missing[0]} on the host"))
262
- elif tool_runtime == "service" and harness_runtime not in COMPOSE_VMS:
263
- marks.append(
264
- pytest.mark.skip(
265
- reason="a tool server in a Compose service needs Compose on a "
266
- "Prime or Modal VM"
267
- )
268
- )
269
- elif (
270
- tool_runtime not in ("colocated", "service")
271
- and not runtime_cls(tool_runtime).supports_expose
272
- # Beside a Prime harness, a rollout's Prime server joins its private network.
273
- and not (not shared and tool_runtime == harness_runtime == "prime")
287
+ reason = None
288
+ if tool_runtime == "service":
289
+ reason = unsupported("null", harness_runtime, ("compose",))
290
+ # Beside a Prime harness, a rollout's Prime server joins its private network.
291
+ elif tool_runtime != "colocated" and not (
292
+ not shared and tool_runtime == harness_runtime == "prime"
274
293
  ):
275
- marks.append(
276
- pytest.mark.skip(
277
- reason=f"{tool_runtime} cannot expose a port; a tool server "
278
- "there is reachable only colocated"
279
- )
280
- )
294
+ reason = unsupported("null", tool_runtime, ("expose",))
295
+ if reason:
296
+ marks.append(pytest.mark.skip(reason=reason))
281
297
  cells.append(
282
298
  pytest.param(
283
299
  harness_runtime,
@@ -3,7 +3,7 @@
3
3
  upstream (agent-user-harness), on the runtimes that can switch users."""
4
4
 
5
5
  import pytest
6
- from grid import grid, runtimes_grid
6
+ from grid import assert_one_branch, grid, runtimes_grid
7
7
 
8
8
 
9
9
  @pytest.mark.parametrize(
@@ -52,11 +52,6 @@ async def test_agent_user_harness(run, harness, harness_runtime, scripted_model)
52
52
  client=scripted_model,
53
53
  )
54
54
  (trace,) = episode.traces
55
- # mini-swe-agent only acts through tool calls: it drops a tool-less reply (the
56
- # scripted "OK") from its history and resends only its format error, so the
57
- # trace forks by design. Recheck on version bumps:
58
- # https://github.com/SWE-agent/mini-swe-agent/blob/v2.4.6/src/minisweagent/agents/default.py#L114
59
- if harness.id != "mini-swe-agent":
60
- assert trace.num_branches == 1
55
+ assert_one_branch(trace, harness, forks=("mini-swe-agent",))
61
56
  assert trace.ok, [error.message for error in trace.errors]
62
57
  assert trace.num_turns >= 1
@@ -13,7 +13,7 @@ async def test_agentic_judge_shared_verifier(run, tmp_path):
13
13
  "id": "agentic-judge",
14
14
  "solver": {
15
15
  "harness": {"id": "bash"},
16
- "runtime": {"type": "docker", "block": ["example.com"]},
16
+ "runtime": {"type": "prime", "block": ["example.com"]},
17
17
  "scoring": {"mode": "shared"},
18
18
  },
19
19
  "judge": {
@@ -59,7 +59,7 @@ async def test_env_id_agentic_judge(run, tmp_path):
59
59
  "id": "agentic-judge",
60
60
  "solver": {
61
61
  "harness": {"id": "bash"},
62
- "runtime": {"type": "docker", "block": ["example.com"]},
62
+ "runtime": {"type": "prime", "block": ["example.com"]},
63
63
  "scoring": {"mode": "isolated"},
64
64
  },
65
65
  "judge": {
@@ -84,7 +84,7 @@ async def test_env_id_agentic_judge(run, tmp_path):
84
84
  assert judge.agent.trainable is False
85
85
  assert solver.agent.runtime is not None and judge.agent.runtime is not None
86
86
  assert solver.agent.runtime.id != judge.agent.runtime.id
87
- assert solver.agent.runtime.type == judge.agent.runtime.type == "docker"
87
+ assert solver.agent.runtime.type == judge.agent.runtime.type == "prime"
88
88
  assert "/app/answer.txt" in solver.state.artifacts
89
89
  assert solver.rewards["wrote_phrase"].score == 1.0
90
90
  assert solver.rewards["wrote_phrase"].weight == 0.5
@@ -1,12 +1,12 @@
1
- """Compose scoring uses live shared services or a released, collected submission."""
1
+ """Compose scoring uses live shared services or a released, collected submission, on
2
+ a Prime VM."""
2
3
 
3
- import shutil
4
+ import os
4
5
 
5
6
  import pytest
6
7
 
7
8
  import verifiers.v1 as vf
8
9
  from verifiers.v1.configs.agent import TimeoutConfig
9
- from verifiers.v1.runtimes.container import cli
10
10
  from verifiers.v1.tasksets.harbor.taskset import (
11
11
  CollectHook,
12
12
  HarborArtifact,
@@ -14,10 +14,8 @@ from verifiers.v1.tasksets.harbor.taskset import (
14
14
  HarborTask,
15
15
  )
16
16
 
17
- pytestmark = [
18
- pytest.mark.docker,
19
- pytest.mark.skipif(not shutil.which("docker"), reason="needs Docker"),
20
- ]
17
+ # Solver service backends by trace id, to check their VM is gone before grading.
18
+ SOLVERS: dict[str, list] = {}
21
19
 
22
20
  IMAGE = "python:3.11-slim"
23
21
  COMPOSE = f"""
@@ -44,7 +42,7 @@ services:
44
42
 
45
43
  class ComposeHarness(vf.Harness):
46
44
  async def launch(self, ctx, trace, runtime, endpoint, secret, mcp_urls, data):
47
- return await runtime.run_program(
45
+ return await runtime.run(
48
46
  [
49
47
  "python",
50
48
  "-c",
@@ -61,23 +59,18 @@ class ComposeTask(HarborTask):
61
59
  async def setup(self, trace, runtime, deployment=None):
62
60
  await super().setup(runtime)
63
61
  if deployment is not None:
64
- trace.info["solver_containers"] = [
65
- runtime.info.id for runtime in deployment.target_backends.values()
66
- ]
62
+ SOLVERS[trace.id] = list(deployment.target_backends.values())
67
63
  else:
68
- # Fresh verifier setup happens only after the solver project is removed.
69
- for container in trace.info["solver_containers"]:
70
- result = await cli("docker", "inspect", container)
71
- assert result.exit_code != 0, "solver service survived into grading"
64
+ # Fresh verifier setup happens only after the solver VM is removed.
65
+ assert all(
66
+ backend._host_backend.stopped for backend in SOLVERS[trace.id]
67
+ ), "solver services survived into grading"
72
68
  trace.info["solver_released_before_grading"] = True
73
69
 
74
70
  async def finalize_services(self, trace, targets):
75
- result = await cli(
76
- "docker",
77
- "inspect",
78
- "--format",
79
- "{{.State.Running}}",
80
- targets["main"].info.id,
71
+ main = targets["main"].backend
72
+ result = await main._run_host(
73
+ "docker", "inspect", "--format", "{{.State.Running}}", main._container
81
74
  )
82
75
  assert result.stdout.strip() == "false", (
83
76
  "workspace must stop before sidecar collection"
@@ -101,7 +94,43 @@ class ComposeTask(HarborTask):
101
94
  "isolated-scoring-timeout",
102
95
  ],
103
96
  )
97
+ @pytest.mark.prime
98
+ @pytest.mark.skipif(not os.environ.get("PRIME_API_KEY"), reason="needs PRIME_API_KEY")
104
99
  async def test_compose_scoring(tmp_path, mode, collect_fails, scoring_timeout):
100
+ task = compose_task(tmp_path, collect_fails, scoring_timeout, mode)
101
+ config = vf.AgentConfig(
102
+ model="unused",
103
+ runtime=vf.PrimeConfig(labels=["vf-ci"]),
104
+ scoring=vf.ScoringConfig(
105
+ mode=mode,
106
+ env={"EXPECT_SIDECAR": "1" if mode == "isolated" else "0"},
107
+ retries=vf.RetryConfig(max_retries=0),
108
+ ),
109
+ timeout=TimeoutConfig(
110
+ setup=600, finalize=60, scoring=1 if scoring_timeout else 120
111
+ ),
112
+ )
113
+ async with vf.Agent(config) as agent:
114
+ agent.harness = ComposeHarness(vf.HarnessConfig())
115
+ trace = await agent.run(task)
116
+ assert all(backend._host_backend.stopped for backend in SOLVERS.pop(trace.id, []))
117
+ if mode == "isolated" and collect_fails:
118
+ assert not trace.ok
119
+ assert "collect hook failed" in str(trace.errors)
120
+ assert "solver_released_before_grading" not in trace.info
121
+ elif scoring_timeout:
122
+ assert trace.ok and trace.is_timeout and not trace.errors
123
+ assert trace.stop_condition == "scoring_timeout"
124
+ assert all(reward is None for reward in trace.rewards.values())
125
+ else:
126
+ assert trace.ok and trace.reward == 1, trace.errors
127
+ assert bool(trace.info.get("collected_sidecars")) == (mode == "isolated")
128
+ assert bool(trace.info.get("solver_released_before_grading")) == (
129
+ mode == "isolated"
130
+ )
131
+
132
+
133
+ def compose_task(tmp_path, collect_fails: bool, scoring_timeout: bool, mode: str):
105
134
  environment = tmp_path / "environment"
106
135
  environment.mkdir()
107
136
  (environment / "docker-compose.yaml").write_text(COMPOSE)
@@ -114,7 +143,7 @@ async def test_compose_scoring(tmp_path, mode, collect_fails, scoring_timeout):
114
143
  + ("sleep 30\n" if scoring_timeout else "")
115
144
  + "echo 1 > /logs/verifier/reward.txt\n"
116
145
  )
117
- task = ComposeTask(
146
+ return ComposeTask(
118
147
  HarborData(
119
148
  prompt="Copy the sidecar answer",
120
149
  task_dir=str(tmp_path),
@@ -135,35 +164,3 @@ async def test_compose_scoring(tmp_path, mode, collect_fails, scoring_timeout):
135
164
  ],
136
165
  )
137
166
  )
138
- config = vf.AgentConfig(
139
- model="unused",
140
- runtime=vf.DockerConfig(),
141
- deployment=vf.DeploymentConfig(trust_compose=True),
142
- scoring=vf.ScoringConfig(
143
- mode=mode,
144
- env={"EXPECT_SIDECAR": "1" if mode == "isolated" else "0"},
145
- retries=vf.RetryConfig(max_retries=0),
146
- ),
147
- timeout=TimeoutConfig(
148
- setup=180, finalize=30, scoring=1 if scoring_timeout else 30
149
- ),
150
- )
151
- async with vf.Agent(config) as agent:
152
- agent.harness = ComposeHarness(vf.HarnessConfig())
153
- trace = await agent.run(task)
154
- for container in trace.info.get("solver_containers", []):
155
- assert (await cli("docker", "inspect", container)).exit_code != 0
156
- if mode == "isolated" and collect_fails:
157
- assert not trace.ok
158
- assert "collect hook failed" in str(trace.errors)
159
- assert "solver_released_before_grading" not in trace.info
160
- elif scoring_timeout:
161
- assert trace.ok and trace.is_timeout and not trace.errors
162
- assert trace.stop_condition == "scoring_timeout"
163
- assert all(reward is None for reward in trace.rewards.values())
164
- else:
165
- assert trace.ok and trace.reward == 1, trace.errors
166
- assert bool(trace.info.get("collected_sidecars")) == (mode == "isolated")
167
- assert bool(trace.info.get("solver_released_before_grading")) == (
168
- mode == "isolated"
169
- )
@@ -19,7 +19,7 @@ async def test_cap(run, cap, stop_condition):
19
19
  (episode,) = await run(
20
20
  "counter-tool",
21
21
  harness="null",
22
- runtime={"type": "subprocess"},
22
+ runtime={"type": "prime"},
23
23
  env={"agent": cap},
24
24
  )
25
25
  (trace,) = episode.traces
@@ -33,7 +33,7 @@ async def test_rollout_timeout(run):
33
33
  (episode,) = await run(
34
34
  "counter-tool",
35
35
  harness="null",
36
- runtime={"type": "subprocess"},
36
+ runtime={"type": "prime"},
37
37
  rollout_timeout=1,
38
38
  )
39
39
  (trace,) = episode.traces