verifiers 0.4.1.dev35__tar.gz → 0.4.1.dev37__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 (271) hide show
  1. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/PKG-INFO +1 -1
  2. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/grid.py +32 -1
  3. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_multi_turn.py +5 -2
  4. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_multi_turn_tool.py +5 -1
  5. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_graph.py +66 -23
  6. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/dialects/anthropic.py +1 -0
  7. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/dialects/base.py +10 -1
  8. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/dialects/chat.py +1 -0
  9. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/dialects/responses.py +1 -0
  10. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/graph.py +63 -30
  11. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harness.py +4 -3
  12. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/claude_code/harness.py +2 -2
  13. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/hermes_agent/harness.py +2 -2
  14. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/kimi_code/harness.py +9 -4
  15. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/opencode/harness.py +11 -4
  16. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/pi/harness.py +9 -8
  17. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/prime_agent/harness.py +62 -62
  18. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/server.py +3 -3
  19. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/session.py +7 -2
  20. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/trace.py +2 -2
  21. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/types.py +4 -0
  22. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/.gitignore +0 -0
  23. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/LICENSE +0 -0
  24. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/README.md +0 -0
  25. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/pyproject.toml +0 -0
  26. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/conftest.py +0 -0
  27. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/agent_user_harness_v1.py +0 -0
  28. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/agent_user_v1.py +0 -0
  29. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/counter_tool_v1.py +0 -0
  30. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/duet_v1.py +0 -0
  31. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_acp_resume_v1.py +0 -0
  32. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_agentic_v1.py +0 -0
  33. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_tool_compose/docker-compose.yaml +0 -0
  34. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_tool_v1.py +0 -0
  35. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_user_sim_v1.py +0 -0
  36. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/echo_v1.py +0 -0
  37. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/network_policy_v1.py +0 -0
  38. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/pyproject.toml +0 -0
  39. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/skill_codeword_v1.py +0 -0
  40. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/skills/project-codeword/SKILL.md +0 -0
  41. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/fixtures/tool_response_image_v1.py +0 -0
  42. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_agent_user.py +0 -0
  43. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_agentic_judge.py +0 -0
  44. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_compose_scoring.py +0 -0
  45. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_examples.py +0 -0
  46. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_limits.py +0 -0
  47. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_multi_agent.py +0 -0
  48. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_multimodal_tool.py +0 -0
  49. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_network_policy.py +0 -0
  50. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_resume_tool.py +0 -0
  51. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_rubric_judge.py +0 -0
  52. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_sampling.py +0 -0
  53. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_shared_tool.py +0 -0
  54. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_single_turn.py +0 -0
  55. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_skills.py +0 -0
  56. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_stateful_tool.py +0 -0
  57. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_user_echo.py +0 -0
  58. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/integration/test_user_sim.py +0 -0
  59. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/cli/test_replay.py +0 -0
  60. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/conftest.py +0 -0
  61. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/harnesses/test_core.py +0 -0
  62. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/harnesses/test_rlm.py +0 -0
  63. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/interception/test_tunnel.py +0 -0
  64. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/judges/conftest.py +0 -0
  65. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/judges/test_judge.py +0 -0
  66. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/judges/test_reference.py +0 -0
  67. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/judges/test_rubric.py +0 -0
  68. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/runtimes/test_e2b.py +0 -0
  69. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/serve/test_client.py +0 -0
  70. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/serve/test_delta.py +0 -0
  71. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/serve/test_pool.py +0 -0
  72. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_agent.py +0 -0
  73. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_dialects.py +0 -0
  74. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_semantic.py +0 -0
  75. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_task.py +0 -0
  76. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_taskset.py +0 -0
  77. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/test_trace.py +0 -0
  78. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/utils/test_compile.py +0 -0
  79. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/utils/test_loaders.py +0 -0
  80. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/utils/test_platform.py +0 -0
  81. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/tests/unit/utils/test_score.py +0 -0
  82. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/__init__.py +0 -0
  83. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/__init__.py +0 -0
  84. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/acp/__init__.py +0 -0
  85. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/acp/runner.py +0 -0
  86. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/agent.py +0 -0
  87. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/__init__.py +0 -0
  88. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/dashboard/__init__.py +0 -0
  89. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/dashboard/base.py +0 -0
  90. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/dashboard/eval.py +0 -0
  91. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/dashboard/replay.py +0 -0
  92. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/dashboard/validate.py +0 -0
  93. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/debug.py +0 -0
  94. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/eval/__init__.py +0 -0
  95. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/eval/hint.py +0 -0
  96. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/eval/main.py +0 -0
  97. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/eval/resume.py +0 -0
  98. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/eval/runner.py +0 -0
  99. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/gepa.py +0 -0
  100. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/output.py +0 -0
  101. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/replay.py +0 -0
  102. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/resolve.py +0 -0
  103. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/resume.py +0 -0
  104. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/cli/validate.py +0 -0
  105. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/clients/__init__.py +0 -0
  106. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/clients/base.py +0 -0
  107. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/clients/client.py +0 -0
  108. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/clients/eval.py +0 -0
  109. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/clients/train.py +0 -0
  110. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/__init__.py +0 -0
  111. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/agent.py +0 -0
  112. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/__init__.py +0 -0
  113. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/debug.py +0 -0
  114. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/env.py +0 -0
  115. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/eval.py +0 -0
  116. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/replay.py +0 -0
  117. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/cli/validate.py +0 -0
  118. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/client.py +0 -0
  119. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/env.py +0 -0
  120. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/harness.py +0 -0
  121. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/judge.py +0 -0
  122. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/retries.py +0 -0
  123. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/runtime.py +0 -0
  124. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/scoring.py +0 -0
  125. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/select.py +0 -0
  126. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/serve.py +0 -0
  127. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/task.py +0 -0
  128. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/configs/taskset.py +0 -0
  129. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/dialects/__init__.py +0 -0
  130. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/env.py +0 -0
  131. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/__init__.py +0 -0
  132. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/agentic_judge/__init__.py +0 -0
  133. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/agentic_judge/env.py +0 -0
  134. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/best_of_n/__init__.py +0 -0
  135. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/best_of_n/env.py +0 -0
  136. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/single_agent/__init__.py +0 -0
  137. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/single_agent/env.py +0 -0
  138. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/user_sim/__init__.py +0 -0
  139. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/envs/user_sim/env.py +0 -0
  140. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/episode.py +0 -0
  141. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/errors.py +0 -0
  142. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/__init__.py +0 -0
  143. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/adapter.py +0 -0
  144. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/config.py +0 -0
  145. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/dataset.py +0 -0
  146. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/reflection.py +0 -0
  147. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/gepa/runner.py +0 -0
  148. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/grading.py +0 -0
  149. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/__init__.py +0 -0
  150. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/bash/__init__.py +0 -0
  151. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/bash/harness.py +0 -0
  152. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/browser_use/__init__.py +0 -0
  153. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/browser_use/harness.py +0 -0
  154. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/browser_use/program.py +0 -0
  155. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/claude_code/__init__.py +0 -0
  156. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/codex/__init__.py +0 -0
  157. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/codex/gate.mjs +0 -0
  158. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/codex/harness.py +0 -0
  159. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/deepseek/__init__.py +0 -0
  160. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/deepseek/gate.mjs +0 -0
  161. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/deepseek/harness.py +0 -0
  162. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/deepseek/usage.mjs +0 -0
  163. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/hermes_agent/__init__.py +0 -0
  164. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/hermes_agent/program.py +0 -0
  165. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/kimi_code/__init__.py +0 -0
  166. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/mini_swe_agent/__init__.py +0 -0
  167. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/mini_swe_agent/harness.py +0 -0
  168. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/mini_swe_agent/program.py +0 -0
  169. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/node.py +0 -0
  170. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/null/__init__.py +0 -0
  171. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/null/harness.py +0 -0
  172. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/openclaw/__init__.py +0 -0
  173. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/openclaw/harness.py +0 -0
  174. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/opencode/__init__.py +0 -0
  175. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/opencode/mcp-ready.js +0 -0
  176. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/pi/__init__.py +0 -0
  177. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/pi/gate.mjs +0 -0
  178. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/prime_agent/__init__.py +0 -0
  179. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/rlm/__init__.py +0 -0
  180. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/rlm/harness.py +0 -0
  181. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/terminus_2/__init__.py +0 -0
  182. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/terminus_2/harness.py +0 -0
  183. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/terminus_2/program.py +0 -0
  184. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/__init__.py +0 -0
  185. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/compaction.py +0 -0
  186. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/core.py +0 -0
  187. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/install.py +0 -0
  188. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/launch.py +0 -0
  189. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/mcp.py +0 -0
  190. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/harnesses/utils/replay.py +0 -0
  191. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/__init__.py +0 -0
  192. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/base.py +0 -0
  193. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/pool.py +0 -0
  194. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/tunnel/__init__.py +0 -0
  195. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/tunnel/base.py +0 -0
  196. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/tunnel/custom.py +0 -0
  197. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/interception/tunnel/prime.py +0 -0
  198. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judge.py +0 -0
  199. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/__init__.py +0 -0
  200. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/decision.py +0 -0
  201. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/reference.py +0 -0
  202. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/reference.txt +0 -0
  203. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/rubric.py +0 -0
  204. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/judges/rubric.txt +0 -0
  205. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/mcp/__init__.py +0 -0
  206. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/mcp/launch.py +0 -0
  207. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/mcp/server.py +0 -0
  208. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/mcp/toolset.py +0 -0
  209. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/rollout.py +0 -0
  210. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/__init__.py +0 -0
  211. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/apptainer.py +0 -0
  212. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/base.py +0 -0
  213. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/compose.py +0 -0
  214. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/container.py +0 -0
  215. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/deployment.py +0 -0
  216. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/docker/__init__.py +0 -0
  217. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/docker/egress.py +0 -0
  218. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/e2b.py +0 -0
  219. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/limiters.py +0 -0
  220. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/modal.py +0 -0
  221. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/prime.py +0 -0
  222. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/runtime.py +0 -0
  223. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/strategies.py +0 -0
  224. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/runtimes/subprocess.py +0 -0
  225. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/semantic.py +0 -0
  226. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/__init__.py +0 -0
  227. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/client.py +0 -0
  228. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/delta.py +0 -0
  229. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/encoding.py +0 -0
  230. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/pool.py +0 -0
  231. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/server.py +0 -0
  232. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/serve/types.py +0 -0
  233. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/state.py +0 -0
  234. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/task.py +0 -0
  235. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/taskset.py +0 -0
  236. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/__init__.py +0 -0
  237. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/harbor/__init__.py +0 -0
  238. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/harbor/taskset.py +0 -0
  239. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/harbor/toolset.py +0 -0
  240. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/nemo_gym/__init__.py +0 -0
  241. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/nemo_gym/response.py +0 -0
  242. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/nemo_gym/server.py +0 -0
  243. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/nemo_gym/taskset.py +0 -0
  244. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/nemo_gym/toolset.py +0 -0
  245. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/openenv/__init__.py +0 -0
  246. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/openenv/taskset.py +0 -0
  247. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/textarena/__init__.py +0 -0
  248. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/tasksets/textarena/taskset.py +0 -0
  249. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/__init__.py +0 -0
  250. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/aio.py +0 -0
  251. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/artifacts.py +0 -0
  252. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/compile.py +0 -0
  253. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/decorators.py +0 -0
  254. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/env.py +0 -0
  255. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/eval.py +0 -0
  256. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/format.py +0 -0
  257. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/generic.py +0 -0
  258. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/git.py +0 -0
  259. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/image.py +0 -0
  260. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/interrupt.py +0 -0
  261. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/loaders.py +0 -0
  262. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/logging.py +0 -0
  263. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/memory.py +0 -0
  264. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/paths.py +0 -0
  265. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/platform.py +0 -0
  266. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/prime.py +0 -0
  267. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/retries.py +0 -0
  268. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/scope.py +0 -0
  269. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/score.py +0 -0
  270. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/verifiers/v1/utils/trace_store.py +0 -0
  271. {verifiers-0.4.1.dev35 → verifiers-0.4.1.dev37}/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.dev35
