verifiers 0.3.2.dev204__tar.gz → 0.3.2.dev206__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 (229) hide show
  1. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/PKG-INFO +2 -2
  2. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/pyproject.toml +1 -1
  3. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_trace.py +41 -9
  4. verifiers-0.3.2.dev206/tests/v1/test_tunnel_watchdog.py +109 -0
  5. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/agent.py +7 -4
  6. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/clients/train.py +1 -1
  7. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/agent.py +13 -14
  8. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/dialects/anthropic.py +1 -1
  9. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/dialects/chat.py +1 -1
  10. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/dialects/responses.py +1 -1
  11. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/tunnel/prime.py +15 -9
  12. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judge.py +23 -4
  13. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/types.py +21 -12
  14. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/generic.py +11 -3
  15. verifiers-0.3.2.dev204/tests/v1/test_tunnel_watchdog.py +0 -71
  16. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/.gitignore +0 -0
  17. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/LICENSE +0 -0
  18. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/README.md +0 -0
  19. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/conftest.py +0 -0
  20. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/agent_user_v1.py +0 -0
  21. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/counter_tool_v1.py +0 -0
  22. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/delivery_behaviors.py +0 -0
  23. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/duet_v1.py +0 -0
  24. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/echo_acp_resume_v1.py +0 -0
  25. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/echo_agentic_v1.py +0 -0
  26. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/echo_tool_v1.py +0 -0
  27. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/echo_user_sim_v1.py +0 -0
  28. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/echo_v1.py +0 -0
  29. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/pyproject.toml +0 -0
  30. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/fixtures/tool_response_image_v1.py +0 -0
  31. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_color_codeword_tasks.py +0 -0
  32. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_configs.py +0 -0
  33. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_delivery_behaviors.py +0 -0
  34. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_e2e.py +0 -0
  35. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_envs.py +0 -0
  36. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_graph.py +0 -0
  37. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_judges.py +0 -0
  38. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_platform_run.py +0 -0
  39. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_scoring.py +0 -0
  40. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_serve_delta.py +0 -0
  41. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/tests/v1/test_taskset.py +0 -0
  42. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/__init__.py +0 -0
  43. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/__init__.py +0 -0
  44. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/acp/__init__.py +0 -0
  45. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/acp/runner.py +0 -0
  46. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/__init__.py +0 -0
  47. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/dashboard/__init__.py +0 -0
  48. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/dashboard/base.py +0 -0
  49. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/dashboard/eval.py +0 -0
  50. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/dashboard/replay.py +0 -0
  51. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/dashboard/validate.py +0 -0
  52. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/debug.py +0 -0
  53. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/eval/__init__.py +0 -0
  54. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/eval/hint.py +0 -0
  55. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/eval/main.py +0 -0
  56. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/eval/resume.py +0 -0
  57. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/eval/runner.py +0 -0
  58. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/gepa.py +0 -0
  59. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/init.py +0 -0
  60. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/output.py +0 -0
  61. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/replay.py +0 -0
  62. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/resolve.py +0 -0
  63. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/resume.py +0 -0
  64. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/cli/validate.py +0 -0
  65. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/clients/__init__.py +0 -0
  66. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/clients/base.py +0 -0
  67. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/clients/client.py +0 -0
  68. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/clients/eval.py +0 -0
  69. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/__init__.py +0 -0
  70. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/__init__.py +0 -0
  71. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/debug.py +0 -0
  72. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/env.py +0 -0
  73. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/eval.py +0 -0
  74. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/init.py +0 -0
  75. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/replay.py +0 -0
  76. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/cli/validate.py +0 -0
  77. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/client.py +0 -0
  78. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/env.py +0 -0
  79. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/harness.py +0 -0
  80. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/judge.py +0 -0
  81. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/retries.py +0 -0
  82. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/runtime.py +0 -0
  83. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/select.py +0 -0
  84. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/serve.py +0 -0
  85. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/task.py +0 -0
  86. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/configs/taskset.py +0 -0
  87. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/dialects/__init__.py +0 -0
  88. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/dialects/base.py +0 -0
  89. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/env.py +0 -0
  90. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/__init__.py +0 -0
  91. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
  92. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/agentic_judge/env.py +0 -0
  93. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
  94. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/best_of_n/env.py +0 -0
  95. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/isolated_verifier/__init__.py +0 -0
  96. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/isolated_verifier/env.py +0 -0
  97. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/shared_agentic_judge/__init__.py +0 -0
  98. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/single_agent/__init__.py +0 -0
  99. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/single_agent/env.py +0 -0
  100. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/user_sim/__init__.py +0 -0
  101. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/envs/user_sim/env.py +0 -0
  102. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/episode.py +0 -0
  103. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/errors.py +0 -0
  104. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/__init__.py +0 -0
  105. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/adapter.py +0 -0
  106. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/config.py +0 -0
  107. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/dataset.py +0 -0
  108. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/reflection.py +0 -0
  109. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/gepa/runner.py +0 -0
  110. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/graph.py +0 -0
  111. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harness.py +0 -0
  112. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/__init__.py +0 -0
  113. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/bash/__init__.py +0 -0
  114. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/bash/harness.py +0 -0
  115. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
  116. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
  117. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/browser_use/program.py +0 -0
  118. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
  119. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/claude_code/harness.py +0 -0
  120. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/codex/__init__.py +0 -0
  121. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
  122. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/codex/harness.py +0 -0
  123. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
  124. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/hermes_agent/harness.py +0 -0
  125. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
  126. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
  127. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/kimi_code/harness.py +0 -0
  128. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
  129. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
  130. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
  131. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/node.py +0 -0
  132. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/null/__init__.py +0 -0
  133. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/null/harness.py +0 -0
  134. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
  135. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
  136. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/pi/__init__.py +0 -0
  137. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
  138. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/pi/harness.py +0 -0
  139. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
  140. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/prime_agent/harness.py +0 -0
  141. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
  142. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/rlm/harness.py +0 -0
  143. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
  144. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
  145. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
  146. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/__init__.py +0 -0
  147. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/compaction.py +0 -0
  148. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/core.py +0 -0
  149. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/install.py +0 -0
  150. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/launch.py +0 -0
  151. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/harnesses/utils/mcp.py +0 -0
  152. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/__init__.py +0 -0
  153. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/base.py +0 -0
  154. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/pool.py +0 -0
  155. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/server.py +0 -0
  156. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/tunnel/__init__.py +0 -0
  157. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/tunnel/base.py +0 -0
  158. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/interception/tunnel/custom.py +0 -0
  159. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/__init__.py +0 -0
  160. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/decision.py +0 -0
  161. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/reference.py +0 -0
  162. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/reference.txt +0 -0
  163. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/rubric.py +0 -0
  164. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/judges/rubric.txt +0 -0
  165. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/mcp/__init__.py +0 -0
  166. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/mcp/launch.py +0 -0
  167. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/mcp/server.py +0 -0
  168. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/mcp/toolset.py +0 -0
  169. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/rollout.py +0 -0
  170. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/__init__.py +0 -0
  171. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/apptainer.py +0 -0
  172. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/base.py +0 -0
  173. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/container.py +0 -0
  174. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/docker/__init__.py +0 -0
  175. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/docker/egress.py +0 -0
  176. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/e2b.py +0 -0
  177. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/limiters.py +0 -0
  178. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/modal.py +0 -0
  179. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/prime.py +0 -0
  180. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/runtimes/subprocess.py +0 -0
  181. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/semantic.py +0 -0
  182. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/__init__.py +0 -0
  183. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/client.py +0 -0
  184. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/delta.py +0 -0
  185. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/encoding.py +0 -0
  186. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/pool.py +0 -0
  187. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/server.py +0 -0
  188. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/serve/types.py +0 -0
  189. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/session.py +0 -0
  190. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/state.py +0 -0
  191. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/task.py +0 -0
  192. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/taskset.py +0 -0
  193. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/__init__.py +0 -0
  194. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
  195. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/harbor/compose.py +0 -0
  196. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/harbor/env.py +0 -0
  197. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
  198. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
  199. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
  200. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
  201. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
  202. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
  203. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
  204. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
  205. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
  206. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
  207. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
  208. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/trace.py +0 -0
  209. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/__init__.py +0 -0
  210. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/aio.py +0 -0
  211. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/artifacts.py +0 -0
  212. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/compile.py +0 -0
  213. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/decorators.py +0 -0
  214. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/eval.py +0 -0
  215. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/format.py +0 -0
  216. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/git.py +0 -0
  217. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/image.py +0 -0
  218. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/interrupt.py +0 -0
  219. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/loaders.py +0 -0
  220. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/logging.py +0 -0
  221. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/memory.py +0 -0
  222. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/paths.py +0 -0
  223. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/platform.py +0 -0
  224. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/prime.py +0 -0
  225. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/retries.py +0 -0
  226. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/scope.py +0 -0
  227. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/score.py +0 -0
  228. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/verifiers/v1/utils/trace_store.py +0 -0
  229. {verifiers-0.3.2.dev204 → verifiers-0.3.2.dev206}/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.dev204
