verifiers 0.4.1.dev64__tar.gz → 0.4.1.dev67__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 (281) hide show
  1. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/PKG-INFO +1 -1
  2. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/counter_tool.py +8 -1
  3. verifiers-0.4.1.dev67/tests/integration/test_limits.py +116 -0
  4. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_task.py +31 -2
  5. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_trace.py +27 -0
  6. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/__init__.py +3 -0
  7. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/agent.py +1 -0
  8. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/agent.py +10 -0
  9. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/scoring.py +6 -0
  10. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/task.py +10 -2
  11. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/rollout.py +22 -1
  12. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/session.py +16 -1
  13. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/trace.py +1 -0
  14. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/decorators.py +11 -5
  15. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/loaders.py +10 -1
  16. verifiers-0.4.1.dev64/tests/integration/test_limits.py +0 -56
  17. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/.gitignore +0 -0
  18. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/LICENSE +0 -0
  19. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/README.md +0 -0
  20. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/pyproject.toml +0 -0
  21. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/conftest.py +0 -0
  22. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/agent_user.py +0 -0
  23. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/agent_user_harness.py +0 -0
  24. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/duet.py +0 -0
  25. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo.py +0 -0
  26. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo_acp_resume.py +0 -0
  27. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo_agentic.py +0 -0
  28. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo_tool.py +0 -0
  29. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
  30. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/echo_user_sim.py +0 -0
  31. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/fetch_tool.py +0 -0
  32. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/network_policy.py +0 -0
  33. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/parallel.py +0 -0
  34. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/pyproject.toml +0 -0
  35. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/skill_codeword.py +0 -0
  36. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
  37. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/fixtures/tool_response_image.py +0 -0
  38. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/grid.py +0 -0
  39. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_agent_user.py +0 -0
  40. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_agentic_judge.py +0 -0
  41. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_compose_scoring.py +0 -0
  42. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_examples.py +0 -0
  43. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_multi_agent.py +0 -0
  44. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_multi_turn.py +0 -0
  45. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_multi_turn_tool.py +0 -0
  46. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_multimodal_tool.py +0 -0
  47. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_network_policy.py +0 -0
  48. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_parallel.py +0 -0
  49. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_resume_tool.py +0 -0
  50. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_rubric_judge.py +0 -0
  51. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_sampling.py +0 -0
  52. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_scoring_network.py +0 -0
  53. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_shared_tool.py +0 -0
  54. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_single_turn.py +0 -0
  55. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_skills.py +0 -0
  56. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_stateful_tool.py +0 -0
  57. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_tool_vms.py +0 -0
  58. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_user_echo.py +0 -0
  59. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/integration/test_user_sim.py +0 -0
  60. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/cli/test_replay.py +0 -0
  61. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/conftest.py +0 -0
  62. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/harnesses/test_core.py +0 -0
  63. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/harnesses/test_rlm.py +0 -0
  64. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/interception/test_tunnel.py +0 -0
  65. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/judges/conftest.py +0 -0
  66. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/judges/test_judge.py +0 -0
  67. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/judges/test_reference.py +0 -0
  68. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/judges/test_rubric.py +0 -0
  69. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/runtimes/test_private_network.py +0 -0
  70. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/serve/test_client.py +0 -0
  71. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/serve/test_delta.py +0 -0
  72. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/serve/test_pool.py +0 -0
  73. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_agent.py +0 -0
  74. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_api.py +0 -0
  75. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_dialects.py +0 -0
  76. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_graph.py +0 -0
  77. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_harbor_grading_network.py +0 -0
  78. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_runtimes.py +0 -0
  79. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_scoring_network.py +0 -0
  80. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_semantic.py +0 -0
  81. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/test_taskset.py +0 -0
  82. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/utils/test_compile.py +0 -0
  83. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/utils/test_loaders.py +0 -0
  84. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/utils/test_platform.py +0 -0
  85. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/tests/unit/utils/test_score.py +0 -0
  86. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/__init__.py +0 -0
  87. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/acp/__init__.py +0 -0
  88. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/acp/runner.py +0 -0
  89. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/__init__.py +0 -0
  90. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/dashboard/__init__.py +0 -0
  91. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/dashboard/base.py +0 -0
  92. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/dashboard/eval.py +0 -0
  93. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/dashboard/replay.py +0 -0
  94. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/dashboard/validate.py +0 -0
  95. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/debug.py +0 -0
  96. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/eval/__init__.py +0 -0
  97. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/eval/hint.py +0 -0
  98. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/eval/main.py +0 -0
  99. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/eval/resume.py +0 -0
  100. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/eval/runner.py +0 -0
  101. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/gepa.py +0 -0
  102. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/output.py +0 -0
  103. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/replay.py +0 -0
  104. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/resolve.py +0 -0
  105. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/resume.py +0 -0
  106. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/cli/validate.py +0 -0
  107. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/clients/__init__.py +0 -0
  108. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/clients/base.py +0 -0
  109. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/clients/client.py +0 -0
  110. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/clients/eval.py +0 -0
  111. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/clients/train.py +0 -0
  112. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/__init__.py +0 -0
  113. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/__init__.py +0 -0
  114. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/debug.py +0 -0
  115. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/env.py +0 -0
  116. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/eval.py +0 -0
  117. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/replay.py +0 -0
  118. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/cli/validate.py +0 -0
  119. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/client.py +0 -0
  120. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/deployment.py +0 -0
  121. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/env.py +0 -0
  122. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/harness.py +0 -0
  123. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/interception.py +0 -0
  124. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/judge.py +0 -0
  125. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/retries.py +0 -0
  126. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/runtime.py +0 -0
  127. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/select.py +0 -0
  128. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/serve.py +0 -0
  129. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/configs/taskset.py +0 -0
  130. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/dialects/__init__.py +0 -0
  131. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/dialects/anthropic.py +0 -0
  132. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/dialects/base.py +0 -0
  133. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/dialects/chat.py +0 -0
  134. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/dialects/responses.py +0 -0
  135. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/env.py +0 -0
  136. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/__init__.py +0 -0
  137. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
  138. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/agentic_judge/env.py +0 -0
  139. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
  140. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/best_of_n/env.py +0 -0
  141. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/single_agent/__init__.py +0 -0
  142. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/single_agent/env.py +0 -0
  143. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/user_sim/__init__.py +0 -0
  144. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/envs/user_sim/env.py +0 -0
  145. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/episode.py +0 -0
  146. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/errors.py +0 -0
  147. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/__init__.py +0 -0
  148. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/adapter.py +0 -0
  149. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/config.py +0 -0
  150. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/dataset.py +0 -0
  151. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/reflection.py +0 -0
  152. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/gepa/runner.py +0 -0
  153. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/grading.py +0 -0
  154. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/graph.py +0 -0
  155. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harness.py +0 -0
  156. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/__init__.py +0 -0
  157. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/bash/__init__.py +0 -0
  158. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/bash/harness.py +0 -0
  159. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
  160. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
  161. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/browser_use/program.py +0 -0
  162. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
  163. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
  164. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/codex/__init__.py +0 -0
  165. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
  166. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/codex/harness.py +0 -0
  167. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
  168. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
  169. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
  170. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
  171. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
  172. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
  173. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
  174. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
  175. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
  176. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
  177. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
  178. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
  179. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/node.py +0 -0
  180. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/null/__init__.py +0 -0
  181. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/null/harness.py +0 -0
  182. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
  183. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
  184. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
  185. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/opencode/harness.py +0 -0
  186. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
  187. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/pi/__init__.py +0 -0
  188. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
  189. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/pi/harness.py +0 -0
  190. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
  191. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
  192. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
  193. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/rlm/harness.py +0 -0
  194. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
  195. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
  196. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
  197. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/__init__.py +0 -0
  198. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/compaction.py +0 -0
  199. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/core.py +0 -0
  200. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/install.py +0 -0
  201. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/launch.py +0 -0
  202. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/mcp.py +0 -0
  203. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/harnesses/utils/replay.py +0 -0
  204. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/__init__.py +0 -0
  205. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/base.py +0 -0
  206. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/pool.py +0 -0
  207. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/server.py +0 -0
  208. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/tunnel/__init__.py +0 -0
  209. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/tunnel/base.py +0 -0
  210. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/tunnel/custom.py +0 -0
  211. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/interception/tunnel/prime.py +0 -0
  212. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judge.py +0 -0
  213. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/__init__.py +0 -0
  214. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/decision.py +0 -0
  215. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/reference.py +0 -0
  216. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/reference.txt +0 -0
  217. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/rubric.py +0 -0
  218. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/judges/rubric.txt +0 -0
  219. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/mcp/__init__.py +0 -0
  220. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/mcp/launch.py +0 -0
  221. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/mcp/server.py +0 -0
  222. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/mcp/toolset.py +0 -0
  223. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/__init__.py +0 -0
  224. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/backends/custom.py +0 -0
  225. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/backends/docker.py +0 -0
  226. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/backends/prime.py +0 -0
  227. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/backends/subprocess.py +0 -0
  228. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/base.py +0 -0
  229. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/compose.py +0 -0
  230. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/deployment.py +0 -0
  231. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/egress.py +0 -0
  232. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/limiters.py +0 -0
  233. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/private_network.py +0 -0
  234. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/runtime.py +0 -0
  235. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/runtimes/strategies.py +0 -0
  236. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/semantic.py +0 -0
  237. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/__init__.py +0 -0
  238. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/client.py +0 -0
  239. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/delta.py +0 -0
  240. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/encoding.py +0 -0
  241. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/pool.py +0 -0
  242. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/server.py +0 -0
  243. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/serve/types.py +0 -0
  244. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/state.py +0 -0
  245. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/task.py +0 -0
  246. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/taskset.py +0 -0
  247. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/__init__.py +0 -0
  248. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
  249. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
  250. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
  251. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
  252. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
  253. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
  254. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
  255. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
  256. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
  257. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
  258. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
  259. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
  260. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/types.py +0 -0
  261. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/__init__.py +0 -0
  262. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/aio.py +0 -0
  263. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/artifacts.py +0 -0
  264. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/compile.py +0 -0
  265. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/env.py +0 -0
  266. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/eval.py +0 -0
  267. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/format.py +0 -0
  268. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/generic.py +0 -0
  269. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/git.py +0 -0
  270. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/image.py +0 -0
  271. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/interrupt.py +0 -0
  272. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/logging.py +0 -0
  273. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/memory.py +0 -0
  274. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/paths.py +0 -0
  275. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/platform.py +0 -0
  276. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/prime.py +0 -0
  277. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/retries.py +0 -0
  278. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/scope.py +0 -0
  279. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/score.py +0 -0
  280. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/verifiers/v1/utils/trace_store.py +0 -0
  281. {verifiers-0.4.1.dev64 → verifiers-0.4.1.dev67}/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.dev64
