verifiers 0.3.2.dev99__tar.gz → 0.3.2.dev101__tar.gz

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