3
+ Version: 0.4.1.dev37
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
@@ -32,6 +32,7 @@ prime cannot pull) stay outside the grid.
32
32
 
33
33
  import shutil
34
34
  from collections.abc import Sequence
35
+ from typing import get_args
35
36
 
36
37
  import pytest
37
38
  from pydantic import TypeAdapter
@@ -40,7 +41,7 @@ import verifiers.v1 as vf
40
41
  from verifiers.v1.configs.runtime import NetworkPolicyConfig
41
42
  from verifiers.v1.harness import Harness
42
43
  from verifiers.v1.runtimes import RuntimeConfig, _backend_cls
43
- from verifiers.v1.utils.loaders import harness_class
44
+ from verifiers.v1.utils.loaders import harness_class, harness_config_type
44
45
 
45
46
  HARNESSES: list[str | dict] = [
46
47
  "null",
@@ -191,6 +192,36 @@ def grid(
191
192
  return cells
192
193
 
193
194
 
195
+ def transports(harness: str) -> tuple[str, ...]:
196
+ """The wire formats the harness config can select (`transport`) besides its
197
+ default. Empty when the program speaks one format or picks its own."""
198
+ field = harness_config_type(harness).model_fields.get("transport")
199
+ if field is None:
200
+ return ()
201
+ return tuple(t for t in get_args(field.annotation) if t != field.default)
202
+
203
+
204
+ def transport_grid(
205
+ runtimes: Sequence[str] = ("prime",), *, needs: tuple[str, ...] = ()
206
+ ) -> list:
207
+ """`grid` cells for every non-default `transport` each harness config can select."""
208
+ cells = []
209
+ for harness in HARNESSES:
210
+ name = harness_id(harness)
211
+ for transport in transports(name):
212
+ for cell in grid(
213
+ [{"id": name, "transport": transport}], runtimes, needs=needs
214
+ ):
215
+ cells.append(
216
+ pytest.param(
217
+ *cell.values,
218
+ marks=cell.marks,
219
+ id=cell.id.replace(f"{name}-in-", f"{name}-{transport}-in-"),
220
+ )
221
+ )
222
+ return cells
223
+
224
+
194
225
  def skip_harness(cells: list, harness: str, reason: str) -> list:
195
226
  """Skip one harness's cells for a limit no capability flag declares. Each use names
196
227
  why, so a reader sees the gap and when it can go."""
@@ -1,11 +1,14 @@
1
1
  """One task, many turns: the model completes a shell task (echo-agentic-v1: write a phrase
2
- to a file, checked in the runtime) across the harness x runtime grid."""
2
+ to a file, checked in the runtime) across the harness x runtime grid, and on prime over
3
+ every other `transport` a harness config can select. A turn the harness re-sends
4
+ differently, beyond what its `replay_view` declares, forks the trace."""
3
5
 
4
6
  import pytest
5
- from grid import grid, mark
7
+ from grid import grid, mark, transport_grid
6
8
 
7
9
  MULTI_TURN = [
8
10
  *grid(needs=("shell",)),
11
+ *transport_grid(needs=("shell",)),
9
12
  pytest.param(
10
13
  "bash",
11
14
  {"type": "modal", "allow": []},
@@ -28,7 +28,11 @@ async def test_tool(run, harness, harness_runtime):
28
28
  # Reward 1.0 is the proof the tool ran. How a program surfaces an MCP tool to the
29
29
  # model is its own business (rlm calls it from code; chat loops advertise it), so
30
30
  # the advertised schema is checked on the chat loop in `test_tool_placement`.
31
- assert trace.reward == 1.0
31
+ assert trace.reward == 1.0, "\n".join(
32
+ message.model_dump_json(exclude_none=True)
33
+ for message in trace.messages
34
+ if message.role in {"assistant", "tool"}
35
+ )
32
36
 
33
37
 
34
38
  @pytest.mark.parametrize(
@@ -270,6 +270,30 @@ def test_reasoning_content_participates_in_graph_prefix_matching():
270
270
  assert len(tool_call_nodes) == 2
271
271
 
272
272
 
273
+ def _replayed_trace(replay_view, sampled, replayed, dialect=None):
274
+ """One tool turn sampled as `sampled` and re-sent as `replayed` on the next turn."""
275
+ trace = vf.Trace(
276
+ agent=vf.AgentInfo(config=vf.AgentConfig()),
277
+ task=vf.TraceTask(type="Task", data=vf.TaskData(idx=0, prompt="go")),
278
+ )
279
+ trace._replay_view = replay_view
280
+ user = vf.UserMessage(content="go")
281
+ call = vf.ToolCall(id="call_0", name="lookup", arguments="{}")
282
+ graph.prepare_turn(trace, [user], dialect=dialect).commit(
283
+ _response(vf.AssistantMessage(tool_calls=[call], **sampled))
284
+ )
285
+ graph.prepare_turn(
286
+ trace,
287
+ [
288
+ user,
289
+ vf.AssistantMessage(tool_calls=[call], **replayed),
290
+ vf.ToolMessage(content="result", tool_call_id="call_0"),
291
+ ],
292
+ dialect=dialect,
293
+ ).commit(_response(vf.AssistantMessage(content="done")))
294
+ return trace
295
+
296
+
273
297
  @pytest.mark.parametrize(
274
298
  "view,sampled,replayed",
275
299
  [
@@ -284,29 +308,48 @@ def test_reasoning_content_participates_in_graph_prefix_matching():
284
308
  ],
285
309
  )
286
310
  def test_replay_view_matches_cosmetically_rewritten_turns(view, sampled, replayed):
287
- def run(replay_view):
288
- trace = vf.Trace(
289
- agent=vf.AgentInfo(config=vf.AgentConfig()),
290
- task=vf.TraceTask(type="Task", data=vf.TaskData(idx=0, prompt="go")),
291
- )
292
- trace._replay_view = replay_view
293
- user = vf.UserMessage(content="go")
294
- call = vf.ToolCall(id="call_0", name="lookup", arguments="{}")
295
- graph.prepare_turn(trace, [user]).commit(
296
- _response(vf.AssistantMessage(tool_calls=[call], **sampled))
297
- )
298
- graph.prepare_turn(
299
- trace,
300
- [
301
- user,
302
- vf.AssistantMessage(tool_calls=[call], **replayed),
303
- vf.ToolMessage(content="result", tool_call_id="call_0"),
304
- ],
305
- ).commit(_response(vf.AssistantMessage(content="done")))
306
- return trace
307
-
308
- assert run(None).num_branches == 2
309
- assert run(view).num_branches == 1
311
+ assert _replayed_trace(None, sampled, replayed).num_branches == 2
312
+ trace = _replayed_trace(lambda message, _: view(message), sampled, replayed)
313
+ assert trace.num_branches == 1
314
+
315
+
316
+ @pytest.mark.parametrize(
317
+ "dialect,branches", [("chat_completions", 1), ("responses", 2)]
318
+ )
319
+ def test_replay_view_receives_the_request_dialect(dialect, branches):
320
+ def view(message, dialect):
321
+ return drop_blank_text(message) if dialect == "chat_completions" else message
322
+
323
+ trace = _replayed_trace(view, {"content": "\n\n"}, {"content": None}, dialect)
324
+ assert trace.num_branches == branches
325
+
326
+
327
+ def test_overlapping_requests_keep_their_own_dialect():
328
+ trace = vf.Trace(
329
+ agent=vf.AgentInfo(config=vf.AgentConfig()),
330
+ task=vf.TraceTask(type="Task", data=vf.TaskData(idx=0, prompt="go")),
331
+ )
332
+ trace._replay_view = lambda message, dialect: (
333
+ drop_blank_text(message) if dialect == "chat_completions" else message
334
+ )
335
+ user = vf.UserMessage(content="go")
336
+ call = vf.ToolCall(id="call_0", name="lookup", arguments="{}")
337
+ graph.prepare_turn(trace, [user], dialect="chat_completions").commit(
338
+ _response(vf.AssistantMessage(content="\n\n", tool_calls=[call]))
339
+ )
340
+ replay = [
341
+ user,
342
+ vf.AssistantMessage(tool_calls=[call]),
343
+ vf.ToolMessage(content="result", tool_call_id="call_0"),
344
+ ]
345
+ chat = graph.prepare_turn(trace, replay, dialect="chat_completions")
346
+ responses = graph.prepare_turn(trace, replay, dialect="responses")
347
+ responses.commit(_response(vf.AssistantMessage(content="other")))
348
+ done = chat.commit(_response(vf.AssistantMessage(content="done")))
349
+
350
+ assert chat.prefix_node_ids == [0, 1]
351
+ assert responses.prefix_node_ids == [0]
352
+ assert graph.path(trace, done)[1] == trace.nodes[1].message
310
353
 
311
354
 
312
355
  @pytest.mark.parametrize("same_tools", [False, True])
@@ -437,6 +437,7 @@ class ModdedAnthropicMessage(AnthropicMessage):
437
437
 
438
438
 
439
439
  class AnthropicDialect(Dialect[AnthropicMessage]):
440
+ name = "anthropic_messages"
440
441
  sampling_fields = frozenset(
441
442
  {
442
443
  "temperature",
@@ -27,7 +27,13 @@ from verifiers.v1.configs.runtime import (
27
27
  intersect_network_hosts,
28
28
  parse_network_rule,
29
29
  )
30
- from verifiers.v1.types import Request, Response, Sampling, SamplingConfig
30
+ from verifiers.v1.types import (
31
+ DialectName,
32
+ Request,
33
+ Response,
34
+ Sampling,
35
+ SamplingConfig,
36
+ )
31
37
 
32
38
  RespT = TypeVar("RespT", bound=BaseModel)
33
39
  RawRequest = dict[str, Any]
@@ -263,6 +269,9 @@ class Dialect(ABC, Generic[RespT]):
263
269
  rewriting them. Implement a `Dialect` + register it in `dialects.DIALECTS` and a harness
264
270
  speaking that format works end-to-end."""
265
271
 
272
+ name: ClassVar[DialectName]
273
+ """The wire format's name, passed to `Harness.replay_view`."""
274
+
266
275
  sampling_fields: ClassVar[frozenset[str]] = frozenset()
267
276
  """Request keys that are call settings — what shapes generation given the same
268
277
  conversation: decoding knobs, budgets/stops, reasoning effort, output contract.
@@ -397,6 +397,7 @@ class ChatStreamParser(StreamParser):
397
397
 
398
398
 
399
399
  class ChatDialect(Dialect[ChatCompletion]):
400
+ name = "chat_completions"
400
401
  sampling_fields = frozenset(
401
402
  {
402
403
  "temperature",
@@ -354,6 +354,7 @@ class ResponsesStreamParser(StreamParser):
354
354
 
355
355
 
356
356
  class ResponsesDialect(Dialect[OpenAIResponse]):
357
+ name = "responses"
357
358
  sampling_fields = frozenset(
358
359
  {
359
360
  "temperature",
@@ -42,6 +42,7 @@ from renderers.base import RenderedTokens
42
42
  from verifiers.v1.semantic import ParentLink
43
43
  from verifiers.v1.types import (
44
44
  AssistantMessage,
45
+ DialectName,
45
46
  Message,
46
47
  Response,
47
48
  SamplingMask,
@@ -321,11 +322,12 @@ def _tools_hash(tools: list[Tool] | None) -> str:
321
322
  return hashlib.blake2b(data, digest_size=16).hexdigest()
322
323
 
323
324
 
324
- def _message_key(trace: Trace, message: Message) -> str:
325
- """`message_hash` of the message as the trace's harness replays it, so a turn the
326
- harness re-sends with cosmetic rewrites still matches the node it came from."""
325
+ def _message_key(trace: Trace, message: Message, dialect: DialectName | None) -> str:
326
+ """`message_hash` of the message as the trace's harness replays it over `dialect`,
327
+ so a turn the harness re-sends with cosmetic rewrites still matches the node it
328
+ came from."""
327
329
  view = trace._replay_view
328
- return message_hash(view(message) if view is not None else message)
330
+ return message_hash(view(message, dialect) if view is not None else message)
329
331
 
330
332
 
331
333
  def _node_key(
@@ -333,25 +335,43 @@ def _node_key(
333
335
  parent: int | None,
334
336
  message: Message,
335
337
  tools: list[Tool] | None = None,
338
+ *,
339
+ dialect: DialectName | None,
336
340
  ) -> tuple[int | None, str | None, str]:
337
341
  return (
338
342
  parent,
339
343
  _tools_hash(tools) if parent is None else None,
340
- _message_key(trace, message),
344
+ _message_key(trace, message, dialect),
341
345
  )
342
346
 
343
347
 
344
- def _head_index(trace: Trace) -> dict[tuple[int | None, str | None, str], int]:
345
- """Physical node key -> id, rebuilt lazily after deserialization."""
346
- if not trace._head_index and trace.nodes:
347
- trace._head_index = {
348
- _node_key(trace, node.parent, node.message, node.tools): nid
348
+ def _head_index(
349
+ trace: Trace, dialect: DialectName | None
350
+ ) -> dict[tuple[int | None, str | None, str], int]:
351
+ """Physical node key -> id under `dialect`'s replay view, built lazily per dialect
352
+ (and after deserialization)."""
353
+ index = trace._head_index.get(dialect)
354
+ if index is None:
355
+ index = trace._head_index[dialect] = {
356
+ _node_key(
357
+ trace, node.parent, node.message, node.tools, dialect=dialect
358
+ ): nid
349
359
  for nid, node in enumerate(trace.nodes)
350
360
  }
351
- return trace._head_index
361
+ return index
352
362
 
353
363
 
354
- def message_prefix_len(trace: Trace, prompt: list[Message]) -> int:
364
+ def _index_node(trace: Trace, node_id: int) -> None:
365
+ """Point every built dialect index at a new node."""
366
+ node = trace.nodes[node_id]
367
+ for dialect, index in trace._head_index.items():
368
+ key = _node_key(trace, node.parent, node.message, node.tools, dialect=dialect)
369
+ index[key] = node_id
370
+
371
+
372
+ def message_prefix_len(
373
+ trace: Trace, prompt: list[Message], dialect: DialectName | None = None
374
+ ) -> int:
355
375
  """Length of the longest message-only graph prefix matching `prompt`."""
356
376
  children: dict[int | None, list[int]] = {}
357
377
  for node_id, node in enumerate(trace.nodes):
@@ -360,12 +380,12 @@ def message_prefix_len(trace: Trace, prompt: list[Message]) -> int:
360
380
  parents: list[int | None] = [None]
361
381
  matched = 0
362
382
  for message in prompt:
363
- key = _message_key(trace, message)
383
+ key = _message_key(trace, message, dialect)
364
384
  parents = [
365
385
  node_id
366
386
  for parent in parents
367
387
  for node_id in children.get(parent, [])
368
- if _message_key(trace, trace.nodes[node_id].message) == key
388
+ if _message_key(trace, trace.nodes[node_id].message, dialect) == key
369
389
  ]
370
390
  if not parents:
371
391
  break
@@ -380,6 +400,8 @@ def _matching_node(
380
400
  token_ids: list[int] | None = None,
381
401
  renderer_token_ids: list[int] | None = None,
382
402
  tools: list[Tool] | None = None,
403
+ *,
404
+ dialect: DialectName | None,
383
405
  ) -> int | None:
384
406
  """Find an existing child, optionally requiring its exact token spans.
385
407
 
@@ -387,8 +409,8 @@ def _matching_node(
387
409
  prefix breaks can leave older physical variants under the same key, so a token mismatch falls
388
410
  back to a reverse scan rather than materializing a duplicate of an already-existing variant.
389
411
  """
390
- key = _node_key(trace, parent, message, tools)
391
- indexed = _head_index(trace).get(key)
412
+ key = _node_key(trace, parent, message, tools, dialect=dialect)
413
+ indexed = _head_index(trace, dialect).get(key)
392
414
  if (
393
415
  indexed is not None
394
416
  and (token_ids is None or trace.nodes[indexed].token_ids == token_ids)
@@ -407,7 +429,8 @@ def _matching_node(
407
429
  if (
408
430
  (token_ids is None or node.token_ids == token_ids)
409
431
  and (renderer_token_ids is None or node.logical_ids == renderer_token_ids)
410
- and _node_key(trace, node.parent, node.message, node.tools) == key
432
+ and _node_key(trace, node.parent, node.message, node.tools, dialect=dialect)
433
+ == key
411
434
  ):
412
435
  return node_id
413
436
  return None
@@ -424,6 +447,8 @@ def _matching_prefix_node(
424
447
  renderer_start: int,
425
448
  renderer_stop: int,
426
449
  tools: list[Tool] | None = None,
450
+ *,
451
+ dialect: DialectName | None,
427
452
  ) -> int | None:
428
453
  """Find the longest content-equivalent child matching inside `[start, stop]`.
429
454
 
@@ -432,8 +457,8 @@ def _matching_prefix_node(
432
457
  otherwise-missing message boundary. The next attributed message's start bounds the match:
433
458
  a sampled variant must never consume tokens that the renderer assigned to that message.
434
459
  """
435
- key = _node_key(trace, parent, message, tools)
436
- indexed = _head_index(trace).get(key)
460
+ key = _node_key(trace, parent, message, tools, dialect=dialect)
461
+ indexed = _head_index(trace, dialect).get(key)
437
462
  candidates: list[int] = []
438
463
  if indexed is not None:
439
464
  candidates.append(indexed)
@@ -446,6 +471,7 @@ def _matching_prefix_node(
446
471
  trace.nodes[node_id].parent,
447
472
  trace.nodes[node_id].message,
448
473
  trace.nodes[node_id].tools,
474
+ dialect=dialect,
449
475
  )
450
476
  == key
451
477
  )
@@ -480,6 +506,8 @@ class PendingTurn:
480
506
  tools: list[Tool]
481
507
  prefix_node_ids: list[int]
482
508
  path_len: int
509
+ dialect: DialectName | None = None
510
+ """The wire format of the request, whose replay view matches its prompt."""
483
511
 
484
512
  @property
485
513
  def tail_start(self) -> int:
@@ -558,13 +586,14 @@ class PendingTurn:
558
586
  def commit_prompt(self) -> None:
559
587
  """Record an input that terminated before model inference."""
560
588
  parent = self.prefix_node_ids[-1] if self.prefix_node_ids else None
561
- index = _head_index(self.trace)
589
+ _head_index(self.trace, self.dialect)
562
590
  for message in self.tail:
563
- existing = _matching_node(self.trace, parent, message, tools=self.tools)
591
+ existing = _matching_node(
592
+ self.trace, parent, message, tools=self.tools, dialect=self.dialect
593
+ )
564
594
  if existing is not None:
565
595
  parent = existing
566
596
  continue
567
- previous = parent
568
597
  self.trace.nodes.append(
569
598
  MessageNode(
570
599
  parent=parent,
@@ -573,7 +602,7 @@ class PendingTurn:
573
602
  )
574
603
  )
575
604
  parent = len(self.trace.nodes) - 1
576
- index[_node_key(self.trace, previous, message, self.tools)] = parent
605
+ _index_node(self.trace, parent)
577
606
  if self.tools:
578
607
  self.trace.tools = list(
579
608
  {
@@ -588,9 +617,11 @@ def prepare_turn(
588
617
  trace: Trace,
589
618
  prompt: list[Message],
590
619
  tools: list[Tool] | None = None,
620
+ dialect: DialectName | None = None,
591
621
  ) -> PendingTurn:
592
- """Resolve a physical message-and-tools prefix without mutating the trace."""
593
- idx = _head_index(trace)
622
+ """Resolve a physical message-and-tools prefix without mutating the trace. `dialect`
623
+ is the request's wire format, whose replay view matches the prompt to stored nodes."""
624
+ idx = _head_index(trace, dialect)
594
625
  tools = list(tools or [])
595
626
  tools_hash = _tools_hash(tools)
596
627
  parent: int | None = None
@@ -614,7 +645,7 @@ def prepare_turn(
614
645
  if len(children) == 1 and trace.nodes[children[0]].message == msg:
615
646
  existing = children[0]
616
647
  if existing is None:
617
- message_key = _message_key(trace, msg)
648
+ message_key = _message_key(trace, msg, dialect)
618
649
  existing = idx.get(
619
650
  (parent, tools_hash if parent is None else None, message_key)
620
651
  )
@@ -629,6 +660,7 @@ def prepare_turn(
629
660
  tools=tools,
630
661
  prefix_node_ids=prefix_node_ids,
631
662
  path_len=path_len,
663
+ dialect=dialect,
632
664
  )
633
665
 
634
666
 
@@ -801,7 +833,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
801
833
  )
802
834
  renderer_spans = tokens.message_spans if tokens else None
803
835
  renderer_is_content = tokens.is_content if tokens else None
804
- idx = _head_index(trace)
836
+ _head_index(trace, turn.dialect)
805
837
 
806
838
  prefix = turn.prefix_node_ids
807
839
  path_len = turn.path_len
@@ -886,6 +918,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
886
918
  renderer_path_len,
887
919
  next_renderer_start,
888
920
  tools=turn.tools,
921
+ dialect=turn.dialect,
889
922
  )
890
923
  if existing is not None:
891
924
  end += len(trace.nodes[existing].token_ids)
@@ -900,6 +933,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
900
933
  node_tokens if tokens is not None else None,
901
934
  renderer_node_tokens if tokens is not None else None,
902
935
  tools=turn.tools,
936
+ dialect=turn.dialect,
903
937
  )
904
938
  if existing is None:
905
939
  break
@@ -914,7 +948,6 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
914
948
  # Track new nodes separately so routed-expert attribution needs only node ids, not this path.
915
949
  new_node_ids: list[int] = []
916
950
  for i, msg in enumerate(prompt[num_reused:], start=num_reused):
917
- key = _node_key(trace, parent, msg, turn.tools)
918
951
  start = path_len if cursor is None else cursor
919
952
  span = spans[i] if spans and i < len(spans) else None
920
953
  end = span[1] if span else start
@@ -938,7 +971,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
938
971
  )