3
+ Version: 0.4.1.dev67
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
@@ -21,6 +21,8 @@ class CounterToolset(vf.Toolset[vf.ToolsetConfig, CounterState]):
21
21
 
22
22
  class CounterTaskConfig(vf.TaskConfig):
23
23
  tools: vf.ToolsetConfig = vf.ToolsetConfig()
24
+ constant_reward: bool = False
25
+ """Score every rollout 1, so a skipped score (reward 0) stands out."""
24
26
 
25
27
 
26
28
  class CounterTask(vf.Task[vf.TaskData, CounterState, CounterTaskConfig]):
@@ -30,7 +32,12 @@ class CounterTask(vf.Task[vf.TaskData, CounterState, CounterTaskConfig]):
30
32
 
31
33
  @vf.reward(weight=1.0)
32
34
  async def counted(self, trace: vf.Trace) -> float:
33
- return float(trace.state.count >= 2)
35
+ return float(self.config.constant_reward or trace.state.count >= 2)
36
+
37
+
38
+ def any_response(response: vf.Response) -> bool:
39
+ """A plugged stop that ends the run on its first model response."""
40
+ return True
34
41
 
35
42
 
36
43
  class CounterConfig(vf.TasksetConfig):
@@ -0,0 +1,116 @@
1
+ """The seat's caps stop a rollout that would run on: the counter task wants three tool
2
+ turns (counter-tool), and each cap ends it after the first with its own stop
3
+ condition. The turn cap also runs across the harness x runtime grid, since each program
4
+ handles a refused request in its own way."""
5
+
6
+ import pytest
7
+ from grid import grid
8
+
9
+ CAPS = [
10
+ pytest.param({"max_turns": 1}, "max_turns", id="max-turns"),
11
+ pytest.param({"max_input_tokens": 1}, "max_input_tokens", id="max-input-tokens"),
12
+ pytest.param({"max_output_tokens": 1}, "max_output_tokens", id="max-output-tokens"),
13
+ pytest.param({"max_total_tokens": 1}, "max_total_tokens", id="max-total-tokens"),
14
+ ]
15
+
16
+
17
+ @pytest.mark.parametrize("cap,stop_condition", CAPS)
18
+ async def test_cap(run, cap, stop_condition):
19
+ (episode,) = await run(
20
+ "counter-tool",
21
+ harness="null",
22
+ runtime={"type": "prime"},
23
+ env={"agent": cap},
24
+ )
25
+ (trace,) = episode.traces
26
+ assert trace.num_branches == 1
27
+ assert trace.stop_condition == stop_condition
28
+ assert trace.is_truncated
29
+ assert trace.num_turns == 1
30
+
31
+
32
+ async def test_rollout_timeout(run):
33
+ (episode,) = await run(
34
+ "counter-tool",
35
+ harness="null",
36
+ runtime={"type": "prime"},
37
+ rollout_timeout=1,
38
+ )
39
+ (trace,) = episode.traces
40
+ assert trace.is_timeout
41
+ assert trace.stop_condition == "agent_timeout"
42
+
43
+
44
+ @pytest.mark.parametrize("skip", [False, True], ids=["scored", "skipped"])
45
+ async def test_skip_scoring_on_truncated(run, skip):
46
+ (episode,) = await run(
47
+ "counter-tool",
48
+ harness="null",
49
+ runtime={"type": "prime"},
50
+ taskset_overrides={"task": {"constant_reward": True}},
51
+ env={"agent": {"max_turns": 1, "scoring": {"skip_on_truncated": skip}}},
52
+ )
53
+ (trace,) = episode.traces
54
+ assert trace.is_truncated and trace.ok
55
+ if skip:
56
+ assert trace.reward == 0 and trace.rewards == {}
57
+ assert trace.info["scoring_skipped"] == "truncated"
58
+ else:
59
+ assert trace.reward == 1
60
+ assert "scoring_skipped" not in trace.info
61
+
62
+
63
+ @pytest.mark.parametrize("skip", [False, True], ids=["scored", "skipped"])
64
+ async def test_skip_scoring_on_timeout(run, skip):
65
+ (episode,) = await run(
66
+ "counter-tool",
67
+ harness="null",
68
+ runtime={"type": "prime"},
69
+ rollout_timeout=1,
70
+ taskset_overrides={"task": {"constant_reward": True}},
71
+ env={"agent": {"scoring": {"skip_on_timeout": skip}}},
72
+ )
73
+ (trace,) = episode.traces
74
+ assert trace.is_timeout and trace.ok
75
+ if skip:
76
+ assert trace.reward == 0 and trace.rewards == {}
77
+ assert trace.info["scoring_skipped"] == "timeout"
78
+ else:
79
+ assert trace.reward == 1
80
+
81
+
82
+ @pytest.mark.parametrize("harness,harness_runtime", grid(needs=("mcp",)), indirect=True)
83
+ async def test_max_turns(run, harness, harness_runtime):
84
+ (episode,) = await run(
85
+ "counter-tool",
86
+ harness=harness,
87
+ runtime=harness_runtime,
88
+ max_turns=1,
89
+ max_tokens=8192,
90
+ )
91
+ (trace,) = episode.traces
92
+ assert trace.num_branches == 1
93
+ assert trace.stop_condition == "max_turns", [e.message for e in trace.errors]
94
+ assert trace.num_turns == 1
95
+
96
+
97
+ @pytest.mark.parametrize("skip", [False, True], ids=["scored", "skipped"])
98
+ async def test_skip_scoring_on_stop(run, scripted_model, skip):
99
+ stop = {"fn": "counter_tool:any_response", "skip_scoring": skip}
100
+ (episode,) = await run(
101
+ "counter-tool",
102
+ harness="null",
103
+ runtime={"type": "subprocess"},
104
+ client=scripted_model,
105
+ taskset_overrides={
106
+ "task": {"constant_reward": True, "stops": {"any_response": stop}}
107
+ },
108
+ )
109
+ (trace,) = episode.traces
110
+ assert trace.stop_condition == "any_response" and trace.ok
111
+ if skip:
112
+ assert trace.reward == 0 and trace.rewards == {}
113
+ assert trace.info["scoring_skipped"] == "any_response"
114
+ else:
115
+ assert trace.reward == 1
116
+ assert "scoring_skipped" not in trace.info
@@ -36,6 +36,10 @@ class HookTask(vf.Task[HookData]):
36
36
  async def single_turn(self, trace: vf.Trace) -> bool:
