verifiers 0.4.1.dev47__tar.gz → 0.4.1.dev48__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 (279) hide show
  1. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/PKG-INFO +1 -1
  2. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/network_policy.py +3 -3
  3. verifiers-0.4.1.dev48/tests/integration/test_scoring_network.py +175 -0
  4. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_tool_vms.py +3 -1
  5. verifiers-0.4.1.dev48/tests/unit/test_scoring_network.py +113 -0
  6. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/__init__.py +2 -0
  7. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/agent.py +1 -1
  8. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/validate.py +11 -2
  9. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/runtime.py +7 -3
  10. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/scoring.py +6 -0
  11. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/agentic_judge/env.py +3 -5
  12. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/grading.py +22 -1
  13. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/rollout.py +8 -0
  14. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/base.py +6 -3
  15. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/deployment.py +0 -6
  16. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/docker/__init__.py +7 -4
  17. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/e2b.py +8 -5
  18. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/modal.py +6 -2
  19. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/prime.py +9 -5
  20. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/runtime.py +22 -0
  21. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/task.py +12 -9
  22. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/harbor/taskset.py +24 -26
  23. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/compile.py +2 -7
  24. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/.gitignore +0 -0
  25. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/LICENSE +0 -0
  26. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/README.md +0 -0
  27. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/pyproject.toml +0 -0
  28. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/conftest.py +0 -0
  29. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/agent_user.py +0 -0
  30. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/agent_user_harness.py +0 -0
  31. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/counter_tool.py +0 -0
  32. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/duet.py +0 -0
  33. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo.py +0 -0
  34. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo_acp_resume.py +0 -0
  35. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo_agentic.py +0 -0
  36. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo_tool.py +0 -0
  37. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
  38. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/echo_user_sim.py +0 -0
  39. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/fetch_tool.py +0 -0
  40. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/parallel.py +0 -0
  41. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/pyproject.toml +0 -0
  42. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/skill_codeword.py +0 -0
  43. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
  44. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/fixtures/tool_response_image.py +0 -0
  45. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/grid.py +0 -0
  46. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_agent_user.py +0 -0
  47. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_agentic_judge.py +0 -0
  48. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_compose_scoring.py +0 -0
  49. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_examples.py +0 -0
  50. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_limits.py +0 -0
  51. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_multi_agent.py +0 -0
  52. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_multi_turn.py +0 -0
  53. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_multi_turn_tool.py +0 -0
  54. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_multimodal_tool.py +0 -0
  55. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_network_policy.py +0 -0
  56. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_parallel.py +0 -0
  57. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_resume_tool.py +0 -0
  58. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_rubric_judge.py +0 -0
  59. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_sampling.py +0 -0
  60. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_shared_tool.py +0 -0
  61. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_single_turn.py +0 -0
  62. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_skills.py +0 -0
  63. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_stateful_tool.py +0 -0
  64. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_user_echo.py +0 -0
  65. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/integration/test_user_sim.py +0 -0
  66. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/cli/test_replay.py +0 -0
  67. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/conftest.py +0 -0
  68. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/harnesses/test_core.py +0 -0
  69. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/harnesses/test_rlm.py +0 -0
  70. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/interception/test_tunnel.py +0 -0
  71. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/judges/conftest.py +0 -0
  72. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/judges/test_judge.py +0 -0
  73. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/judges/test_reference.py +0 -0
  74. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/judges/test_rubric.py +0 -0
  75. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/runtimes/test_e2b.py +0 -0
  76. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/runtimes/test_private_network.py +0 -0
  77. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/serve/test_client.py +0 -0
  78. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/serve/test_delta.py +0 -0
  79. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/serve/test_pool.py +0 -0
  80. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_agent.py +0 -0
  81. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_dialects.py +0 -0
  82. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_graph.py +0 -0
  83. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_semantic.py +0 -0
  84. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_task.py +0 -0
  85. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_taskset.py +0 -0
  86. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/test_trace.py +0 -0
  87. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/utils/test_compile.py +0 -0
  88. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/utils/test_loaders.py +0 -0
  89. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/utils/test_platform.py +0 -0
  90. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/tests/unit/utils/test_score.py +0 -0
  91. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/__init__.py +0 -0
  92. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/acp/__init__.py +0 -0
  93. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/acp/runner.py +0 -0
  94. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/__init__.py +0 -0
  95. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/dashboard/__init__.py +0 -0
  96. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/dashboard/base.py +0 -0
  97. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/dashboard/eval.py +0 -0
  98. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/dashboard/replay.py +0 -0
  99. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/dashboard/validate.py +0 -0
  100. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/debug.py +0 -0
  101. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/eval/__init__.py +0 -0
  102. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/eval/hint.py +0 -0
  103. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/eval/main.py +0 -0
  104. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/eval/resume.py +0 -0
  105. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/eval/runner.py +0 -0
  106. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/gepa.py +0 -0
  107. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/output.py +0 -0
  108. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/replay.py +0 -0
  109. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/resolve.py +0 -0
  110. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/cli/resume.py +0 -0
  111. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/clients/__init__.py +0 -0
  112. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/clients/base.py +0 -0
  113. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/clients/client.py +0 -0
  114. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/clients/eval.py +0 -0
  115. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/clients/train.py +0 -0
  116. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/__init__.py +0 -0
  117. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/agent.py +0 -0
  118. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/__init__.py +0 -0
  119. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/debug.py +0 -0
  120. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/env.py +0 -0
  121. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/eval.py +0 -0
  122. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/replay.py +0 -0
  123. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/cli/validate.py +0 -0
  124. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/client.py +0 -0
  125. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/env.py +0 -0
  126. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/harness.py +0 -0
  127. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/judge.py +0 -0
  128. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/retries.py +0 -0
  129. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/select.py +0 -0
  130. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/serve.py +0 -0
  131. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/task.py +0 -0
  132. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/configs/taskset.py +0 -0
  133. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/dialects/__init__.py +0 -0
  134. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/dialects/anthropic.py +0 -0
  135. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/dialects/base.py +0 -0
  136. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/dialects/chat.py +0 -0
  137. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/dialects/responses.py +0 -0
  138. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/env.py +0 -0
  139. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/__init__.py +0 -0
  140. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
  141. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
  142. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/best_of_n/env.py +0 -0
  143. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/single_agent/__init__.py +0 -0
  144. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/single_agent/env.py +0 -0
  145. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/user_sim/__init__.py +0 -0
  146. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/envs/user_sim/env.py +0 -0
  147. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/episode.py +0 -0
  148. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/errors.py +0 -0
  149. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/__init__.py +0 -0
  150. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/adapter.py +0 -0
  151. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/config.py +0 -0
  152. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/dataset.py +0 -0
  153. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/reflection.py +0 -0
  154. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/gepa/runner.py +0 -0
  155. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/graph.py +0 -0
  156. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harness.py +0 -0
  157. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/__init__.py +0 -0
  158. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/bash/__init__.py +0 -0
  159. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/bash/harness.py +0 -0
  160. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
  161. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
  162. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/browser_use/program.py +0 -0
  163. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
  164. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
  165. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/codex/__init__.py +0 -0
  166. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
  167. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/codex/harness.py +0 -0
  168. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
  169. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
  170. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
  171. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
  172. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
  173. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
  174. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
  175. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
  176. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
  177. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
  178. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
  179. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
  180. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/node.py +0 -0
  181. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/null/__init__.py +0 -0
  182. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/null/harness.py +0 -0
  183. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
  184. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
  185. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
  186. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/opencode/harness.py +0 -0
  187. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
  188. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/pi/__init__.py +0 -0
  189. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
  190. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/pi/harness.py +0 -0
  191. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
  192. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
  193. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
  194. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/rlm/harness.py +0 -0
  195. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
  196. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
  197. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
  198. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/__init__.py +0 -0
  199. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/compaction.py +0 -0
  200. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/core.py +0 -0
  201. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/install.py +0 -0
  202. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/launch.py +0 -0
  203. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/mcp.py +0 -0
  204. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/harnesses/utils/replay.py +0 -0
  205. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/__init__.py +0 -0
  206. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/base.py +0 -0
  207. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/pool.py +0 -0
  208. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/server.py +0 -0
  209. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/tunnel/__init__.py +0 -0
  210. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/tunnel/base.py +0 -0
  211. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/tunnel/custom.py +0 -0
  212. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/interception/tunnel/prime.py +0 -0
  213. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judge.py +0 -0
  214. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/__init__.py +0 -0
  215. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/decision.py +0 -0
  216. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/reference.py +0 -0
  217. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/reference.txt +0 -0
  218. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/rubric.py +0 -0
  219. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/judges/rubric.txt +0 -0
  220. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/mcp/__init__.py +0 -0
  221. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/mcp/launch.py +0 -0
  222. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/mcp/server.py +0 -0
  223. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/mcp/toolset.py +0 -0
  224. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/__init__.py +0 -0
  225. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/apptainer.py +0 -0
  226. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/compose.py +0 -0
  227. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/container.py +0 -0
  228. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/docker/egress.py +0 -0
  229. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/limiters.py +0 -0
  230. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/private_network.py +0 -0
  231. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/strategies.py +0 -0
  232. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/runtimes/subprocess.py +0 -0
  233. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/semantic.py +0 -0
  234. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/__init__.py +0 -0
  235. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/client.py +0 -0
  236. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/delta.py +0 -0
  237. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/encoding.py +0 -0
  238. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/pool.py +0 -0
  239. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/server.py +0 -0
  240. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/serve/types.py +0 -0
  241. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/session.py +0 -0
  242. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/state.py +0 -0
  243. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/taskset.py +0 -0
  244. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/__init__.py +0 -0
  245. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
  246. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
  247. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
  248. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
  249. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
  250. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
  251. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
  252. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
  253. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
  254. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
  255. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
  256. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/trace.py +0 -0
  257. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/types.py +0 -0
  258. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/__init__.py +0 -0
  259. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/aio.py +0 -0
  260. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/artifacts.py +0 -0
  261. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/decorators.py +0 -0
  262. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/env.py +0 -0
  263. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/eval.py +0 -0
  264. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/format.py +0 -0
  265. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/generic.py +0 -0
  266. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/git.py +0 -0
  267. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/image.py +0 -0
  268. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/interrupt.py +0 -0
  269. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/loaders.py +0 -0
  270. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/logging.py +0 -0
  271. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/memory.py +0 -0
  272. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/paths.py +0 -0
  273. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/platform.py +0 -0
  274. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/prime.py +0 -0
  275. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/retries.py +0 -0
  276. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/scope.py +0 -0
  277. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/score.py +0 -0
  278. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/verifiers/v1/utils/trace_store.py +0 -0
  279. {verifiers-0.4.1.dev47 → verifiers-0.4.1.dev48}/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.dev47