939
972
  )
940
973
  parent = len(trace.nodes) - 1
941
- idx[key] = parent
974
+ _index_node(trace, parent)
942
975
  new_node_ids.append(parent)
943
976
  cursor = end
944
977
  renderer_cursor = renderer_end
@@ -967,7 +1000,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
967
1000
  )
968
1001
  )
969
1002
  assistant_id = len(trace.nodes) - 1
970
- idx[_node_key(trace, parent, response.message, turn.tools)] = assistant_id
1003
+ _index_node(trace, assistant_id)
971
1004
  new_node_ids.append(assistant_id)
972
1005
 
973
1006
  # Attribute this turn's expert-routing array onto the nodes created this turn (new input
@@ -18,7 +18,7 @@ from verifiers.v1.errors import (
18
18
  )
19
19
  from verifiers.v1.runtimes import ProgramResult, Runtime
20
20
  from verifiers.v1.task import TaskData
21
- from verifiers.v1.types import Message, Messages
21
+ from verifiers.v1.types import DialectName, Message, Messages
22
22
  from verifiers.v1.utils.decorators import (
23
23
  discover_decorated,
24
24
  invoke_all,
@@ -67,8 +67,9 @@ class Harness(ABC, Generic[ConfigT]):
67
67
  def __init__(self, config: ConfigT) -> None:
68
68
  self.config = config
69
69
 
70
- def replay_view(self, message: Message) -> Message:
71
- """`message` as this harness re-sends it on later requests. Override only for
70
+ def replay_view(self, message: Message, dialect: DialectName | None) -> Message:
71
+ """`message` as this harness re-sends it on later requests over `dialect` (None
72
+ before the first intercepted request). Override only for
72
73
  deterministic cosmetic rewrites (e.g. dropped whitespace-only text), never for
73
74
  content changes, so a replayed turn matches the turn it came from in the trace
74
75
  graph instead of forking it."""
@@ -11,7 +11,7 @@ from verifiers.v1.harnesses.utils.replay import drop_blank_text
11
11
  from verifiers.v1.runtimes import Runtime
12
12
  from verifiers.v1.task import TaskData
13
13
  from verifiers.v1.trace import Trace
14
- from verifiers.v1.types import Message
14
+ from verifiers.v1.types import DialectName, Message
15
15
 
16
16
  CLAUDE_ACP_DIR = "/var/tmp/vf-claude-agent-acp-{version}-{acp_version}"
17
17
  PACKAGES_DIR = f"{CLAUDE_ACP_DIR}/packages"
@@ -44,7 +44,7 @@ class ClaudeCodeHarness(ACPHarness[ClaudeCodeHarnessConfig]):
44
44
 
45
45
  # Claude Code drops whitespace-only text blocks on replay. Closed source: observed
46
46
  # with 2.1.278, recheck on version bumps.
47
- def replay_view(self, message: Message) -> Message:
47
+ def replay_view(self, message: Message, dialect: DialectName | None) -> Message:
48
48
  return drop_blank_text(message)
49
49
 
50
50
  async def setup(self, runtime: Runtime) -> None:
@@ -12,7 +12,7 @@ from verifiers.v1.runtimes import Runtime
12
12
  from verifiers.v1.runtimes.base import _ENSURE_UV
13
13
  from verifiers.v1.task import TaskData
14
14
  from verifiers.v1.trace import Trace
15
- from verifiers.v1.types import Message
15
+ from verifiers.v1.types import DialectName, Message
16
16
 
17
17
  PROGRAM_SOURCE = (Path(__file__).resolve().parent / "program.py").read_text()
18
18
  HERMES_DIR = "/var/tmp/vf-hermes-agent-{version}"
@@ -43,7 +43,7 @@ class HermesAgentHarness(ACPHarness[HermesAgentHarnessConfig]):
43
43
  # replay. Recheck on version bumps:
44
44
  # https://github.com/NousResearch/hermes-agent/blob/v2026.9.14/agent/chat_completion_helpers.py#L1444
45
45
  # https://github.com/NousResearch/hermes-agent/blob/v2026.9.14/agent/message_sanitization.py#L545
46
- def replay_view(self, message: Message) -> Message:
46
+ def replay_view(self, message: Message, dialect: DialectName | None) -> Message:
47
47
  return strip_text(message)
48
48
 
49
49
  async def setup(self, runtime: Runtime) -> None:
@@ -2,7 +2,6 @@
2
2
 
3
3
  import logging
4
4
  import tomllib
5
- from typing import Literal
6
5
 
7
6
  import tomli_w
8
7
 
@@ -11,9 +10,11 @@ from verifiers.v1.clients import ModelContext
11
10
  from verifiers.v1.configs.harness import HarnessConfig, PinnedVersion
12
11
  from verifiers.v1.harnesses.node import NODE_BIN_DIR, ensure_node
13
12
  from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
13
+ from verifiers.v1.harnesses.utils.replay import drop_blank_text
14
14
  from verifiers.v1.runtimes import Runtime
15
15
  from verifiers.v1.task import TaskData
16
16
  from verifiers.v1.trace import Trace
17
+ from verifiers.v1.types import DialectName, Message
17
18
 
18
19
  logger = logging.getLogger(__name__)
19
20
 
@@ -39,9 +40,7 @@ fi
39
40
  class KimiCodeHarnessConfig(HarnessConfig):
40
41
  version: PinnedVersion = "2.0.2"
41
42
  """Kimi Code release to install, pinned for reproducibility."""
42
- transport: Literal["chat_completions", "responses", "anthropic_messages"] = (
43
- "chat_completions"
44
- )
43
+ transport: DialectName = "chat_completions"
45
44
  """Model API transport."""
46
45
 
47
46
 
@@ -51,6 +50,12 @@ class KimiCodeHarness(ACPHarness[KimiCodeHarnessConfig]):
51
50
  SUPPORTS_SKILLS = True
52
51
  SUPPORTS_TOOL_INTERCEPTION = True
53
52
 
53
+ # Kimi Code drops whitespace-only assistant text when it stores a step, so every
54
+ # transport replays it without. Recheck on version bumps:
55
+ # https://github.com/MoonshotAI/kimi-code/blob/@moonshot-ai/kimi-code@2.0.2/packages/agent-core-v2/src/agent/loop/loopService.ts#L1723
56
+ def replay_view(self, message: Message, dialect: DialectName | None) -> Message:
57
+ return drop_blank_text(message)
58
+
54
59
  async def setup(self, runtime: Runtime) -> None:
55
60
  await ensure_node(runtime)
56
61
  logger.info(
@@ -2,16 +2,17 @@
2
2
 
3
3
  import json
4
4
  from pathlib import Path
5
- from typing import Literal
6
5
 
7
6
  from verifiers.v1.acp import ACPConfig, ACPHarness
8
7
  from verifiers.v1.clients import ModelContext
9
8
  from verifiers.v1.configs.harness import HarnessConfig, PinnedVersion
10
9
  from verifiers.v1.harnesses.node import ensure_node
11
10
  from verifiers.v1.harnesses.utils.install import ensure_installed, remove_dir
11
+ from verifiers.v1.harnesses.utils.replay import drop_blank_text
12
12
  from verifiers.v1.runtimes import Runtime
13
13
  from verifiers.v1.task import TaskData
14
14
  from verifiers.v1.trace import Trace
15
+ from verifiers.v1.types import DialectName, Message
15
16
 
16
17
  OPENCODE_DIR = "/var/tmp/vf-opencode"
17
18
  STATE_ROOT = "/tmp/vf-opencode-runs"
@@ -29,9 +30,7 @@ npm install --prefix "$VF_OPENCODE_DIR" --no-audit --no-fund --omit=dev \
29
30
  class OpenCodeHarnessConfig(HarnessConfig):
30
31
  version: PinnedVersion = "2.0.26"
31
32
  """OpenCode 2 release to install, pinned for reproducibility."""
32
- transport: Literal["chat_completions", "responses", "anthropic_messages"] = (
33
- "chat_completions"
34
- )
33
+ transport: DialectName = "chat_completions"
35
34
  """Model API transport."""
36
35
  disabled_tools: list[str] | None = None
37
36
  """OpenCode permission actions to deny, such as shell, read, or edit."""
@@ -42,6 +41,14 @@ class OpenCodeHarness(ACPHarness[OpenCodeHarnessConfig]):
42
41
  SUPPORTS_MCP = True
43
42
  SUPPORTS_SKILLS = True
44
43
 
44
+ # OpenCode drops whitespace-only assistant text on replay over Anthropic messages.
45
+ # Recheck on version bumps:
46
+ # https://github.com/anomalyco/opencode/blob/v2.0.26/packages/ai/src/protocols/anthropic-messages.ts#L929
47
+ def replay_view(self, message: Message, dialect: DialectName | None) -> Message:
48
+ if dialect == "anthropic_messages":
49
+ return drop_blank_text(message)
50
+ return message
51
+
45
52
  async def setup(self, runtime: Runtime) -> None:
46
53
  await ensure_node(runtime)
47
54
  directory = f"{OPENCODE_DIR}/{self.config.version}"