37
37
  return trace.num_turns >= 1
38
38
 
39
+ @vf.stop(skip_scoring=True)
40
+ async def no_reply(self, trace: vf.Trace) -> bool:
41
+ return trace.last_reply is None
42
+
39
43
  @vf.reward
40
44
  async def lcs(self, trace: vf.Trace) -> float:
41
45
  return 0.5
@@ -49,7 +53,7 @@ async def test_config_plugged_fns_merge_and_override(tmp_path) -> None:
49
53
  fns = tmp_path / "fns.py"
50
54
  fns.write_text(PLUGGED_FNS_PY)
51
55
  config = vf.TaskConfig(
52
- stops={"single_turn": vf.DecoratedFunctionConfig(fn=f"{fns}:two_turns")},
56
+ stops={"single_turn": vf.StopFunctionConfig(fn=f"{fns}:two_turns")},
53
57
  metrics={"reply_length": vf.DecoratedFunctionConfig(fn=f"{fns}:reply_length")},
54
58
  rewards={
55
59
  "exact_match": vf.RewardFunctionConfig(fn=f"{fns}:exact_match", weight=0.5),
@@ -70,9 +74,10 @@ async def test_config_plugged_fns_merge_and_override(tmp_path) -> None:
70
74
  )
71
75
 
72
76
  # the plugged `single_turn` replaces the decorated one: no stop after one turn
73
- (stop,) = task.hooks("stop")
77
+ no_reply, stop = task.hooks("stop")
74
78
  assert stop.__name__ == "single_turn"
75
79
  assert not await stop(trace)
80
+ assert no_reply.stop_skip_scoring and not stop.stop_skip_scoring
76
81
 
77
82
  await task.score(trace)
78
83
  # `lcs` scored by the plugged marker (config wins the name clash), config weight
@@ -102,3 +107,27 @@ async def test_defer_scoring_defers_only_task_scoring() -> None:
102
107
  assert trace.rewards == {}
103
108
  await task.score(trace)
104
109
  assert set(trace.rewards) == {"fmt", "lcs"}
110
+
111
+
112
+ def test_plugged_stops_set_skip_scoring(tmp_path) -> None:
113
+ fns = tmp_path / "fns.py"
114
+ fns.write_text(PLUGGED_FNS_PY)
115
+ data = HookData(idx=0, prompt="abc")
116
+
117
+ def skips(stops: dict) -> dict[str, bool]:
118
+ config = vf.TaskConfig(stops=stops)
119
+ return {
120
+ fn.__name__: fn.stop_skip_scoring
121
+ for fn in HookTask(data, config).hooks("stop")
122
+ }
123
+
124
+ # a fresh plugged stop scores by default; a fn-less entry keeps or overrides the decorator's
125
+ assert skips({"two": vf.StopFunctionConfig(fn=f"{fns}:two_turns")})["two"] is False
126
+ assert skips(
127
+ {"two": vf.StopFunctionConfig(fn=f"{fns}:two_turns", skip_scoring=True)}
128
+ )["two"]
129
+ assert skips({"no_reply": vf.StopFunctionConfig()})["no_reply"] is True
130
+ assert (
131
+ skips({"no_reply": vf.StopFunctionConfig(skip_scoring=False)})["no_reply"]
132
+ is False
133
+ )
@@ -9,6 +9,7 @@ from verifiers.v1.configs.agent import resolve_agent
9
9
  from verifiers.v1.dialects.chat import ChatDialect
10
10
  from verifiers.v1.dialects.responses import ResponsesDialect, fold_assistant
11
11
  from verifiers.v1.graph import MessageNode, prepare_turn
12
+ from verifiers.v1.session import RolloutLimits
12
13
  from verifiers.v1.types import AssistantMessage, UserMessage
13
14
  from verifiers.v1.utils.trace_store import write_episode
14
15
 
@@ -266,3 +267,29 @@ def test_sampling_mask_from_packed_matches_lists():
266
267
  ):