3
+ Version: 0.4.1.dev48
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
@@ -63,9 +63,9 @@ class NetworkPolicyTaskset(vf.Taskset[NetworkPolicyTask, vf.TasksetConfig]):
63
63
  def load(self) -> list[NetworkPolicyTask]:
64
64
  policies = {
65
65
  "open": {},
66
- "off": {"network_allow": []},
67
- "block": {"network_block": [BLOCKED]},
68
- "allow": {"network_allow": [ALLOWED]},
66
+ "off": {"network": vf.NetworkPolicyConfig(allow=[])},
67
+ "block": {"network": vf.NetworkPolicyConfig(block=[BLOCKED])},
68
+ "allow": {"network": vf.NetworkPolicyConfig(allow=[ALLOWED])},
69
69
  }
70
70
  prompt = (
71
71
  f"Your only task: run the command `python3 {PROBE_PATH}` once in your "
@@ -0,0 +1,175 @@
1
+ """Scoring runs under the network its policy declares: a task with framework-only egress
2
+ probes two public hosts from its scoring hook, in the workspace (shared) and in a fresh
3
+ verifier (isolated), in rollouts and in vf-validate, and a Harbor task's trusted grading
4
+ lifts the policy unless scoring declares its network."""
5
+
6
+ import json
7
+ import shutil
8
+
9
+ import pytest
10
+
11
+ import verifiers.v1 as vf
12
+ from verifiers.v1.cli.validate import _run_check
13
+ from verifiers.v1.configs.agent import TimeoutConfig
14
+ from verifiers.v1.configs.cli.validate import ValidateConfig
15
+ from verifiers.v1.tasksets.harbor.taskset import HarborData, HarborTask
16
+
17
+ pytestmark = [
18
+ pytest.mark.docker,
19
+ pytest.mark.skipif(not shutil.which("docker"), reason="needs Docker"),
20
+ ]
21
+
22
+ IMAGE = "python:3.11-slim"
23
+ HOSTS = ["example.com", "pypi.org"]
24
+ # Prints which hosts answer 200. Requests go through the runtime's egress proxy, which
25
+ # refuses a host the policy denies.
26
+ PROBE = f"""
27
+ import json, urllib.request
28
+ reachable = []
29
+ for host in {HOSTS!r}:
30
+ try:
31
+ with urllib.request.urlopen("https://" + host, timeout=15) as response:
32
+ if response.status == 200:
33
+ reachable.append(host)
34
+ except Exception:
35
+ pass
36
+ print(json.dumps(reachable))
37
+ """
38
+
39
+
40
+ class IdleHarness(vf.Harness):
41
+ async def launch(self, ctx, trace, runtime, endpoint, secret, mcp_urls, data):
42
+ return await runtime.run_program(["true"], {})
43
+
44
+
45
+ class ProbeTask(vf.Task):
46
+ @vf.reward(weight=1.0)
47
+ async def probe(self, trace, runtime) -> float:
48
+ result = await runtime.run(["python", "-c", PROBE], {})
49
+ trace.info["reachable"] = json.loads(result.stdout)
50
+ return 1.0
51
+
52
+
53
+ async def run(task) -> vf.Trace:
54
+ config = vf.AgentConfig(
55
+ model="unused",
56
+ runtime=vf.DockerConfig(),
57
+ timeout=TimeoutConfig(setup=180, finalize=30, scoring=120),
58
+ )
59
+ async with vf.Agent(config) as agent:
60
+ agent.harness = IdleHarness(vf.HarnessConfig())
61
+ return await agent.run(task)
62
+
63
+
64
+ @pytest.mark.parametrize("mode", ["shared", "isolated"])
65
+ @pytest.mark.parametrize(
66
+ ("network", "reachable"),
67
+ [
68
+ (None, []),
69
+ (vf.NetworkPolicyConfig(allow=["example.com"]), ["example.com"]),
70
+ (vf.NetworkPolicyConfig(), HOSTS),
71
+ ],
72
+ ids=["undeclared", "one-host", "open"],
73
+ )
74
+ async def test_scoring_network(mode, network, reachable):
75
+ task = ProbeTask(
76
+ vf.TaskData(
77
+ prompt="Do nothing",
78
+ image=IMAGE,
79
+ network=vf.NetworkPolicyConfig(allow=[]),
80
+ scoring=vf.ScoringConfig(
81
+ mode=mode, network=network, retries=vf.RetryConfig(max_retries=0)
82
+ ),
83
+ )
84
+ )
85
+ trace = await run(task)
86
+ assert trace.ok, trace.errors
87
+ assert trace.info["reachable"] == reachable
88
+
89
+
90
+ class ReachTask(vf.Task):
91
+ @vf.reward(weight=1.0)
92
+ async def reach(self, trace, runtime) -> float:
93
+ result = await runtime.run(["python", "-c", PROBE], {})
94
+ return float(json.loads(result.stdout) == ["example.com"])
95
+
96
+
97
+ @pytest.mark.parametrize("mode", ["shared", "isolated"])
98
+ async def test_validate_scores_under_the_declared_network(mode):
99
+ task = ReachTask(
100
+ vf.TaskData(
101
+ prompt="Do nothing",
102
+ image=IMAGE,
103
+ network=vf.NetworkPolicyConfig(allow=[]),
104
+ scoring=vf.ScoringConfig(
105
+ mode=mode,
106
+ network=vf.NetworkPolicyConfig(allow=["example.com"]),
107
+ retries=vf.RetryConfig(max_retries=0),
108
+ ),
109
+ )
110
+ )
111
+ row = await _run_check(task, ValidateConfig(runtime=vf.DockerConfig()), "noop")
112
+ # vf-validate never applies the agent phase's policy, so the shared workspace is open
113
+ # until scoring declares a network. Scoring that reaches only example.com passes the
114
+ # untouched task, which the noop check reports as invalid.
115
+ assert row["error"] is None
116
+ assert row["valid"] is False
117
+
118
+
119
+ class GoldReachTask(ReachTask):
120
+ async def validate(self, trace, runtime) -> bool:
121
+ await vf.grade_submission(self, trace, runtime)
122
+ return trace.reward == 1.0
123
+
124
+
125
+ async def test_validate_grades_a_submission_under_the_declared_network():
126
+ task = GoldReachTask(
127
+ vf.TaskData(
128
+ prompt="Do nothing",
129
+ image=IMAGE,
130
+ network=vf.NetworkPolicyConfig(allow=[]),
131
+ scoring=vf.ScoringConfig(
132
+ mode="isolated",
133
+ network=vf.NetworkPolicyConfig(allow=["example.com"]),
134
+ retries=vf.RetryConfig(max_retries=0),
135
+ ),
136
+ )
137
+ )
138
+ # vf-validate's trace records its own runtime config, so the verifier can reach
139
+ # example.com although the task's policy is framework-only.
140
+ row = await _run_check(task, ValidateConfig(runtime=vf.DockerConfig()), "gold")
141
+ assert row["error"] is None
142
+ assert row["valid"] is True
143
+
144
+
145
+ @pytest.mark.parametrize(
146
+ ("network", "reward"),
147
+ [(None, 1.0), (vf.NetworkPolicyConfig(allow=["pypi.org"]), 0.0)],
148
+ ids=["trusted-default", "declared"],
149
+ )
150
+ async def test_harbor_grading_network(tmp_path, network, reward):
151
+ tests = tmp_path / "tests"
152
+ tests.mkdir()
153
+ (tests / "test.sh").write_text(
154
+ "python - <<'EOF'\n"
155
+ "import urllib.request\n"
156
+ "try:\n"
157
+ " urllib.request.urlopen('https://example.com', timeout=15)\n"
158
+ " reward = 1\n"
159
+ "except Exception:\n"
160
+ " reward = 0\n"
161
+ "open('/logs/verifier/reward.txt', 'w').write(str(reward))\n"
162
+ "EOF\n"
163
+ )
164
+ task = HarborTask(
165
+ HarborData(
166
+ prompt="Do nothing",
167
+ task_dir=str(tmp_path),
168
+ image=IMAGE,
169
+ network=vf.NetworkPolicyConfig(allow=[]),
170
+ scoring=vf.ScoringConfig(network=network),
171
+ )
172
+ )
173
+ trace = await run(task)
174
+ assert trace.ok, trace.errors
175
+ assert trace.reward == reward
@@ -69,7 +69,9 @@ async def test_a_tool_vm_keeps_its_own_egress_beside_a_restricted_workspace(
69
69
  runtime=vf.PrimeConfig(labels=["vf-integration"], allow=allow)
70
70
  )
71
71
  task = ProbeTask(
72
- vf.TaskData(prompt="Probe the network", network_allow=[]),
72
+ vf.TaskData(
73
+ prompt="Probe the network", network=vf.NetworkPolicyConfig(allow=[])
74
+ ),
73
75
  FetchToolTaskConfig(tools=tools),
74
76
  )
75
77
  config = vf.AgentConfig(
@@ -0,0 +1,113 @@
1
+ """Scoring's declared network: how agent and task policies combine, how it combines with
2
+ the runtime's own rules (in `grade_submission`, the agent's), and what the runtime asks
3
+ its provider for."""
4
+
5
+ from typing import cast
6
+
7
+ import pytest
8
+
9
+ import verifiers.v1 as vf
10
+ from verifiers.v1 import grading
11
+ from verifiers.v1.configs.scoring import resolve_scoring
12
+ from verifiers.v1.errors import SandboxError, TaskError
13
+ from verifiers.v1.grading import grade_submission, scoring_network
14
+ from verifiers.v1.runtimes import deployment
15
+ from verifiers.v1.runtimes.base import RuntimeBackend
16
+ from verifiers.v1.runtimes.runtime import Runtime
17
+ from verifiers.v1.utils.compile import resolve_runtime_config
18
+
19
+ PYPI = vf.NetworkPolicyConfig(allow=["pypi.org"])
20
+
21
+
22
+ def test_agent_network_replaces_the_tasks():
23
+ task = vf.ScoringConfig(network=PYPI)
24
+ assert resolve_scoring(task, vf.ScoringConfig()).network == PYPI
25
+ agent = vf.ScoringConfig(network=vf.NetworkPolicyConfig())
26
+ assert resolve_scoring(task, agent).network == vf.NetworkPolicyConfig()
27
+
28
+
29
+ def test_scoring_network_combines_with_the_runtimes_rules():
30
+ assert scoring_network(vf.DockerConfig(), PYPI).allow == ["pypi.org"]
31
+ narrowed = vf.DockerConfig(allow=["pypi.org", "example.com"])
32
+ opened = scoring_network(narrowed, vf.NetworkPolicyConfig())
33
+ assert opened.allow == ["pypi.org", "example.com"]
34
+ # As for `TaskData.network`, a concrete allowlist can't sit beside a blocklist.
35
+ with pytest.raises(ValueError):
36
+ scoring_network(vf.DockerConfig(block=["example.com"]), PYPI)
37
+
38
+
39
+ def test_scoring_network_needs_a_runtime_with_policies():
40
+ with pytest.raises(TaskError):
41
+ scoring_network(vf.SubprocessConfig(), PYPI)
42
+ open_network = vf.NetworkPolicyConfig()
43
+ assert scoring_network(vf.SubprocessConfig(), open_network) is open_network
44
+
45
+
46
+ class Backend:
47
+ supports_user = False
48
+ name = "fake"
49
+
50
+ def __init__(self, config, restricted=True):
51
+ self.config = config
52
+ self.network_restricted = restricted
53
+ self.calls = []
54
+
55
+ async def prepare_execution(self, routes, network=None):
56
+ self.calls.append((routes, None if network is None else network.allow))
57
+
58
+
59
+ async def test_set_network_enforces_a_policy_or_lifts_it():
60
+ backend = Backend(vf.DockerConfig(allow=[]))
61
+ runtime = Runtime(cast(RuntimeBackend, backend))
62
+ await runtime.set_network(PYPI)
63
+ await runtime.set_network(vf.NetworkPolicyConfig())
64
+ assert backend.calls == [([], ["pypi.org"]), (None, None)]
65
+
66
+
67
+ async def test_set_network_cannot_restrict_a_runtime_that_started_open():
68
+ backend = Backend(vf.DockerConfig(), restricted=False)
69
+ runtime = Runtime(cast(RuntimeBackend, backend))
70
+ with pytest.raises(SandboxError):
71
+ await runtime.set_network(PYPI)
72
+ await runtime.set_network(vf.NetworkPolicyConfig())
73
+ assert backend.calls == [(None, None)]
74
+
75
+
76
+ async def test_grade_submission_widens_from_the_agents_runtime(monkeypatch):
77
+ graded = []
78
+
79
+ async def grade_task(task, trace, config, *args, **kwargs):
80
+ graded.append(config)
81
+
82
+ class Deployment:
83
+ def __init__(self, *args, **kwargs):
84
+ pass
85
+
86
+ async def start(self):
87
+ pass
88
+
89
+ async def close(self):
90
+ pass
91
+
92
+ monkeypatch.setattr(grading, "grade_task", grade_task)
93
+ monkeypatch.setattr(deployment, "Deployment", Deployment)
94
+ task = vf.Task(
95
+ vf.TaskData(
96
+ prompt="",
97
+ image="python:3.11-slim",
98
+ network=vf.NetworkPolicyConfig(allow=[]),
99
+ scoring=vf.ScoringConfig(mode="isolated", network=PYPI),
100
+ )
101
+ )
102
+ agent_runtime = vf.DockerConfig()
103
+ # The solver's resolved config carries the task's framework-only policy.
104
+ solver = Runtime(
105
+ cast(RuntimeBackend, Backend(resolve_runtime_config(agent_runtime, task)))
106
+ )
107
+ trace = vf.Trace(
108
+ agent=vf.AgentInfo(config=vf.AgentConfig(runtime=agent_runtime)),
109
+ task=vf.TraceTask(type="Task", data=task.data),
110
+ )
111
+ await grade_submission(task, trace, solver)
112
+ [config] = graded
113
+ assert config.allow == ["pypi.org"]
@@ -82,6 +82,7 @@ from verifiers.v1.mcp import (
82
82
  from verifiers.v1.runtimes import (
83
83
  ApptainerConfig,
84
84
  DockerConfig,
85
+ NetworkPolicyConfig,
85
86
  PodmanConfig,
86
87
  PrimeConfig,
87
88
  ProgramResult,
@@ -315,6 +316,7 @@ __all__ = [ # noqa: RUF022 - grouped by public API area
315
316
  "ProgramResult",
316
317
  "SubprocessConfig",
317
318
  "DockerConfig",
319
+ "NetworkPolicyConfig",
318
320
  "PodmanConfig",
319
321
  "ApptainerConfig",
320
322
  "PrimeConfig",
@@ -94,7 +94,7 @@ def _check_borrowed_placement(
94
94
  """A borrowed box is never re-provisioned, so a task's placement fields can't
95
95
  be honored. Reject requirements that cannot be applied to the running box; an
96
96
  image mismatch on a container only warns, since sharing its world is the point."""
97
- task_policy = "*" not in task.data.network_allow or bool(task.data.network_block)
97
+ task_policy = task.data.network.network_restricted
98
98
  base_policy = base_config if isinstance(base_config, NetworkPolicyConfig) else None
99
99
  if task_policy or (base_policy is not None and base_policy.network_restricted):
100
100
  config = runtime.config
@@ -31,7 +31,12 @@ from verifiers.v1.cli.resolve import (
31
31
  from verifiers.v1.cli.resume import distribute
32
32
  from verifiers.v1.configs.cli.validate import ValidateConfig
33
33
  from verifiers.v1.errors import TaskError, boundary
34
- from verifiers.v1.grading import bind_scoring_env, grade_task, verifier_runtime
34
+ from verifiers.v1.grading import (
35
+ bind_scoring_env,
36
+ grade_task,
37
+ scoring_network,
38
+ verifier_runtime,
39
+ )
35
40
  from verifiers.v1.runtimes import make_backend
36
41
  from verifiers.v1.runtimes.deployment import Deployment
37
42
  from verifiers.v1.state import state_cls
@@ -244,7 +249,7 @@ async def _setup_only(task: Task, trace: Trace, runtime) -> bool:
244
249
 
245
250
  async def _gold(task: Task, trace: Trace, runtime) -> bool | None:
246
251
  """Apply and check the reference answer."""
247
- return await task.validate(runtime)
252
+ return await invoke(task.validate, {"trace": trace, "runtime": runtime})
248
253
 
249
254
 
250
255
  async def _score_untouched(
@@ -288,6 +293,10 @@ async def _score_untouched(
288
293
  async with asyncio.timeout(task.data.timeout.scoring):
289
294
  runtime = bind_scoring_env(runtime, policy)
290
295
  await invoke(grader.stage_verifier, {"trace": trace, "runtime": runtime})
296
+ if policy.network is not None:
297
+ await runtime.set_network(
298
+ scoring_network(config.runtime, policy.network)
299
+ )
291
300
  await grader.score(trace, runtime, deployment)
292
301
  if not trace.rewards:
293
302
  return None
@@ -55,7 +55,9 @@ def intersect_network_hosts(left: str, right: str) -> str:
55
55
 
56
56
 
57
57
  class NetworkPolicyConfig(BaseConfig):
58
- """Shared execution-time policy surface for runtimes that support it."""
58
+ """What a box may reach. A runtime's own rules, a task's (`TaskData.network`) and a
59
+ task's scoring (`ScoringConfig.network`) all use it; a task's policy combines with its
60
+ runtime's rules: allowlists intersect and blocklists merge."""
59
61
 
60
62
  allow: list[str] = Field(default_factory=lambda: ["*"])
61
63
  """Destinations allowed during execution; `*` is unrestricted and `[]` is
@@ -87,10 +89,12 @@ class NetworkPolicyConfig(BaseConfig):
87
89
  for rule in self.block
88
90
  ) and any(network_rule_matches(rule, scheme, host, port) for rule in self.allow)
89
91
 
90
- def with_task_network_policy(self, allow: list[str], block: list[str]) -> Self:
92
+ def with_task_network_policy(self, network: "NetworkPolicyConfig") -> Self:
91
93
  values = self.model_dump()
92
94
  # Intersection must not erase syntax the runtime cannot enforce.
93
- task = type(self).model_validate({**values, "allow": allow, "block": block})
95
+ task = type(self).model_validate(
96
+ {**values, "allow": network.allow, "block": network.block}
97
+ )
94
98
  allow, block = task.allow, task.block
95
99
  if "*" in allow:
96
100
  allow = self.allow
@@ -6,6 +6,7 @@ from pydantic import SerializationInfo, field_serializer
6
6
  from pydantic_config import BaseConfig
7
7
 
8
8
  from verifiers.v1.configs.retries import RetryConfig
9
+ from verifiers.v1.configs.runtime import NetworkPolicyConfig
9
10
  from verifiers.v1.runtimes import RuntimeConfig
10
11
  from verifiers.v1.utils.generic import merge_defaults
11
12
 
@@ -19,6 +20,11 @@ class ScoringConfig(BaseConfig):
19
20
  """Scoring-only variables, merged over task defaults and resolved at scoring time."""
20
21
  retries: RetryConfig = RetryConfig(max_retries=2)
21
22
  """Retry rules for fresh isolated scoring attempts; shared scoring is not retried."""
23
+ network: NetworkPolicyConfig | None = None
24
+ """The task's network policy while scoring runs, in place of `TaskData.network` and
25
+ combined with the runtime's own rules the same way. None keeps the default: isolated
26
+ scoring runs under `TaskData.network`, shared scoring keeps the agent phase's network,
27
+ and Harbor's shared grading lifts the policy."""
22
28
 
23
29
  @field_serializer("runtime")
24
30
  def serialize_runtime(
@@ -165,8 +165,7 @@ class JudgeTask(vf.Task):
165
165
  image=solved.image,
166
166
  workdir=solved.workdir,
167
167
  resources=solved.resources,
168
- network_allow=solved.network_allow,
169
- network_block=solved.network_block,
168
+ network=solved.network,
170
169
  ),
171
170
  files=files,
172
171
  )
@@ -334,9 +333,8 @@ class AgenticJudgeEnv(vf.Env[AgenticJudgeEnvConfig]):
334
333
  "workdir": runtime.config.workdir,
335
334
  }
336
335
  if isinstance(runtime.config, NetworkPolicyConfig):
337
- updates.update(
338
- network_allow=runtime.config.allow,
339
- network_block=runtime.config.block,
336
+ updates["network"] = NetworkPolicyConfig(
337
+ allow=runtime.config.allow, block=runtime.config.block
340
338
  )
341
339
  judge_task = judge_task.with_data(**updates)
342
340
  # A per-invocation view retains episode accounting and concurrency while
@@ -9,6 +9,7 @@ from pathlib import PurePosixPath
9
9
  from verifiers.v1.configs.scoring import ScoringConfig
10
10
  from verifiers.v1.errors import TaskError, boundary
11
11
  from verifiers.v1.runtimes import (
12
+ NetworkPolicyConfig,
12
13
  PrimeConfig,
13
14
  Runtime,
14
15
  RuntimeConfig,
@@ -56,6 +57,8 @@ def verifier_runtime(
56
57
  image=task.data.image or getattr(solver_runtime.config, "image", None),
57
58
  workdir=task.data.workdir or getattr(solver_runtime.config, "workdir", None),
58
59
  )
60
+ if policy.network is not None:
61
+ task = task.with_data(network=policy.network)
59
62
  config = resolve_runtime_config(source, task)
60
63
  if policy.runtime is not None and "image" in policy.runtime.model_fields_set:
61
64
  config = config.model_copy(update={"image": policy.runtime.image})
@@ -75,6 +78,21 @@ def verifier_runtime(
75
78
  return config
76
79
 
77
80
 
81
+ def scoring_network(
82
+ base: RuntimeConfig, network: NetworkPolicyConfig
83
+ ) -> NetworkPolicyConfig:
84
+ """`network` as the task's policy while scoring, combined with the runtime's own
85
+ rules the way `TaskData.network` is."""
86
+ if isinstance(base, NetworkPolicyConfig):
87
+ return base.with_task_network_policy(network)
88
+ if network.network_restricted:
89
+ raise TaskError(
90
+ f"scoring requires a network policy, but the {base.type} runtime does not "
91
+ "support one"
92
+ )
93
+ return network
94
+
95
+
78
96
  def bind_scoring_env(runtime: Runtime, policy: ScoringConfig) -> Runtime:
79
97
  """Bind scoring variables without changing the solver's runtime or backend."""
80
98
  return runtime.with_env({**runtime.env, **resolve_env(policy.env or {})})
@@ -188,6 +206,9 @@ async def grade_submission(
188
206
 
189
207
  The caller finalizes the submission and collects artifacts into the trace first.
190
208
  Uses the task's grader, scoring policy, and timeouts, including retry behavior.
209
+ As in a rollout, the verifier derives from the agent's runtime config on the trace
210
+ (`trace.agent.config.runtime`), not from the solver's resolved one, so the solver
211
+ task's requirements, such as its network policy, don't carry over.
191
212
  """
192
213
  from verifiers.v1.runtimes.deployment import Deployment
193
214
 
@@ -195,7 +216,7 @@ async def grade_submission(
195
216
  if policy.mode != "isolated":
196
217
  raise ValueError("grade_submission requires isolated scoring")
197
218
  grader = task.grading_task(runtime, scoring=policy)
198
- config = verifier_runtime(grader, runtime, runtime.config, policy)
219
+ config = verifier_runtime(grader, runtime, trace.agent.config.runtime, policy)
199
220
  deployment = Deployment(
200
221
  runtime.backend, borrowed_runtime=runtime, env=dict(runtime.env)
201
222
  )
@@ -24,6 +24,7 @@ from verifiers.v1.errors import (
24
24
  from verifiers.v1.grading import (
25
25
  bind_scoring_env,
26
26
  grade_task,
27
+ scoring_network,
27
28
  scoring_transaction,
28
29
  verifier_runtime,
29
30
  )
@@ -880,6 +881,13 @@ class Rollout:
880
881
  "runtime": scoring_runtime,
881
882
  },
882
883
  )
884
+ if self._scoring_policy.network is not None:
885
+ await scoring_runtime.set_network(
886
+ scoring_network(
887
+ self.trace.agent.config.runtime,
888
+ self._scoring_policy.network,
889
+ )
890
+ )
883
891
  await self._scoring_task.score(
884
892
  trace, scoring_runtime, self.deployment
885
893
  )
@@ -310,10 +310,13 @@ class RuntimeBackend(ABC):
310
310
  await self.prepare_execution(None)
311
311
  self._setup_claimed = True
312
312
 
313
- async def prepare_execution(self, routes: list[str] | None) -> None:
313
+ async def prepare_execution(
314
+ self, routes: list[str] | None, network: NetworkPolicyConfig | None = None
315
+ ) -> None:
314
316
  """Last setup step, right before the agent starts. Restricted runtimes enforce
315
- their policy here; `routes` identifies the interception and MCP endpoints.
316
- None restores unrestricted egress for another trusted setup phase."""
317
+ their policy here, or `network` instead of it; `routes` identifies the
318
+ interception and MCP endpoints. None restores unrestricted egress for another
319
+ trusted setup phase."""
317
320
 
318
321
  @property
319
322
  def network_restricted(self) -> bool:
@@ -44,9 +44,6 @@ class _DeploymentStrategy:
44
44
  ) -> None:
45
45
  await deployment.harness_backend.prepare_execution(routes)
46
46
 
47
- async def prepare_grading(self, deployment: Deployment) -> None:
48
- await deployment.execution_backend.prepare_execution(None)
49
-
50
47
  async def stop_execution(self, deployment: Deployment) -> None:
51
48
  return
52
49
 
@@ -195,9 +192,6 @@ class Deployment:
195
192
  server's own VM keeps only `state_route`, its state channel."""
196
193
  await self._strategy.prepare_execution(self, routes, state_route)
197
194
 
198
- async def prepare_grading(self) -> None:
199
- await self._strategy.prepare_grading(self)
200
-
201
195
  async def close(self) -> None:
202
196
  async def release():
203
197
  try:
@@ -416,10 +416,13 @@ class DockerBackend(ContainerBackend):
416
416
  descriptors.frombytes(ancillary[0][2][: descriptors.itemsize])
417
417
  return socket.socket(fileno=descriptors[0])
418
418
 
419
- async def prepare_execution(self, routes: list[str] | None) -> None:
420
- """Allow the declared framework routes, then leave the proxy as the only way out."""
419
+ async def prepare_execution(
420
+ self, routes: list[str] | None, network: NetworkPolicyConfig | None = None
421
+ ) -> None:
422
+ """Allow the declared framework routes, then leave the proxy, enforcing the
423
+ configured policy or `network`, as the only way out."""
421
424
  if self._host_backend is not None:
422
- await self._host_backend.prepare_execution(routes)
425
+ await self._host_backend.prepare_execution(routes, network)
423
426
  return
424
427
  if not self.network_restricted:
425
428
  return
@@ -434,7 +437,7 @@ class DockerBackend(ContainerBackend):
434
437
  for url in routes
435
438
  ]
436
439
  assert isinstance(self.config, NetworkPolicyConfig)
437
- self._proxy.policy = NetworkPolicy(self.config, framework)
440
+ self._proxy.policy = NetworkPolicy(network or self.config, framework)
438
441
  if self._cut:
439
442
  return
440
443
  # Off Linux the host proxy has a real address; allow only its listening port.
@@ -437,17 +437,20 @@ class E2BBackend(RuntimeBackend):
437
437
  except Exception as e:
438
438
  raise SandboxError(f"e2b sandbox provisioning failed: {e}") from e
439
439
 
440
- async def prepare_execution(self, routes: list[str] | None) -> None:
441
- """Apply the host policy after setup; the update replaces all rules atomically."""
440
+ async def prepare_execution(
441
+ self, routes: list[str] | None, network: NetworkPolicyConfig | None = None
442
+ ) -> None:
443
+ """Apply the host policy, or `network`, after setup; the update replaces all
444
+ rules atomically."""
442
445
  if not self.network_restricted:
443
446
  return
444
- network = _egress_update(self.config, routes)
447
+ update = _egress_update(network or self.config, routes)
445
448
  try:
446
- await self._sandbox.update_network(network)
449
+ await self._sandbox.update_network(update)
447
450
  except Exception as e:
448
451
  raise SandboxError(f"e2b egress policy failed: {e}") from e
449
452
  logger.info(
450
- "e2b: egress policy applied on sandbox %s (%s)", self.info.id, network
453
+ "e2b: egress policy applied on sandbox %s (%s)", self.info.id, update
451
454
  )
452
455
 
453
456
  def _command(
@@ -250,7 +250,9 @@ class ModalBackend(RuntimeBackend):
250
250
  experimental_options={"vm_runtime": True} if self.config.vm else {},
251
251
  )
252
252
 
253
- async def prepare_execution(self, routes: list[str] | None) -> None:
253
+ async def prepare_execution(
254
+ self, routes: list[str] | None, network: NetworkPolicyConfig | None = None
255
+ ) -> None:
254
256
  """Apply TLS domain filtering after setup, retaining framework endpoints.
255
257
 
256
258
  Modal filters TLS SNI on port 443, not HTTP Host headers or URL paths.
@@ -263,7 +265,9 @@ class ModalBackend(RuntimeBackend):
263
265
  domains, cidrs = ["*"], ["0.0.0.0/0"]
264
266
  else:
265
267
  domains = [_egress_domain(route, framework=True) for route in routes]
266
- domains.extend(_egress_domain(rule) for rule in self.config.allow)
268
+ domains.extend(
269
+ _egress_domain(rule) for rule in (network or self.config).allow
270
+ )
267
271
  domains = list(dict.fromkeys(d for d in domains if d is not None))
268
272
  cidrs = []
269
273
  # Always send both lists: leaving the setup CIDR grant would bypass domains.