3
+ Version: 0.3.2.dev206
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
@@ -37,7 +37,7 @@ Requires-Dist: openai<3.0.0,>=2.54.0
37
37
  Requires-Dist: prime-pydantic-config[toml]>=0.4.3
38
38
  Requires-Dist: prime-runs>=0.1.4
39
39
  Requires-Dist: prime-sandboxes>=0.4.2
40
- Requires-Dist: prime-tunnel>=0.1.13
40
+ Requires-Dist: prime-tunnel>=0.1.14
41
41
  Requires-Dist: pydantic>=2.12.3
42
42
  Requires-Dist: pyzmq>=27.1.0
43
43
  Requires-Dist: renderers[multimodal]>=0.1.12.dev2
@@ -32,7 +32,7 @@ dependencies = [
32
32
  "numpy>=2.1.0",
33
33
  "math-verify>=0.8.0",
34
34
  "openai>=2.54.0,<3.0.0",
35
- "prime-tunnel>=0.1.13",
35
+ "prime-tunnel>=0.1.14",
36
36
  "prime-sandboxes>=0.4.2",
37
37
  "prime-runs>=0.1.4",
38
38
  "pydantic>=2.12.3",
@@ -10,6 +10,7 @@ import pytest
10
10
 
11
11
  import verifiers.v1 as vf
12
12
  from verifiers.v1.agent import Interaction
13
+ from verifiers.v1.configs.agent import resolve_agent
13
14
  from verifiers.v1.dialects.chat import ChatDialect
14
15
  from verifiers.v1.dialects.responses import ResponsesDialect, fold_assistant
15
16
  from verifiers.v1.graph import MessageNode, prepare_turn
@@ -127,10 +128,30 @@ async def test_failed_segment_does_not_reuse_prior_root_reply():
127
128
  assert trace.last_reply == "current partial reply"
128
129
 
129
130
 
130
- def test_bare_trace_round_trip():
131
+ @pytest.mark.parametrize(
132
+ "sampling",
133
+ [
134
+ None,
135
+ {},
136
+ {"reasoning_effort": "high"},
137
+ {"temperature": 0.7, "max_tokens": 128, "reasoning_effort": "high"},
138
+ {"temperature": None},
139
+ {"max_completion_tokens": None},
140
+ {"extra_body": {"top_k": None}},
141
+ {"extra_body": None},
142
+ {"top_k": 10, "extra_body": {"frequency_penalty": 0.5}},
143
+ {"extra_body": {"top_k": 20, "max_completion_tokens": None}},
144
+ ],
145
+ )
146
+ def test_bare_trace_round_trip(sampling):
147
+ spec = vf.AgentConfig(sampling=sampling)
148
+ defaults = vf.SamplingConfig(temperature=0.7, max_tokens=128, top_k=40)
149
+ # Resolve the live overrides before serializing the effective config on a trace.
150
+ resolved = resolve_agent(spec, sampling=defaults)
151
+ assert set(vf.SamplingConfig.model_fields) <= resolved.sampling.model_fields_set
131
152
  # The minimal trace: a base task, no nodes, no extras — dump and back into a plain Trace.
132
153
  tr = vf.Trace(
133
- agent=vf.AgentInfo(config=vf.AgentConfig()),
154
+ agent=vf.AgentInfo(config=resolved),
134
155
  task=vf.TraceTask(
135
156
  type="Task",
136
157
  data=vf.TaskData(idx=3, prompt="hello"),
@@ -138,13 +159,24 @@ def test_bare_trace_round_trip():
138
159
  hash="content-digest",
139
160
  ),
140
161
  )
141
- rt = vf.Trace.model_validate(tr.model_dump())
142
- assert rt.id == tr.id
143
- assert rt.task.type == "Task"
144
- assert rt.task.data.idx == 3 and rt.task.data.prompt == "hello"
145
- assert rt.task.key == "dataset/example-3" and rt.task.hash == "content-digest"
146
- assert rt.num_turns == 0 and rt.num_branches == 0
147
- assert rt.reward == 0.0 and rt.errors == []
162
+ episode = vf.Episode(task=tr.task, traces=[tr], ok=True)
163
+ for rt in (
164
+ vf.Trace.model_validate(tr.model_dump()),
165
+ vf.Trace.model_validate_json(tr.model_dump_json(exclude_none=True)),
166
+ vf.Trace.model_validate(tr.to_record()),
167
+ vf.Episode.model_validate_json(
168
+ episode.model_dump_json(exclude_none=True)
169
+ ).traces[0],
170
+ vf.Episode.model_validate(episode.to_record()).traces[0],
171
+ ):
172
+ assert rt.id == tr.id
173
+ assert rt.task.type == "Task"
174
+ assert rt.task.data.idx == 3 and rt.task.data.prompt == "hello"
175
+ assert rt.task.key == "dataset/example-3" and rt.task.hash == "content-digest"
176
+ assert rt.num_turns == 0 and rt.num_branches == 0
177
+ assert rt.reward == 0.0 and rt.errors == []
178
+ assert rt.agent.config == tr.agent.config
179
+ assert rt.agent.config.sampling.model_dump() == resolved.sampling.model_dump()
148
180
 
149
181
 
150
182
  def test_custom_task_state_round_trip(tmp_path):
@@ -0,0 +1,109 @@
1
+ """The prime tunnel watchdog restarts frpc when the tunnel service has the tunnel
2
+ disconnected or frpc has exited, leaves it alone otherwise, and stops watching a tunnel
3
+ whose registration is gone."""
4
+
5
+ import asyncio
6
+
7
+ import pytest
8
+ from prime_tunnel import TunnelGoneError, TunnelStatus
9
+
10
+ from verifiers.v1.interception.tunnel import prime
11
+
12
+ pytestmark = pytest.mark.asyncio
13
+
14
+ GONE = (None, "terminated", "expired")
15
+
16
+
17
+ class FakeClient:
18
+ def __init__(self, statuses, running=True, restart_error=None):
19
+ self.statuses = list(statuses)
20
+ self.is_running = running
21
+ self.is_gone = False
22
+ self.tunnel_id = "t-0-test"
23
+ self.restart_error = restart_error
24
+ self.restarts = 0
25
+ self.checks = 0
26
+
27
+ async def restart(self):
28
+ self.restarts += 1
29
+ if self.restart_error is not None:
30
+ raise self.restart_error
31
+ self.is_running = True
32
+
33
+ async def status(self):
34
+ self.checks += 1
35
+ registration = self.statuses.pop(0) if self.statuses else "connected"
36
+ if isinstance(registration, Exception):
37
+ raise registration
38
+ self.is_gone = self.is_gone or registration in GONE
39
+ return TunnelStatus(
40
+ tunnel_id=self.tunnel_id,
41
+ running=self.is_running,
42
+ registration=registration,
43
+ gone=self.is_gone,
44
+ )
45
+
46
+
47
+ async def watch(client, checks, monkeypatch):
48
+ """Run the watchdog for about `checks` checks; how many restarts it made."""
49
+ monkeypatch.setattr(prime, "CHECK_SECONDS", 0.01)
50
+ task = asyncio.create_task(prime._watch(client, "https://t"))
51
+ await asyncio.sleep(0.0125 * checks)
52
+ task.cancel()
53
+ await asyncio.wait({task})
54
+ return client.restarts
55
+
56
+
57
+ async def stops(client, monkeypatch):
58
+ """Run the watchdog until it gives the tunnel up."""
59
+ monkeypatch.setattr(prime, "CHECK_SECONDS", 0.01)
60
+ await asyncio.wait_for(prime._watch(client, "https://t"), 1)
61
+
62
+
63
+ async def test_connected_is_left_alone(monkeypatch):
64
+ assert await watch(FakeClient(["connected"] * 10), 8, monkeypatch) == 0
65
+
66
+
67
+ async def test_one_disconnected_check_is_not_enough(monkeypatch):
68
+ client = FakeClient(["disconnected", "connected"] * 5)
69
+ assert await watch(client, 8, monkeypatch) == 0
70
+
71
+
72
+ async def test_disconnected_twice_restarts_once(monkeypatch):
73
+ client = FakeClient(["disconnected", "disconnected"])
74
+ assert await watch(client, 8, monkeypatch) == 1
75
+
76
+
77
+ async def test_exited_frpc_restarts_without_asking(monkeypatch):
78
+ client = FakeClient([RuntimeError("api down")] * 10, running=False)
79
+ assert await watch(client, 4, monkeypatch) == 1
80
+
81
+
82
+ async def test_unreachable_service_is_no_verdict(monkeypatch):
83
+ client = FakeClient([RuntimeError("api down")] * 10)
84
+ assert await watch(client, 8, monkeypatch) == 0
85
+
86
+
87
+ @pytest.mark.parametrize("registration", GONE)
88
+ async def test_gone_registration_stops_watching(registration, monkeypatch):
89
+ client = FakeClient([registration])
90
+ await stops(client, monkeypatch)
91
+ assert client.restarts == 0
92
+
93
+
94
+ async def test_gone_reported_by_frpc_stops_watching(monkeypatch):
95
+ client = FakeClient([])
96
+ client.is_gone = True
97
+ await stops(client, monkeypatch)
98
+ assert (client.checks, client.restarts) == (0, 0)
99
+
100
+
101
+ async def test_restart_refused_as_gone_stops_watching(monkeypatch):
102
+ client = FakeClient([], running=False, restart_error=TunnelGoneError("inactive"))
103
+ await stops(client, monkeypatch)
104
+ assert client.restarts == 1
105
+
106
+
107
+ async def test_failed_restart_is_tried_again(monkeypatch):
108
+ client = FakeClient([], running=False, restart_error=RuntimeError("frpc"))
109
+ assert await watch(client, 6, monkeypatch) >= 2
@@ -21,7 +21,12 @@ from verifiers.v1.clients import (
21
21
  EvalClientConfig,
22
22
  ModelContext,
23
23
  )
24
- from verifiers.v1.configs.agent import AgentConfig, TimeoutConfig, agent_config_fields
24
+ from verifiers.v1.configs.agent import (
25
+ AgentConfig,
26
+ TimeoutConfig,
27
+ agent_config_fields,
28
+ resolve_agent,
29
+ )
25
30
  from verifiers.v1.configs.runtime import NetworkPolicyConfig
26
31
  from verifiers.v1.dialects import parse_message
27
32
  from verifiers.v1.harness import Harness
@@ -41,7 +46,6 @@ from verifiers.v1.trace import Trace
41
46
  from verifiers.v1.types import (
42
47
  AssistantMessage,
43
48
  Messages,
44
- Sampling,
45
49
  ToolMessage,
46
50
  UserMessage,
47
51
  )
@@ -550,8 +554,7 @@ class Agent:
550
554
  config = config.model_copy(
551
555
  update={"harness": harness_config_type("bash")(id="bash")}
552
556
  )
553
- if config.sampling is None:
554
- config = config.model_copy(update={"sampling": Sampling()})
557
+ config = resolve_agent(config)
555
558
  self.config = config
556
559
  self.harness = load_harness(config.harness)
557
560
  self.ctx = ModelContext(
@@ -375,7 +375,7 @@ class TrainClient(Client):
375
375
  prompt_ids: list[int] | None = None
376
376
  prompt_attribution: RenderedTokens | None = None
377
377
  model = body["model"]
378
- sampling_params = sampling.wire_args()
378
+ sampling_params = sampling.model_dump(exclude_none=True)
379
379
  chat_template_kwargs = sampling_params.pop("chat_template_kwargs", None)
380
380
  cache_salt = sampling_params.pop("cache_salt", None)
381
381
  pool = ElasticRendererPool(
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- from pydantic import BaseModel, Field, SerializeAsAny, model_validator
5
+ from pydantic import BaseModel, Field, SerializeAsAny, field_serializer, model_validator
6
6
  from pydantic_config import BaseConfig
7
7
 
8
8
  from verifiers.v1.clients import ClientConfig
@@ -10,7 +10,7 @@ from verifiers.v1.configs.harness import HarnessConfig, WireHarnessConfig
10
10
  from verifiers.v1.configs.retries import RetryConfig
11
11
  from verifiers.v1.runtimes import PrimeConfig, RuntimeConfig
12
12
  from verifiers.v1.types import SamplingConfig
13
- from verifiers.v1.utils.generic import deep_merge
13
+ from verifiers.v1.utils.generic import merge_defaults
14
14
 
15
15
 
16
16
  class TimeoutConfig(BaseConfig):
@@ -57,6 +57,12 @@ class AgentConfig(BaseConfig):
57
57
  network_notice: bool = True
58
58
  """Include the runtime's network restrictions in the agent's prompt."""
59
59
 
60
+ @field_serializer("sampling")
61
+ def _sampling_overrides(self, sampling: SamplingConfig | None) -> dict | None:
62
+ # An unresolved agent carries only overrides across env-server boundaries.
63
+ # resolve_agent fills every field before the config is recorded on a trace.
64
+ return sampling.model_dump(exclude_unset=True) if sampling is not None else None
65
+
60
66
  @model_validator(mode="before")
61
67
  @classmethod
62
68
  def _resolve_harness(cls, data):
@@ -99,9 +105,7 @@ def merge_agent_defaults(config: type[BaseModel], data: Any) -> Any:
99
105
  if isinstance(field.default, AgentConfig) and isinstance(
100
106
  data.get(name), dict
101
107
  ):
102
- data[name] = deep_merge(
103
- field.default.model_dump(exclude_none=True), data[name]
104
- )
108
+ data[name] = merge_defaults(field.default, data[name])
105
109
  return data
106
110
 
107
111
 
@@ -116,19 +120,14 @@ def resolve_agent(
116
120
  """`spec` with what it leaves unset filled from the run's defaults; its own
117
121
  sampling values merge over the run's. The one place a seat's identity resolves,
118
122
  for configured agent roles."""
119
- merged = spec.sampling if sampling is None else sampling
120
- if sampling is not None and spec.sampling is not None:
121
- merged = sampling.model_copy(
122
- update=deep_merge(
123
- sampling.model_dump(exclude_unset=True),
124
- spec.sampling.model_dump(exclude_unset=True),
125
- )
126
- )
123
+ defaults = sampling or SamplingConfig()
124
+ overrides = (spec.sampling or SamplingConfig()).model_dump(exclude_unset=True)
125
+ merged = {**defaults.model_dump(), **merge_defaults(defaults, overrides)}
127
126
  return spec.model_copy(
128
127
  update={
129
128
  "harness": spec.harness if spec.harness is not None else harness,
130
129
  "model": spec.model if spec.model is not None else model,
131
130
  "client": spec.client if spec.client is not None else client,
132
- "sampling": merged,
131
+ "sampling": SamplingConfig.model_validate(merged),
133
132
  }
134
133
  )
@@ -660,7 +660,7 @@ class AnthropicDialect(Dialect[AnthropicMessage]):
660
660
  # Preserve native fields except the eval's model + sampling. `temperature`/`top_p` are
661
661
  # authoritative (always dropped, the eval's applied if set); `max_tokens` is required by
662
662
  # the API, so the program's is kept unless the eval sets one.
663
- s = sampling.wire_args()
663
+ s = sampling.model_dump(exclude_none=True)
664
664
  reasoning_effort = s.pop("reasoning_effort", None)
665
665
  sampling_output_config = s.pop("output_config", None)
666
666
  overrides: dict = {**s, "model": model}
@@ -586,7 +586,7 @@ class ChatDialect(Dialect[ChatCompletion]):
586
586
  # Preserve the program's native fields, overlaying only what the eval owns: the model and
587
587
  # the sampling knobs it set. The selected model is authoritative even if a permissive
588
588
  # sampling config carries an extra field named `model`.
589
- overrides = sampling.wire_args()
589
+ overrides = sampling.model_dump(exclude_none=True)
590
590
  max_token_keys = {"max_tokens", "max_completion_tokens"}
591
591
  max_tokens_overridden = not max_token_keys.isdisjoint(overrides)
592
592
  steered = {
@@ -754,7 +754,7 @@ class ResponsesDialect(Dialect[OpenAIResponse]):
754
754
  ) -> RawRequest:
755
755
  # Preserve native fields except the eval's model + sampling, mapped to the Responses shape
756
756
  # (`max_tokens` -> `max_output_tokens`); sampling is authoritative.
757
- s = sampling.wire_args()
757
+ s = sampling.model_dump(exclude_none=True)
758
758
  max_tokens = s.pop("max_tokens", None)
759
759
  reasoning_effort = s.pop("reasoning_effort", None)
760
760
  sampling_reasoning = s.pop("reasoning", None)
@@ -53,22 +53,25 @@ CHECK_SECONDS = 20
53
53
  async def _watch(client: "TunnelClient", url: str) -> None:
54
54
  """Keep a held tunnel up. A tunnel service hiccup can leave frpc running while the
55
55
  service has it disconnected for good, and every request to the URL then hangs or
56
- 404s; frpc can also exit. Either way, restart it."""
56
+ 404s; frpc can also exit. Either way, restart it. A tunnel the service has deleted
57
+ or expired can't be restarted, so stop watching it."""
58
+ from prime_tunnel import TunnelGoneError
59
+
57
60
  strikes = 0
58
61
  while True:
59
62
  await asyncio.sleep(CHECK_SECONDS * random.uniform(0.75, 1.25))
60
- if client.is_running:
63
+ if client.is_running and not client.is_gone:
61
64
  try:
62
- info = await client._client.get_tunnel(client.tunnel_id)
65
+ status = await client.status()
63
66
  except Exception as e: # noqa: BLE001 - the service is unreachable: no verdict
64
67
  logger.debug("tunnel %s: state check failed: %s", url, e)
65
68
  continue
66
- if info is None:
67
- logger.error("tunnel %s: registration gone; cannot repair", url)
68
- return
69
- strikes = strikes + 1 if info.status == "disconnected" else 0
70
- if strikes < 2:
71
- continue
69
+ strikes = strikes + 1 if status.registration == "disconnected" else 0
70
+ if client.is_gone:
71
+ logger.error("tunnel %s: registration gone; cannot repair", url)
72
+ return
73
+ if client.is_running and strikes < 2:
74
+ continue
72
75
  logger.warning(
73
76
  "tunnel %s: %s; restarting frpc",
74
77
  url,
@@ -76,6 +79,9 @@ async def _watch(client: "TunnelClient", url: str) -> None:
76
79
  )
77
80
  try:
78
81
  await client.restart()
82
+ except TunnelGoneError:
83
+ logger.error("tunnel %s: registration gone; cannot repair", url)
84
+ return
79
85
  except Exception as e: # noqa: BLE001 - tried again on the next check
80
86
  logger.warning("tunnel %s: frpc restart failed: %s", url, e)
81
87
  else:
@@ -53,6 +53,9 @@ import re
53
53
  from collections.abc import Callable, Mapping, Sequence
54
54
  from typing import TYPE_CHECKING, Any, Generic, Literal, cast
55
55
 
56
+ from openai.types.chat.completion_create_params import (
57
+ CompletionCreateParamsNonStreaming,
58
+ )
56
59
  from pydantic import BaseModel
57
60
  from typing_extensions import TypeVar
58
61
 
@@ -62,8 +65,8 @@ from verifiers.v1.configs.judge import (
62
65
  judge_key,
63
66
  )
64
67
  from verifiers.v1.dialects.chat import message_to_wire
65
- from verifiers.v1.types import Messages, Usage
66
- from verifiers.v1.utils.generic import concrete_type
68
+ from verifiers.v1.types import Messages, SamplingConfig, Usage
69
+ from verifiers.v1.utils.generic import concrete_type, merge_defaults
67
70
  from verifiers.v1.utils.score import parse_judge_choice
68
71
 
69
72
  if TYPE_CHECKING:
@@ -176,8 +179,24 @@ class Judge(Generic[ParsedT, ConfigT]):
176
179
  else [message_to_wire(m) for m in messages]
177
180
  )
178
181
  kwargs: dict[str, Any] = {"model": self.config.model, "messages": wire}
179
- kwargs.update(self.config.sampling.model_dump(exclude_none=True))
180
- kwargs.update(sampling)
182
+ # Transport options are SDK arguments, not model sampling parameters.
183
+ request_options = {
184
+ key: sampling.pop(key)
185
+ for key in ("extra_headers", "extra_query", "timeout")
186
+ if key in sampling
187
+ }
188
+ params = SamplingConfig.model_validate(
189
+ merge_defaults(self.config.sampling, sampling)
190
+ ).model_dump(exclude_none=True)
191
+ sdk_fields = CompletionCreateParamsNonStreaming.__annotations__
192
+ kwargs.update(
193
+ {key: value for key, value in params.items() if key in sdk_fields}
194
+ )
195
+ # The SDK accepts provider-specific parameters only through extra_body.
196
+ kwargs["extra_body"] = {
197
+ key: value for key, value in params.items() if key not in sdk_fields
198
+ }
199
+ kwargs.update(request_options)
181
200
 
182
201
  response: JudgeResponse[Any] | None = None
183
202
  try:
@@ -3,7 +3,13 @@ from dataclasses import dataclass
3
3
  from typing import Annotated, Any, Literal
4
4
 
5
5
  import numpy as np
6
- from pydantic import AliasChoices, BaseModel, ConfigDict, Field
6
+ from pydantic import (
7
+ AliasChoices,
8
+ BaseModel,
9
+ ConfigDict,
10
+ Field,
11
+ model_validator,
12
+ )
7
13
  from typing_extensions import TypedDict
8
14
 
9
15
 
@@ -276,17 +282,20 @@ class SamplingConfig(BaseModel):
276
282
  None, validation_alias=AliasChoices("max_tokens", "max_completion_tokens")
277
283
  )
278
284
 
279
- def wire_args(self) -> dict[str, Any]:
280
- """Flatten OpenAI-style ``extra_body`` before building a provider request."""
281
- args = self.model_dump(exclude_none=True)
282
- extra_body = {
283
- key: value
284
- for key, value in (args.pop("extra_body", None) or {}).items()
285
- if value is not None
286
- }
287
- if "max_tokens" in args:
288
- extra_body.pop("max_completion_tokens", None)
289
- return {**extra_body, **args}
285
+ @model_validator(mode="before")
286
+ @classmethod
287
+ def normalize(cls, data: Any) -> Any:
288
+ """Use one key per parameter before merging overrides, retaining null clears."""
289
+ if not isinstance(data, dict):
290
+ return data
291
+ normalized = {}
292
+ for layer in (data.get("extra_body") or {}, data):
293
+ layer = dict(layer)
294
+ if "max_completion_tokens" in layer:
295
+ layer.setdefault("max_tokens", layer.pop("max_completion_tokens"))
296
+ layer.pop("extra_body", None)
297
+ normalized.update(layer)
298
+ return normalized
290
299
 
291
300
 
292
301
  Sampling = SamplingConfig
@@ -4,6 +4,8 @@ from typing import TypeVar, get_args, get_origin
4
4
 
5
5
  from pydantic import BaseModel, ValidationError
6
6
 
7
+ from verifiers.v1.types import SamplingConfig
8
+
7
9
  T = TypeVar("T")
8
10
 
9
11
 
@@ -52,15 +54,21 @@ def merge_defaults(defaults: BaseModel, raw: dict | None) -> dict:
52
54
  `{}` becomes `{type = "grpo", kl = 0.1}`, `{kl = 0.5}` becomes
53
55
  `{type = "grpo", kl = 0.5}`, and `{type = "max_rl"}` stays `{type = "max_rl"}`.
54
56
  """
55
- # `deep_merge` detects an `id`/`type` switch only on nested blocks, so wrap the
56
- # block once to detect a switch of the block itself too.
57
+ raw = dict(raw or {})
58
+ if isinstance(defaults, SamplingConfig):
59
+ raw = SamplingConfig.model_validate(raw).model_dump(exclude_unset=True)
57
60
  identity = {
58
61
  k: getattr(defaults, k)
59
62
  for k in ("id", "type")
60
63
  if k in type(defaults).model_fields
61
64
  }
65
+ if any(key in raw and raw[key] != value for key, value in identity.items()):
66
+ return raw
67
+ for name, value in defaults:
68
+ if isinstance(value, BaseModel) and isinstance(raw.get(name), dict):
69
+ raw[name] = merge_defaults(value, raw[name])
62
70
  block = {**identity, **_dump_set(defaults)}
63
- return deep_merge({"block": block}, {"block": raw or {}})["block"]
71
+ return deep_merge(block, raw)
64
72
 
65
73
 
66
74
  def _dump_set(config: BaseModel) -> dict:
@@ -1,71 +0,0 @@
1
- """The prime tunnel watchdog restarts frpc when the tunnel service has the tunnel
2
- disconnected or frpc has exited, and leaves it alone otherwise."""
3
-
4
- import asyncio
5
- from types import SimpleNamespace
6
-
7
- import pytest
8
-
9
- from verifiers.v1.interception.tunnel import prime
10
-
11
- pytestmark = pytest.mark.asyncio
12
-
13
-
14
- class FakeClient:
15
- def __init__(self, statuses, running=True):
16
- self.statuses = list(statuses)
17
- self.is_running = running
18
- self.tunnel_id = "t-0-test"
19
- self._client = self
20
- self.restarts = 0
21
-
22
- async def restart(self):
23
- self.restarts += 1
24
- self.is_running = True
25
-
26
- async def get_tunnel(self, tunnel_id):
27
- status = self.statuses.pop(0) if self.statuses else "connected"
28
- if isinstance(status, Exception):
29
- raise status
30
- return None if status is None else SimpleNamespace(status=status)
31
-
32
-
33
- async def watch(client, checks, monkeypatch):
34
- """Run the watchdog for about `checks` checks; how many restarts it made."""
35
- monkeypatch.setattr(prime, "CHECK_SECONDS", 0.01)
36
- task = asyncio.create_task(prime._watch(client, "https://t"))
37
- await asyncio.sleep(0.0125 * checks)
38
- task.cancel()
39
- await asyncio.wait({task})
40
- return client.restarts
41
-
42
-
43
- async def test_connected_is_left_alone(monkeypatch):
44
- assert await watch(FakeClient(["connected"] * 10), 8, monkeypatch) == 0
45
-
46
-
47
- async def test_one_disconnected_check_is_not_enough(monkeypatch):
48
- client = FakeClient(["disconnected", "connected"] * 5)
49
- assert await watch(client, 8, monkeypatch) == 0
50
-
51
-
52
- async def test_disconnected_twice_restarts_once(monkeypatch):
53
- client = FakeClient(["disconnected", "disconnected"])
54
- assert await watch(client, 8, monkeypatch) == 1
55
-
56
-
57
- async def test_exited_frpc_restarts_without_asking(monkeypatch):
58
- client = FakeClient([RuntimeError("api down")] * 10, running=False)
59
- assert await watch(client, 4, monkeypatch) == 1
60
-
61
-
62
- async def test_unreachable_service_is_no_verdict(monkeypatch):
63
- client = FakeClient([RuntimeError("api down")] * 10)
64
- assert await watch(client, 8, monkeypatch) == 0
65
-
66
-
67
- async def test_gone_registration_stops_watching(monkeypatch):
68
- client = FakeClient([None])
69
- monkeypatch.setattr(prime, "CHECK_SECONDS", 0.01)
70
- await asyncio.wait_for(prime._watch(client, "https://t"), 1)
71
- assert client.restarts == 0