267
268
  np.testing.assert_array_equal(mask.ids, ids)
268
269
  np.testing.assert_array_equal(mask.counts, counts)
270
+
271
+
272
+ def test_max_turn_tokens_limit():
273
+ limits = RolloutLimits(max_turn_tokens=16)
274
+ trace = vf.Trace(
275
+ agent=vf.AgentInfo(config=vf.AgentConfig()),
276
+ task=vf.TraceTask(type="Task", data=vf.TaskData(idx=0, prompt=None)),
277
+ )
278
+ trace.calls.append(vf.ModelCall(finish_reason="stop"))
279
+ assert limits.reached(trace) is None
280
+ # A length finish below the cap ran out of context: not this limit.
281
+ usage = vf.Usage(prompt_tokens=100, completion_tokens=8)
282
+ trace.calls.append(vf.ModelCall(finish_reason="length", usage=usage))
283
+ assert limits.reached(trace) is None
284
+ usage = vf.Usage(prompt_tokens=100, completion_tokens=16)
285
+ trace.calls.append(vf.ModelCall(finish_reason="length", usage=usage))
286
+ assert limits.reached(trace) == "max_turn_tokens"
287
+ trace.stop("max_turn_tokens")
288
+ assert trace.is_truncated
289
+
290
+
291
+ @pytest.mark.parametrize("max_tokens,expected", [(None, 16), (8, 8), (64, 16)])
292
+ def test_max_turn_tokens_caps_sampling(max_tokens, expected):
293
+ spec = vf.AgentConfig(max_turn_tokens=16)
294
+ sampling = vf.SamplingConfig(max_tokens=max_tokens)
295
+ assert resolve_agent(spec, sampling=sampling).sampling.max_tokens == expected
@@ -56,6 +56,7 @@ if TYPE_CHECKING:
56
56
  from verifiers.v1.configs.task import (
57
57
  DecoratedFunctionConfig,
58
58
  RewardFunctionConfig,
59
+ StopFunctionConfig,
59
60
  TaskConfig,
60
61
  )
61
62
  from verifiers.v1.configs.taskset import SharedTasksetConfig, TasksetConfig
@@ -301,6 +302,7 @@ _NAME_TO_MODULE = {
301
302
  "State": "verifiers.v1.state",
302
303
  "StateT": "verifiers.v1.state",
303
304
  "StaticPoolConfig": "verifiers.v1.configs.serve",
305
+ "StopFunctionConfig": "verifiers.v1.configs.task",
304
306
  "SubprocessConfig": "verifiers.v1.configs.runtime",
305
307
  "SystemMessage": "verifiers.v1.types",
306
308
  "TRACE_VERSION": "verifiers.v1.trace",
@@ -480,6 +482,7 @@ __all__ = [ # noqa: RUF022 - grouped by public API area
480
482
  "SharedTasksetConfig",
481
483
  "DecoratedFunctionConfig",
482
484
  "RewardFunctionConfig",
485
+ "StopFunctionConfig",
483
486
  "BaseConfig",
484
487
  "Harness",
485
488
  "HarnessSession",
@@ -575,6 +575,7 @@ class Agent:
575
575
  max_input_tokens=config.max_input_tokens,
576
576
  max_output_tokens=config.max_output_tokens,
577
577
  max_total_tokens=config.max_total_tokens,
578
+ max_turn_tokens=config.max_turn_tokens,
578
579
  )
579
580
  self.timeout = config.timeout
580
581
  # Env episode agents replace this with the episode's agent semaphore
@@ -66,6 +66,11 @@ class AgentConfig(BaseConfig):
66
66
  """Max output tokens per run (None = no limit)."""
67
67
  max_total_tokens: int | None = None
68
68
  """Max total tokens per run (None = no limit)."""
69
+ max_turn_tokens: int | None = Field(None, gt=0)
70
+ """Max output tokens per model response (None = no limit). Caps the sampling
71
+ `max_tokens` the framework sets on every request, whatever the harness asks for,
72
+ and stops the run once a response hits it. `sampling.max_tokens` alone caps each
73
+ response without stopping the run."""
69
74
 
70
75
  timeout: TimeoutConfig = TimeoutConfig()
71
76
  retries: RetryConfig = RetryConfig()
@@ -147,6 +152,11 @@ def resolve_agent(
147
152
  defaults = sampling or SamplingConfig()
148
153
  overrides = (spec.sampling or SamplingConfig()).model_dump(exclude_unset=True)
149
154
  merged = {**defaults.model_dump(), **merge_defaults(defaults, overrides)}
155
+ if spec.max_turn_tokens is not None:
156
+ max_tokens = merged.get("max_tokens")
157
+ merged["max_tokens"] = min(
158
+ max_tokens or spec.max_turn_tokens, spec.max_turn_tokens
159
+ )
150
160
  return spec.model_copy(
151
161
  update={
152
162
  "harness": spec.harness if spec.harness is not None else harness,
@@ -24,6 +24,12 @@ class ScoringConfig(BaseConfig):
24
24
  combined with the runtime's own rules the same way. None keeps the default: isolated
25
25
  scoring runs under `TaskData.network`, shared scoring keeps the agent phase's network,
26
26
  and Harbor's shared grading lifts the policy."""
27
+ skip_on_truncated: bool = False
28
+ """Skip task scoring for a truncated trace (`Trace.is_truncated`): it keeps no
29
+ rewards, so its reward is 0."""
30
+ skip_on_timeout: bool = False
31
+ """Skip task scoring for a trace whose stage deadline expired before scoring
32
+ (`Trace.is_timeout`): it keeps no rewards, so its reward is 0."""
27
33
 
28
34
  @field_serializer("runtime")
29
35
  def serialize_runtime(
@@ -14,13 +14,21 @@ class DecoratedFunctionConfig(BaseConfig):
14
14
  fn: str | None = None
15
15
  """Import path to the function: `pkg.module.function`, `pkg.module:function`,
16
16
  or `path/to/file.py:function`. Unset keeps the task's decorated method with the
17
- entry's name and only overrides its metadata (priority, weight)."""
17
+ entry's name and only overrides its metadata (priority, weight, skip_scoring)."""
18
18
 
19
19
  priority: int | None = None
20
20
  """Execution order, like the decorator's — higher runs first, ties break by name.
21
21
  Unset keeps the replaced method's priority (0 for a fresh function)."""
22
22
 
23
23
 
24
+ class StopFunctionConfig(DecoratedFunctionConfig):
25
+ """A plugged function standing in for a `@vf.stop` task method."""
26
+
27
+ skip_scoring: bool | None = None
28
+ """Skip task scoring for a trace this stop ends: it keeps no rewards, so its reward
29
+ is 0. Unset keeps the replaced method's setting (false for a fresh function)."""
30
+
31
+
24
32
  class RewardFunctionConfig(DecoratedFunctionConfig):
25
33
  """A plugged function standing in for a `@vf.reward` task method."""
26
34
 
@@ -39,7 +47,7 @@ class TaskConfig(BaseConfig):
39
47
  judges: Judges = Field(default_factory=list)
40
48
  """Judge plugins run after task rewards, set through `--env.taskset.task.judges`."""
41
49
 
42
- stops: dict[str, DecoratedFunctionConfig] = Field(default_factory=dict)
50
+ stops: dict[str, StopFunctionConfig] = Field(default_factory=dict)
43
51
  """Typed `Request`, `Response`, or `Trace` stop predicates plugged by name and
44
52
  merged with the task's `@vf.stop` methods (a plugged function replaces a
45
53
  decorated one with the same name)."""
@@ -157,6 +157,9 @@ class Rollout:
157
157
  for fn in discover_decorated(task, "intercept")
158
158
  ]
159
159
  stops = [(hook_boundary(fn, allow_trace=True), fn) for fn in task.hooks("stop")]
160
+ self._skip_scoring_stops = {
161
+ fn.__name__ for _, fn in stops if getattr(fn, "stop_skip_scoring", False)
162
+ }
160
163
  execution_policy = runtime_config
161
164
  self._session = RolloutSession(
162
165
  ctx=ctx,
@@ -721,6 +724,17 @@ class Rollout:
721
724
  "agent_completed",
722
725
  )
723
726
 
727
+ def _scoring_skip_reason(self) -> str | None:
728
+ """Why the resolved scoring policy, or the `skip_scoring` stop that ended this trace,
729
+ skips task scoring for it, if either does."""
730
+ if self._scoring_policy.skip_on_truncated and self.trace.is_truncated:
731
+ return "truncated"
732
+ if self._scoring_policy.skip_on_timeout and self.trace.is_timeout:
733
+ return "timeout"
734
+ if self.trace.stop_condition in self._skip_scoring_stops:
735
+ return self.trace.stop_condition
736
+ return None
737
+
724
738
  def _metrics_deadline(self) -> float:
725
739
  """Best-effort metrics get at most 30 seconds, and a tenth of a finite scoring budget."""
726
740
  budget = (
@@ -848,7 +862,14 @@ class Rollout:
848
862
  boundary(TaskError, "scoring"),
849
863
  ):
850
864
  # Cross-trace judgement runs later, after the runtime is gone.
851
- if grader is not None:
865
+ if skip_reason := self._scoring_skip_reason():
866
+ logger.info(
867
+ "rollout %s: scoring skipped (%s)",
868
+ trace.id,
869
+ skip_reason,
870
+ )
871
+ trace.info["scoring_skipped"] = skip_reason
872
+ elif grader is not None:
852
873
  try:
853
874
  await grade_task(
854
875
  grader,
@@ -87,12 +87,15 @@ class RolloutLimits:
87
87
  a @stop — and becomes the trace's stop condition. Each caps a trace computed property:
88
88
  `max_turns` -> num_turns, `max_input_tokens` -> num_input_tokens, `max_output_tokens` ->
89
89
  num_output_tokens, `max_total_tokens` -> num_total_tokens. Token caps are soft by one turn:
90
- they're checked between turns, so the turn that crosses a cap still completes."""
90
+ they're checked between turns, so the turn that crosses a cap still completes.
91
+ `max_turn_tokens` caps each response (applied through sampling) and refuses the turn
92
+ after a response that hit it."""
91
93
 
92
94
  max_turns: int | None = None
93
95
  max_input_tokens: int | None = None
94
96
  max_output_tokens: int | None = None
95
97
  max_total_tokens: int | None = None
98
+ max_turn_tokens: int | None = None
96
99
 
97
100
  def reached(self, trace: Trace) -> str | None:
98
101
  """The name of the first limit `trace` has reached, or None if within all caps."""
@@ -113,6 +116,18 @@ class RolloutLimits:
113
116
  and trace.num_total_tokens >= self.max_total_tokens
114
117
  ):
115
118
  return "max_total_tokens"
119
+ if self.max_turn_tokens is not None:
120
+ last = next((c for c in reversed(trace.calls) if c.error is None), None)
121
+ # A length finish below the cap ran out of context, not turn tokens.
122
+ if (
123
+ last is not None
124
+ and last.finish_reason == "length"
125
+ and (
126
+ last.usage is None
127
+ or last.usage.completion_tokens >= self.max_turn_tokens
128
+ )
129
+ ):
130
+ return "max_turn_tokens"
116
131
  return None
117
132
 
118
133
 
@@ -648,6 +648,7 @@ class Trace(BaseModel, Generic[DataT, StateT, AgentConfigT]):
648
648
  "max_input_tokens",
649
649
  "max_output_tokens",
650
650
  "max_total_tokens",
651
+ "max_turn_tokens",
651
652
  "compaction_failed",
652
653
  ):
653
654
  return True
@@ -83,12 +83,18 @@ def tool(func: F | None = None, name: str | None = None) -> F | Callable[[F], F]
83
83
 
84
84
 
85
85
  @overload
86
- def stop(func: F, priority: int = 0) -> F: ...
86
+ def stop(func: F, priority: int = 0, skip_scoring: bool = False) -> F: ...
87
87
  @overload
88
- def stop(func: None = None, priority: int = 0) -> Callable[[F], F]: ...
89
- def stop(func: F | None = None, priority: int = 0) -> F | Callable[[F], F]:
90
- """Stop when a typed `Request`, `Response`, or `Trace` predicate returns true."""
91
- decorator = mark("stop", stop_priority=priority)
88
+ def stop(
89
+ func: None = None, priority: int = 0, skip_scoring: bool = False
90
+ ) -> Callable[[F], F]: ...
91
+ def stop(
92
+ func: F | None = None, priority: int = 0, skip_scoring: bool = False
93
+ ) -> F | Callable[[F], F]:
94
+ """Stop when a typed `Request`, `Response`, or `Trace` predicate returns true. With
95
+ `skip_scoring`, a trace this stop ends skips task scoring: it keeps no rewards, so
96
+ its reward is 0."""
97
+ decorator = mark("stop", stop_priority=priority, stop_skip_scoring=skip_scoring)
92
98
  return decorator if func is None else decorator(func)
93
99
 
94
100
 
@@ -15,7 +15,11 @@ from pydantic_config import BaseConfig
15
15
  from verifiers.v1.configs.env import EnvConfig
16
16
  from verifiers.v1.configs.harness import HarnessConfig
17
17
  from verifiers.v1.configs.judge import JudgeConfig
18
- from verifiers.v1.configs.task import DecoratedFunctionConfig, RewardFunctionConfig
18
+ from verifiers.v1.configs.task import (
19
+ DecoratedFunctionConfig,
20
+ RewardFunctionConfig,
21
+ StopFunctionConfig,
22
+ )
19
23
  from verifiers.v1.configs.taskset import TasksetConfig
20
24
  from verifiers.v1.env import Env
21
25
  from verifiers.v1.envs.single_agent import SingleAgentEnv
@@ -279,6 +283,11 @@ def load_plugged_fn(
279
283
  if weight is None:
280
284
  weight = getattr(fn, "_vf_weight", 1.0)
281
285
  plugged._vf_weight = weight
286
+ if isinstance(config, StopFunctionConfig):
287
+ skip_scoring = config.skip_scoring
288
+ if skip_scoring is None:
289
+ skip_scoring = getattr(fn, "stop_skip_scoring", False)
290
+ plugged.stop_skip_scoring = skip_scoring
282
291
  return plugged
283
292
 
284
293
 
@@ -1,56 +0,0 @@
1
- """The seat's caps stop a rollout that would run on: the counter task wants three tool
2
- turns (counter-tool), and each cap ends it after the first with its own stop
3
- condition. The turn cap also runs across the harness x runtime grid, since each program
4
- handles a refused request in its own way."""
5
-
6
- import pytest
7
- from grid import grid
8
-
9
- CAPS = [
10
- pytest.param({"max_turns": 1}, "max_turns", id="max-turns"),
11
- pytest.param({"max_input_tokens": 1}, "max_input_tokens", id="max-input-tokens"),
12
- pytest.param({"max_output_tokens": 1}, "max_output_tokens", id="max-output-tokens"),
13
- pytest.param({"max_total_tokens": 1}, "max_total_tokens", id="max-total-tokens"),
14
- ]
15
-
16
-
17
- @pytest.mark.parametrize("cap,stop_condition", CAPS)
18
- async def test_cap(run, cap, stop_condition):
19
- (episode,) = await run(
20
- "counter-tool",
21
- harness="null",
22
- runtime={"type": "prime"},
23
- env={"agent": cap},
24
- )
25
- (trace,) = episode.traces
26
- assert trace.num_branches == 1
27
- assert trace.stop_condition == stop_condition
28
- assert trace.is_truncated
29
- assert trace.num_turns == 1
30
-
31
-
32
- async def test_rollout_timeout(run):
33
- (episode,) = await run(
34
- "counter-tool",
35
- harness="null",
36
- runtime={"type": "prime"},
37
- rollout_timeout=1,
38
- )
39
- (trace,) = episode.traces
40
- assert trace.is_timeout
41
- assert trace.stop_condition == "agent_timeout"
42
-
43
-
44
- @pytest.mark.parametrize("harness,harness_runtime", grid(needs=("mcp",)), indirect=True)
45
- async def test_max_turns(run, harness, harness_runtime):
46
- (episode,) = await run(
47
- "counter-tool",
48
- harness=harness,
49
- runtime=harness_runtime,
50
- max_turns=1,
51
- max_tokens=8192,
52
- )
53
- (trace,) = episode.traces
54
- assert trace.num_branches == 1
55
- assert trace.stop_condition == "max_turns", [e.message for e in trace.errors]
56
- assert trace.num_turns == 1
File without changes