verifiers 0.1.15.dev154__tar.gz → 0.1.15.dev156__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 (324) hide show
  1. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/PKG-INFO +1 -1
  2. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_client_multimodal_types.py +73 -1
  3. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_composable_env.py +27 -0
  4. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_multiturn_env.py +2 -2
  5. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_openai_responses_client.py +19 -0
  6. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_renderer_client.py +8 -0
  7. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_harbor_cli.py +49 -1
  8. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_mini_swe_agent.py +27 -0
  9. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/anthropic_messages_client.py +24 -2
  10. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/openai_chat_completions_client.py +27 -4
  11. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/openai_responses_client.py +6 -2
  12. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/renderer_client.py +6 -2
  13. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harnesses/__init__.py +2 -2
  14. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harnesses/mini_swe_agent.py +6 -14
  15. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harnesses/opencode.py +18 -20
  16. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/.gitignore +0 -0
  17. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/LICENSE +0 -0
  18. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/README.md +0 -0
  19. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/pyproject.toml +0 -0
  20. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/AGENTS.md +0 -0
  21. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/README.md +0 -0
  22. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/__init__.py +0 -0
  23. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/conftest.py +0 -0
  24. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_browser_env.py +0 -0
  25. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_build_script.py +0 -0
  26. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_cli_agent_env.py +0 -0
  27. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_client_auth_errors.py +0 -0
  28. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_client_config.py +0 -0
  29. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_context_token_metrics.py +0 -0
  30. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_decorator_ranks.py +0 -0
  31. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_endpoint_registry.py +0 -0
  32. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_env_group.py +0 -0
  33. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_env_server.py +0 -0
  34. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_environment.py +0 -0
  35. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_environment_extra.py +0 -0
  36. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_envs.py +0 -0
  37. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_error_chain.py +0 -0
  38. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_eval_cli.py +0 -0
  39. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_eval_display.py +0 -0
  40. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_eval_utils.py +0 -0
  41. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_gepa_cli.py +0 -0
  42. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_gepa_utils.py +0 -0
  43. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_gym_env.py +0 -0
  44. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_harbor_env_mcp.py +0 -0
  45. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_imports.py +0 -0
  46. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_init_script.py +0 -0
  47. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_install_utils.py +0 -0
  48. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_interception_utils.py +0 -0
  49. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_langchain_deep_agents_wikispeedia.py +0 -0
  50. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_lean_task.py +0 -0
  51. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_logging.py +0 -0
  52. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_math_rubric.py +0 -0
  53. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_maybe_think_parser.py +0 -0
  54. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_mcp_search_env.py +0 -0
  55. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_message_utils.py +0 -0
  56. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_message_utils_multimodal.py +0 -0
  57. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_nemorl_client.py +0 -0
  58. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_openai_chat_completions_token_client.py +0 -0
  59. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_opencode_harbor.py +0 -0
  60. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_opencode_rlm_env.py +0 -0
  61. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_openenv_client.py +0 -0
  62. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_parser.py +0 -0
  63. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_path_utils.py +0 -0
  64. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_per_turn_timing.py +0 -0
  65. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_pricing_utils.py +0 -0
  66. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_prime_plugin.py +0 -0
  67. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_renderer_e2e.py +0 -0
  68. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_rlm_composable_env.py +0 -0
  69. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_rlm_env.py +0 -0
  70. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_rubric.py +0 -0
  71. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_rubric_group.py +0 -0
  72. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_sandbox_env.py +0 -0
  73. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_sandbox_mixin.py +0 -0
  74. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_save_utils.py +0 -0
  75. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_setup_script.py +0 -0
  76. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_singleturn_env.py +0 -0
  77. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_stateful_tool_env.py +0 -0
  78. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_think_parser.py +0 -0
  79. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_tool_env.py +0 -0
  80. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_tool_utils.py +0 -0
  81. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_trajectory_processing.py +0 -0
  82. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_tui_info_formatting.py +0 -0
  83. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_types.py +0 -0
  84. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_bfcl.py +0 -0
  85. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_config_extension.py +0 -0
  86. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_empty_completions.py +0 -0
  87. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_endpoint_protocols.py +0 -0
  88. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_example_counts.py +0 -0
  89. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_group_reward_env.py +0 -0
  90. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_nemo_gym_harness.py +0 -0
  91. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_openenv_taskset.py +0 -0
  92. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_openreward_taskset.py +0 -0
  93. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_rlm_swe.py +0 -0
  94. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_runtime_lifecycle.py +0 -0
  95. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_scoring_functions.py +0 -0
  96. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_taskset_bindings.py +0 -0
  97. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_taskset_utils.py +0 -0
  98. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_v1_textarena_taskset.py +0 -0
  99. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_wiki_search_v1.py +0 -0
  100. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_wordle_env.py +0 -0
  101. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_wordle_v1_env.py +0 -0
  102. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/tests/test_xml_parser.py +0 -0
  103. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/AGENTS.md +0 -0
  104. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/__init__.py +0 -0
  105. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/__init__.py +0 -0
  106. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/__init__.py +0 -0
  107. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/build.py +0 -0
  108. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/eval.py +0 -0
  109. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/gepa.py +0 -0
  110. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/init.py +0 -0
  111. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/install.py +0 -0
  112. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/commands/setup.py +0 -0
  113. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/plugins/__init__.py +0 -0
  114. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/plugins/prime.py +0 -0
  115. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/cli/tui.py +0 -0
  116. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/__init__.py +0 -0
  117. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/client.py +0 -0
  118. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/nemorl_chat_completions_client.py +0 -0
  119. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/openai_chat_completions_token_client.py +0 -0
  120. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/clients/openai_completions_client.py +0 -0
  121. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/decorators.py +0 -0
  122. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/AGENTS.md +0 -0
  123. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/__init__.py +0 -0
  124. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/env_group.py +0 -0
  125. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/environment.py +0 -0
  126. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/README.md +0 -0
  127. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/__init__.py +0 -0
  128. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/cli_agent_env.py +0 -0
  129. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/README.md +0 -0
  130. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/__init__.py +0 -0
  131. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/_filter.py +0 -0
  132. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/composable_env.py +0 -0
  133. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harness.py +0 -0
  134. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harnesses/prompt.txt +0 -0
  135. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/harnesses/rlm.py +0 -0
  136. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/swe_debug_env.py +0 -0
  137. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/task.py +0 -0
  138. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/__init__.py +0 -0
  139. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/cp/__init__.py +0 -0
  140. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/cp/cp_task.py +0 -0
  141. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/cp/test_utils.py +0 -0
  142. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/harbor/__init__.py +0 -0
  143. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/harbor/harbor.py +0 -0
  144. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/lean/__init__.py +0 -0
  145. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/lean/lean_task.py +0 -0
  146. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/math/__init__.py +0 -0
  147. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/math/math_task.py +0 -0
  148. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/__init__.py +0 -0
  149. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/__init__.py +0 -0
  150. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/extract_fix_patch.sh +0 -0
  151. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/multi_swe/taskset.py +0 -0
  152. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/openswe/__init__.py +0 -0
  153. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/openswe/taskset.py +0 -0
  154. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/__init__.py +0 -0
  155. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/log_parser.py +0 -0
  156. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/r2e_gym/taskset.py +0 -0
  157. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/scale_swe/__init__.py +0 -0
  158. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/scale_swe/taskset.py +0 -0
  159. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/shared/__init__.py +0 -0
  160. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/shared/test_patch.py +0 -0
  161. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_bench/__init__.py +0 -0
  162. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_bench/taskset.py +0 -0
  163. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_lego/__init__.py +0 -0
  164. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_lego/taskset.py +0 -0
  165. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/__init__.py +0 -0
  166. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/log_parsers.py +0 -0
  167. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_rebench_v2/taskset.py +0 -0
  168. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_smith/__init__.py +0 -0
  169. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_smith/taskset.py +0 -0
  170. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/composable/tasksets/swe/swe_tasksets.py +0 -0
  171. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/gym_env.py +0 -0
  172. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/harbor_env/__init__.py +0 -0
  173. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/harbor_env/env.py +0 -0
  174. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/harbor_env/mcp.py +0 -0
  175. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/mcp_env.py +0 -0
  176. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/opencode_env.py +0 -0
  177. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/opencode_qa_env.py +0 -0
  178. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/opencode_rlm_env.py +0 -0
  179. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/rlm_env.py +0 -0
  180. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/sandbox_mixin.py +0 -0
  181. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/utils/__init__.py +0 -0
  182. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/utils/file_locks.py +0 -0
  183. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/experimental/utils/git_checkout_cache.py +0 -0
  184. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/README.md +0 -0
  185. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/__init__.py +0 -0
  186. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/README.md +0 -0
  187. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/__init__.py +0 -0
  188. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/browser_env.py +0 -0
  189. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/modes/__init__.py +0 -0
  190. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/modes/base.py +0 -0
  191. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/modes/cua_mode.py +0 -0
  192. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/browser_env/modes/dom_mode.py +0 -0
  193. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/openenv_env.py +0 -0
  194. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/reasoninggym_env.py +0 -0
  195. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/integrations/textarena_env.py +0 -0
  196. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/multiturn_env.py +0 -0
  197. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/python_env.py +0 -0
  198. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/sandbox_env.py +0 -0
  199. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/singleturn_env.py +0 -0
  200. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/stateful_tool_env.py +0 -0
  201. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/envs/tool_env.py +0 -0
  202. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/errors.py +0 -0
  203. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/gepa/__init__.py +0 -0
  204. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/gepa/adapter.py +0 -0
  205. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/gepa/config.py +0 -0
  206. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/gepa/display.py +0 -0
  207. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/gepa/gepa_utils.py +0 -0
  208. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/parsers/__init__.py +0 -0
  209. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/parsers/maybe_think_parser.py +0 -0
  210. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/parsers/parser.py +0 -0
  211. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/parsers/think_parser.py +0 -0
  212. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/parsers/xml_parser.py +0 -0
  213. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/README.md +0 -0
  214. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/__init__.py +0 -0
  215. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/inference/__init__.py +0 -0
  216. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/inference/client.py +0 -0
  217. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/inference/server.py +0 -0
  218. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/trainer/__init__.py +0 -0
  219. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/trainer/config.py +0 -0
  220. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/trainer/orchestrator.py +0 -0
  221. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/trainer/trainer.py +0 -0
  222. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rl/trainer/utils.py +0 -0
  223. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/__init__.py +0 -0
  224. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/experimental/hybrid_math_rubric.py +0 -0
  225. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/judge_rubric.py +0 -0
  226. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/math_rubric.py +0 -0
  227. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/rubric.py +0 -0
  228. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/rubrics/rubric_group.py +0 -0
  229. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/__init__.py +0 -0
  230. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/build.py +0 -0
  231. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/eval.py +0 -0
  232. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/gepa.py +0 -0
  233. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/init.py +0 -0
  234. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/install.py +0 -0
  235. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/rl.py +0 -0
  236. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/setup.py +0 -0
  237. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/train.py +0 -0
  238. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/tui.py +0 -0
  239. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/scripts/vllm.py +0 -0
  240. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/__init__.py +0 -0
  241. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/client/env_client.py +0 -0
  242. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/client/zmq_env_client.py +0 -0
  243. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/server/__init__.py +0 -0
  244. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/server/env_router.py +0 -0
  245. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/server/env_server.py +0 -0
  246. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/server/env_worker.py +0 -0
  247. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/server/zmq_env_server.py +0 -0
  248. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/serve/types.py +0 -0
  249. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/types.py +0 -0
  250. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/__init__.py +0 -0
  251. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/async_utils.py +0 -0
  252. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/client_utils.py +0 -0
  253. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/config_utils.py +0 -0
  254. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/data_utils.py +0 -0
  255. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/display_utils.py +0 -0
  256. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/env_config_utils.py +0 -0
  257. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/env_utils.py +0 -0
  258. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/error_utils.py +0 -0
  259. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/eval_display.py +0 -0
  260. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/eval_utils.py +0 -0
  261. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/heartbeat.py +0 -0
  262. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/import_utils.py +0 -0
  263. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/install_utils.py +0 -0
  264. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/interception_utils.py +0 -0
  265. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/logging_utils.py +0 -0
  266. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/message_utils.py +0 -0
  267. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/metric_utils.py +0 -0
  268. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/path_utils.py +0 -0
  269. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/pricing_utils.py +0 -0
  270. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/process_utils.py +0 -0
  271. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/response_utils.py +0 -0
  272. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/save_utils.py +0 -0
  273. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/serve_utils.py +0 -0
  274. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/thread_utils.py +0 -0
  275. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/threaded_sandbox_client.py +0 -0
  276. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/tool_utils.py +0 -0
  277. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/usage_utils.py +0 -0
  278. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/utils/version_utils.py +0 -0
  279. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/ENVIRONMENT_BEST_PRACTICES.md +0 -0
  280. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/README.md +0 -0
  281. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/RE_MIGRATION.md +0 -0
  282. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/__init__.py +0 -0
  283. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/artifact.py +0 -0
  284. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/config.py +0 -0
  285. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/env.py +0 -0
  286. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/harness.py +0 -0
  287. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/model.py +0 -0
  288. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/program.py +0 -0
  289. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/runtime.py +0 -0
  290. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/runtime_handles.py +0 -0
  291. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/sandbox.py +0 -0
  292. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/state.py +0 -0
  293. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/task.py +0 -0
  294. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/taskset.py +0 -0
  295. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/toolset.py +0 -0
  296. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/types.py +0 -0
  297. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/user.py +0 -0
  298. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/__init__.py +0 -0
  299. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/binding_utils.py +0 -0
  300. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/config_callable_utils.py +0 -0
  301. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/config_utils.py +0 -0
  302. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/endpoint_utils.py +0 -0
  303. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/json_utils.py +0 -0
  304. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/judge_utils.py +0 -0
  305. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/lifecycle_utils.py +0 -0
  306. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/logging_utils.py +0 -0
  307. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/mcp_proxy_utils.py +0 -0
  308. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/mcp_utils.py +0 -0
  309. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/object_utils.py +0 -0
  310. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/program_utils.py +0 -0
  311. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/prompt_utils.py +0 -0
  312. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/runtime_owner_utils.py +0 -0
  313. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/runtime_registry.py +0 -0
  314. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/sandbox_program_utils.py +0 -0
  315. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/sandbox_python_utils.py +0 -0
  316. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/sandbox_utils.py +0 -0
  317. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/scoring_utils.py +0 -0
  318. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/serialization_utils.py +0 -0
  319. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/task_freeze_utils.py +0 -0
  320. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/taskset_utils.py +0 -0
  321. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/tool_utils.py +0 -0
  322. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/toolset_utils.py +0 -0
  323. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/trajectory_utils.py +0 -0
  324. {verifiers-0.1.15.dev154 → verifiers-0.1.15.dev156}/verifiers/v1/utils/usage_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: verifiers
3
- Version: 0.1.15.dev154
3
+ Version: 0.1.15.dev156
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
@@ -1,7 +1,9 @@
1
- import pytest
2
1
  from types import SimpleNamespace
3
2
 
3
+ import pytest
4
+
4
5
  from verifiers.clients.openai_chat_completions_client import OpenAIChatCompletionsClient
6
+ from verifiers.errors import EmptyModelResponseError
5
7
  from verifiers.types import (
6
8
  AssistantMessage,
7
9
  ImageUrlContentPart,
@@ -18,6 +20,11 @@ from verifiers.types import (
18
20
  from verifiers.utils.response_utils import parse_response_message
19
21
 
20
22
 
23
+ class _OpenAIMessage(SimpleNamespace):
24
+ def model_dump(self):
25
+ return self.__dict__
26
+
27
+
21
28
  @pytest.mark.asyncio
22
29
  async def test_openai_to_native_prompt_with_typed_multimodal_content_parts():
23
30
  client = OpenAIChatCompletionsClient(object())
@@ -52,6 +59,53 @@ async def test_openai_to_native_prompt_with_typed_multimodal_content_parts():
52
59
  ]
53
60
 
54
61
 
62
+ @pytest.mark.asyncio
63
+ async def test_openai_chat_rejects_reasoning_only_native_response():
64
+ client = OpenAIChatCompletionsClient(object())
65
+ native_response = SimpleNamespace(
66
+ choices=[
67
+ SimpleNamespace(
68
+ message=_OpenAIMessage(
69
+ content=None,
70
+ reasoning_content="hidden chain",
71
+ tool_calls=None,
72
+ )
73
+ )
74
+ ]
75
+ )
76
+
77
+ with pytest.raises(EmptyModelResponseError, match="reasoning but no content"):
78
+ await client.raise_from_native_response(native_response)
79
+
80
+
81
+ @pytest.mark.asyncio
82
+ async def test_openai_chat_accepts_refusal_with_reasoning_native_response():
83
+ client = OpenAIChatCompletionsClient(object())
84
+ native_response = SimpleNamespace(
85
+ id="chatcmpl_refusal",
86
+ created=0,
87
+ model="gpt-5.2",
88
+ usage=None,
89
+ choices=[
90
+ SimpleNamespace(
91
+ finish_reason="stop",
92
+ message=_OpenAIMessage(
93
+ content=None,
94
+ refusal="I cannot help with that.",
95
+ reasoning_content="hidden chain",
96
+ tool_calls=None,
97
+ ),
98
+ )
99
+ ],
100
+ )
101
+
102
+ await client.raise_from_native_response(native_response)
103
+ response = await client.from_native_response(native_response)
104
+
105
+ assert response.message.content == "I cannot help with that."
106
+ assert response.message.reasoning_content == "hidden chain"
107
+
108
+
55
109
  @pytest.mark.asyncio
56
110
  async def test_anthropic_to_native_prompt_with_typed_multimodal_content_parts():
57
111
  pytest.importorskip("anthropic")
@@ -228,6 +282,24 @@ async def test_anthropic_from_native_response_always_parses_reasoning():
228
282
  assert response.message.content == "final answer"
229
283
 
230
284
 
285
+ @pytest.mark.asyncio
286
+ async def test_anthropic_rejects_reasoning_only_native_response():
287
+ pytest.importorskip("anthropic")
288
+ from verifiers.clients.anthropic_messages_client import AnthropicMessagesClient
289
+
290
+ client = AnthropicMessagesClient(object())
291
+ native_response = SimpleNamespace(
292
+ id="msg_think",
293
+ model="claude-haiku-4-5",
294
+ stop_reason="end_turn",
295
+ usage=SimpleNamespace(input_tokens=1, output_tokens=1),
296
+ content=[SimpleNamespace(type="thinking", thinking="hidden chain")],
297
+ )
298
+
299
+ with pytest.raises(EmptyModelResponseError, match="reasoning but no content"):
300
+ await client.raise_from_native_response(native_response)
301
+
302
+
231
303
  @pytest.mark.asyncio
232
304
  async def test_anthropic_tool_call_round_trips_thinking_blocks():
233
305
  pytest.importorskip("anthropic")
@@ -17,6 +17,12 @@ from verifiers.envs.experimental.composable import (
17
17
  TaskSet,
18
18
  discover_sibling_dir,
19
19
  )
20
+ from verifiers.envs.experimental.composable.harnesses.mini_swe_agent import (
21
+ build_mini_swe_agent_install_script,
22
+ )
23
+ from verifiers.envs.experimental.composable.harnesses.opencode import (
24
+ build_install_script as build_opencode_install_script,
25
+ )
20
26
 
21
27
 
22
28
  # ── Mock Rubrics ──────────────────────────────────────────────────────
@@ -187,6 +193,27 @@ def test_taskset_repr():
187
193
  assert "3" in repr(ts)
188
194
 
189
195
 
196
+ def test_composable_mini_swe_agent_unversioned_package_uses_unpinned_requirement():
197
+ setup = build_mini_swe_agent_install_script(package=" mini-swe-agent ")
198
+
199
+ assert (
200
+ "vf_python_install --target /opt/mini-swe-agent/prefix/site-packages mini-swe-agent"
201
+ in setup
202
+ )
203
+ assert "mini-swe-agent==mini-swe-agent" not in setup
204
+
205
+
206
+ def test_composable_opencode_unversioned_release_uses_latest_download_url():
207
+ setup = build_opencode_install_script(
208
+ release=" PrimeIntellect-ai/opencode ",
209
+ install_ripgrep=False,
210
+ )
211
+
212
+ assert "OPENCODE_RELEASE_REPO=PrimeIntellect-ai/opencode" in setup
213
+ assert "OPENCODE_RELEASE_PATH=releases/latest/download" in setup
214
+ assert "releases/download/vPrimeIntellect-ai/opencode" not in setup
215
+
216
+
190
217
  @pytest.mark.asyncio
191
218
  async def test_composable_env_exports_task_workdir():
192
219
  taskset = MockSandboxTaskSet(dataset=_make_dataset(), name="test")
@@ -189,7 +189,7 @@ class TestMultiTurnEnv:
189
189
 
190
190
  async def add_model_response(self, state, prompt_messages, response): # type: ignore[override]
191
191
  await super().add_model_response(state, prompt_messages, response)
192
- await asyncio.sleep(0.05)
192
+ await asyncio.sleep(1)
193
193
 
194
194
  env = SlowMultiTurnEnv(
195
195
  client=mock_client,
@@ -197,7 +197,7 @@ class TestMultiTurnEnv:
197
197
  dataset=sample_chat_dataset,
198
198
  parser=Parser(),
199
199
  rubric=Rubric(),
200
- timeout_seconds=0.01,
200
+ timeout_seconds=0.2,
201
201
  )
202
202
  mock_client.set_default_response("Still going")
203
203
 
@@ -8,6 +8,7 @@ from verifiers.clients.openai_responses_client import (
8
8
  OPENAI_RESPONSES_OUTPUT_FIELD,
9
9
  OpenAIResponsesClient,
10
10
  )
11
+ from verifiers.errors import EmptyModelResponseError
11
12
  from verifiers.types import (
12
13
  AssistantMessage,
13
14
  ClientConfig,
@@ -133,6 +134,24 @@ async def test_get_native_response_normalizes_sampling_args_and_tools():
133
134
  ]
134
135
 
135
136
 
137
+ @pytest.mark.asyncio
138
+ async def test_raise_from_native_response_rejects_reasoning_only_response():
139
+ native_response = SimpleNamespace(
140
+ output=[
141
+ {
142
+ "type": "reasoning",
143
+ "id": "rs_1",
144
+ "summary": [{"type": "summary_text", "text": "thinking"}],
145
+ "status": "completed",
146
+ }
147
+ ]
148
+ )
149
+ client = OpenAIResponsesClient(object())
150
+
151
+ with pytest.raises(EmptyModelResponseError, match="reasoning but no content"):
152
+ await client.raise_from_native_response(native_response)
153
+
154
+
136
155
  @pytest.mark.asyncio
137
156
  async def test_to_native_tool_omits_strict_when_unset():
138
157
  client = OpenAIResponsesClient(object())
@@ -355,6 +355,14 @@ async def test_renderer_client_rejects_empty_dict_native_response():
355
355
  await client.raise_from_native_response({})
356
356
 
357
357
 
358
+ @pytest.mark.asyncio
359
+ async def test_renderer_client_rejects_reasoning_only_native_response():
360
+ client = object.__new__(RendererClient)
361
+
362
+ with pytest.raises(EmptyModelResponseError, match="reasoning but no content"):
363
+ await client.raise_from_native_response({"reasoning_content": "hidden chain"})
364
+
365
+
358
366
  @pytest.mark.asyncio
359
367
  async def test_from_native_response_uses_request_id_and_token_lengths():
360
368
  """vLLM's /inference/v1/generate returns ``request_id`` (not ``id``) and
@@ -279,11 +279,47 @@ def test_opencode_config_owns_opencode_harness_fields() -> None:
279
279
  assert harness.config.max_turns == 2
280
280
  assert "apt-get -o Acquire::Retries=3 update" in setup
281
281
  assert "apt-get -o Acquire::Retries=3 install" in setup
282
+ assert "OPENCODE_RELEASE_REPO=PrimeIntellect-ai/opencode" in setup
283
+ assert "OPENCODE_RELEASE_PATH=releases/download/v1.1.63-rl2" in setup
282
284
  assert "/workspace" in cast(str, command[2])
283
285
  assert '"webfetch": false' in cast(str, mcp_setup)
284
286
  assert "/opencode/system.txt" in cast(dict[str, object], program["files"])
285
287
 
286
288
 
289
+ @pytest.mark.parametrize(
290
+ "release", ["PrimeIntellect-ai/opencode@latest", " PrimeIntellect-ai/opencode "]
291
+ )
292
+ def test_opencode_latest_release_uses_latest_download_url(release: str) -> None:
293
+ harness = OpenCode(
294
+ config=OpenCodeConfig(
295
+ program=OpenCodeProgramConfig(
296
+ release=release,
297
+ install_ripgrep=False,
298
+ )
299
+ )
300
+ )
301
+ program = cast(dict[str, object], harness.config.program.data())
302
+ setup = cast(str, program["setup"])
303
+
304
+ assert "OPENCODE_RELEASE_REPO=PrimeIntellect-ai/opencode" in setup
305
+ assert "OPENCODE_RELEASE_PATH=releases/latest/download" in setup
306
+
307
+
308
+ def test_opencode_custom_release_uses_versioned_spec() -> None:
309
+ harness = OpenCode(
310
+ config=OpenCodeConfig(
311
+ program=OpenCodeProgramConfig(
312
+ release="Example/open-code@v2.0.0",
313
+ )
314
+ )
315
+ )
316
+ program = cast(dict[str, object], harness.config.program.data())
317
+ setup = cast(str, program["setup"])
318
+
319
+ assert "OPENCODE_RELEASE_REPO=Example/open-code" in setup
320
+ assert "OPENCODE_RELEASE_PATH=releases/download/v2.0.0" in setup
321
+
322
+
287
323
  @pytest.mark.parametrize(
288
324
  ("harness_cls", "config_cls", "program_cls"),
289
325
  [
@@ -357,7 +393,7 @@ def test_pi_harness_writes_intercepted_model_and_mcp_config() -> None:
357
393
  assert "apt-get -o Acquire::Retries=3 update" in setup
358
394
  assert "apt-get -o Acquire::Retries=3 install" in setup
359
395
  assert harness.config.program.package == PI_DEFAULT_PACKAGE
360
- assert PI_DEFAULT_PACKAGE == "@earendil-works/pi-coding-agent"
396
+ assert PI_DEFAULT_PACKAGE == "@earendil-works/pi-coding-agent@latest"
361
397
  assert f"npm install -g --ignore-scripts {PI_DEFAULT_PACKAGE}" in setup
362
398
  assert "mariozechner" not in setup
363
399
  assert '"baseUrl": "${OPENAI_BASE_URL}"' in mcp_setup
@@ -368,6 +404,18 @@ def test_pi_harness_writes_intercepted_model_and_mcp_config() -> None:
368
404
  assert f'"command": "{SANDBOX_PYTHON}"' in mcp_setup
369
405
 
370
406
 
407
+ def test_pi_harness_preserves_scoped_npm_package_versions() -> None:
408
+ harness = Pi(
409
+ config=PiConfig(
410
+ program=PiProgramConfig(package="@anthropic-ai/claude-code@1.2.3")
411
+ )
412
+ )
413
+ program = cast(dict[str, object], harness.config.program.data())
414
+ setup = cast(str, program["setup"])
415
+
416
+ assert "npm install -g --ignore-scripts @anthropic-ai/claude-code@1.2.3" in setup
417
+
418
+
371
419
  def test_terminus_2_harness_builds_sandbox_program() -> None:
372
420
  harness = Terminus2(
373
421
  config=Terminus2Config(
@@ -80,11 +80,38 @@ def test_mini_swe_agent_builds_sandbox_program():
80
80
  assert "model.model_kwargs.parallel_tool_calls=true" in script
81
81
  assert "apt-get -o Acquire::Retries=3 update" in cast(str, program["setup"])
82
82
  assert "apt-get -o Acquire::Retries=3 install" in cast(str, program["setup"])
83
+ assert "mini-swe-agent==2.2.8" in cast(str, program["setup"])
83
84
  assert "/mini-swe-agent/prompt.txt" in cast(dict[str, object], program["files"])
84
85
  assert "/mini-swe-agent/system.txt" in cast(dict[str, object], program["files"])
85
86
  assert "mini_swe_agent_log" in cast(dict[str, object], program["artifacts"])
86
87
 
87
88
 
89
+ @pytest.mark.parametrize("package", ["mini-swe-agent@latest", " mini-swe-agent "])
90
+ def test_mini_swe_agent_latest_package_uses_unpinned_pip_requirement(package: str):
91
+ harness = MiniSWEAgent(
92
+ config=MiniSWEAgentConfig(program=MiniSWEAgentProgramConfig(package=package))
93
+ )
94
+ program = cast(dict[str, Any], harness.config.program.data())
95
+ setup = cast(str, program["setup"])
96
+
97
+ assert (
98
+ "vf_python_install --target /opt/mini-swe-agent/prefix/site-packages mini-swe-agent"
99
+ in setup
100
+ )
101
+
102
+
103
+ def test_mini_swe_agent_pinned_package_uses_pip_requirement():
104
+ harness = MiniSWEAgent(
105
+ config=MiniSWEAgentConfig(
106
+ program=MiniSWEAgentProgramConfig(package="mini-swe-agent@2.2.7")
107
+ )
108
+ )
109
+ program = cast(dict[str, Any], harness.config.program.data())
110
+ setup = cast(str, program["setup"])
111
+
112
+ assert "mini-swe-agent==2.2.7" in setup
113
+
114
+
88
115
  def test_mini_swe_agent_composes_with_harbor_taskset(
89
116
  tmp_path: Path, monkeypatch: pytest.MonkeyPatch
90
117
  ):
@@ -29,7 +29,7 @@ from anthropic.types import (
29
29
  )
30
30
 
31
31
  from verifiers.clients.client import Client
32
- from verifiers.errors import OverlongPromptError
32
+ from verifiers.errors import EmptyModelResponseError, OverlongPromptError
33
33
  from verifiers.types import (
34
34
  AssistantMessage,
35
35
  ClientConfig,
@@ -378,7 +378,29 @@ class AnthropicMessagesClient(
378
378
  )
379
379
 
380
380
  async def raise_from_native_response(self, response: AnthropicMessage) -> None:
381
- pass
381
+ if response is None:
382
+ raise EmptyModelResponseError("Model returned no response")
383
+
384
+ has_text = False
385
+ has_tool_call = False
386
+ has_reasoning = False
387
+ for content_block in getattr(response, "content", []) or []:
388
+ block_type = getattr(content_block, "type", None)
389
+ if block_type == "text" and getattr(content_block, "text", None):
390
+ has_text = True
391
+ elif block_type == "tool_use":
392
+ has_tool_call = True
393
+ elif block_type in {"thinking", "redacted_thinking"}:
394
+ has_reasoning = True
395
+
396
+ if not (has_text or has_tool_call):
397
+ if has_reasoning:
398
+ raise EmptyModelResponseError(
399
+ "Model returned reasoning but no content and did not call any tools"
400
+ )
401
+ raise EmptyModelResponseError(
402
+ "Model returned no content and did not call any tools"
403
+ )
382
404
 
383
405
  async def from_native_response(self, response: AnthropicMessage) -> Response:
384
406
  def parse_content(
@@ -43,6 +43,7 @@ from verifiers.types import (
43
43
  ClientConfig,
44
44
  FinishReason,
45
45
  Message,
46
+ MessageContent,
46
47
  Messages,
47
48
  Response,
48
49
  ResponseMessage,
@@ -119,6 +120,14 @@ def content_to_text(content: Any) -> str:
119
120
  return ""
120
121
 
121
122
 
123
+ def parse_refusal_content(message: Any) -> str | None:
124
+ if isinstance(message, Mapping):
125
+ refusal = message.get("refusal")
126
+ else:
127
+ refusal = getattr(message, "refusal", None)
128
+ return refusal if isinstance(refusal, str) and refusal else None
129
+
130
+
122
131
  DEFAULT_REASONING_FIELDS = [
123
132
  "reasoning", # vLLM, Together AI, OpenRouter
124
133
  "reasoning_content", # DeepSeek, Qwen/DashScope, SGLang, Fireworks AI, Kimi/Moonshot
@@ -331,15 +340,29 @@ class OpenAIChatCompletionsClient(
331
340
  f"Model returned {len(response.choices)} choices, expected 1"
332
341
  )
333
342
  message = response.choices[0].message
334
- has_content = bool(content_to_text(getattr(message, "content", None)))
343
+ has_content = bool(
344
+ content_to_text(getattr(message, "content", None))
345
+ or parse_refusal_content(message)
346
+ )
335
347
  has_tool_calls = bool(getattr(message, "tool_calls", None))
336
348
  has_reasoning = bool(parse_reasoning_content(message))
337
- if not (has_content or has_tool_calls or has_reasoning):
349
+ if not (has_content or has_tool_calls):
350
+ if has_reasoning:
351
+ raise EmptyModelResponseError(
352
+ "Model returned reasoning but no content and did not call any tools"
353
+ )
338
354
  raise EmptyModelResponseError(
339
- "Model returned no content, reasoning, and did not call any tools"
355
+ "Model returned no content and did not call any tools"
340
356
  )
341
357
 
342
358
  async def from_native_response(self, response: OpenAIChatResponse) -> Response:
359
+ def parse_content(response: OpenAIChatResponse) -> MessageContent | None:
360
+ message = response.choices[0].message
361
+ content = message.content
362
+ if content_to_text(content):
363
+ return content
364
+ return parse_refusal_content(message)
365
+
343
366
  def parse_single_tool_call(tool_call: Any) -> ToolCall | None:
344
367
  if isinstance(tool_call, ChatCompletionMessageFunctionToolCall):
345
368
  return ToolCall(
@@ -511,7 +534,7 @@ class OpenAIChatCompletionsClient(
511
534
  model=model,
512
535
  usage=parse_usage(response),
513
536
  message=ResponseMessage(
514
- content=response.choices[0].message.content,
537
+ content=parse_content(response),
515
538
  reasoning_content=parse_reasoning_content(response.choices[0].message),
516
539
  finish_reason=parse_finish_reason(response),
517
540
  is_truncated=parse_is_truncated(response),
@@ -293,9 +293,13 @@ class OpenAIResponsesClient(
293
293
  ):
294
294
  has_text = True
295
295
 
296
- if not (has_text or has_tool_call or has_reasoning):
296
+ if not (has_text or has_tool_call):
297
+ if has_reasoning:
298
+ raise EmptyModelResponseError(
299
+ "Model returned reasoning but no content and did not call any tools"
300
+ )
297
301
  raise EmptyModelResponseError(
298
- "Model returned no content, reasoning, and did not call any tools"
302
+ "Model returned no content and did not call any tools"
299
303
  )
300
304
 
301
305
  async def from_native_response(
@@ -641,9 +641,13 @@ class RendererClient(
641
641
  # model having tried to call a tool, so we don't filter by status here.
642
642
  has_tool_calls = bool(response.get("tool_calls"))
643
643
  has_reasoning = bool(response.get("reasoning_content"))
644
- if not (has_content or has_tool_calls or has_reasoning):
644
+ if not (has_content or has_tool_calls):
645
+ if has_reasoning:
646
+ raise EmptyModelResponseError(
647
+ "Model returned reasoning but no content and did not call any tools"
648
+ )
645
649
  raise EmptyModelResponseError(
646
- "Model returned no content, reasoning, and did not call any tools"
650
+ "Model returned no content and did not call any tools"
647
651
  )
648
652
 
649
653
  async def from_native_response(self, response: dict[str, Any]) -> Response:
@@ -9,7 +9,7 @@ from verifiers.envs.experimental.composable.harnesses.rlm import (
9
9
  )
10
10
  from verifiers.envs.experimental.composable.harnesses.opencode import (
11
11
  DEFAULT_DISABLED_TOOLS,
12
- DEFAULT_RELEASE_SHA256,
12
+ DEFAULT_RELEASE,
13
13
  DEFAULT_SYSTEM_PROMPT,
14
14
  OPENCODE_INSTALL_SCRIPT,
15
15
  build_install_script as build_opencode_install_script,
@@ -39,7 +39,7 @@ __all__ = [
39
39
  "build_opencode_run_command",
40
40
  "OPENCODE_INSTALL_SCRIPT",
41
41
  "DEFAULT_DISABLED_TOOLS",
42
- "DEFAULT_RELEASE_SHA256",
42
+ "DEFAULT_RELEASE",
43
43
  "DEFAULT_SYSTEM_PROMPT",
44
44
  "mini_swe_agent_harness",
45
45
  "build_mini_swe_agent_install_script",
@@ -4,6 +4,7 @@ from pathlib import PurePosixPath
4
4
  import shlex
5
5
 
6
6
  from harnesses.mini_swe_agent import (
7
+ MINI_SWE_AGENT_DEFAULT_PACKAGE,
7
8
  build_mini_swe_agent_install_script as build_packaged_mini_swe_agent_install_script,
8
9
  )
9
10
 
@@ -13,11 +14,7 @@ DEFAULT_SITE_PACKAGES_DIR = f"{DEFAULT_PREFIX_DIR}/site-packages"
13
14
  DEFAULT_MINI_BINARY = f"{DEFAULT_PREFIX_DIR}/bin/mini"
14
15
  MINI_SWE_AGENT_CLI_PACKAGE = "mini-swe-agent"
15
16
  MINI_SWE_AGENT_CLI_VERSION = "2.2.8"
16
- MINI_SWE_AGENT_CLI_SHA256 = (
17
- "694df4de1337e665e3cd82e99f93374f573bf52b8e7c362ac5d8045ad9f7c37c"
18
- )
19
- DEFAULT_PACKAGE_VERSION = MINI_SWE_AGENT_CLI_VERSION
20
- DEFAULT_PACKAGE_SHA256 = MINI_SWE_AGENT_CLI_SHA256
17
+ DEFAULT_PACKAGE = MINI_SWE_AGENT_DEFAULT_PACKAGE
21
18
  DEFAULT_INSTRUCTION_PATH = "/mini-swe-agent/prompt.txt"
22
19
  DEFAULT_SYSTEM_PROMPT_PATH = "/mini-swe-agent/system.txt"
23
20
  DEFAULT_LOG_DIR = "/logs/agent"
@@ -30,14 +27,12 @@ DEFAULT_ENVIRONMENT_TIMEOUT = 120
30
27
 
31
28
 
32
29
  def build_mini_swe_agent_install_script(
33
- package_version: str = DEFAULT_PACKAGE_VERSION,
34
- package_sha256: str = DEFAULT_PACKAGE_SHA256,
30
+ package: str = DEFAULT_PACKAGE,
35
31
  prefix_dir: str = DEFAULT_PREFIX_DIR,
36
32
  ) -> str:
37
33
  """Build the shell script that installs mini-SWE-agent."""
38
34
  return build_packaged_mini_swe_agent_install_script(
39
- package_version=package_version,
40
- package_sha256=package_sha256,
35
+ package=package,
41
36
  prefix_dir=prefix_dir,
42
37
  )
43
38
 
@@ -127,7 +122,6 @@ MINI_SWE_AGENT_CONFIG = {
127
122
  "install_script": MINI_SWE_AGENT_INSTALL_SCRIPT,
128
123
  "cli_package": MINI_SWE_AGENT_CLI_PACKAGE,
129
124
  "cli_version": MINI_SWE_AGENT_CLI_VERSION,
130
- "cli_sha256": MINI_SWE_AGENT_CLI_SHA256,
131
125
  }
132
126
 
133
127
 
@@ -139,8 +133,7 @@ def mini_swe_agent_harness(
139
133
  system_prompt_path: str = DEFAULT_SYSTEM_PROMPT_PATH,
140
134
  log_path: str = DEFAULT_LOG_PATH,
141
135
  trajectory_path: str = DEFAULT_TRAJECTORY_PATH,
142
- package_version: str = DEFAULT_PACKAGE_VERSION,
143
- package_sha256: str = DEFAULT_PACKAGE_SHA256,
136
+ package: str = DEFAULT_PACKAGE,
144
137
  config_spec: str = DEFAULT_CONFIG_SPEC,
145
138
  model_class: str = DEFAULT_MODEL_CLASS,
146
139
  environment_timeout: int = DEFAULT_ENVIRONMENT_TIMEOUT,
@@ -160,8 +153,7 @@ def mini_swe_agent_harness(
160
153
  # into mini's agent.system_template at runtime.
161
154
  return Harness(
162
155
  install_script=build_mini_swe_agent_install_script(
163
- package_version=package_version,
164
- package_sha256=package_sha256,
156
+ package=package,
165
157
  ),
166
158
  run_command=build_mini_swe_agent_run_command(
167
159
  agent_workdir=agent_workdir,
@@ -13,13 +13,11 @@ import json
13
13
  import shlex
14
14
  from pathlib import Path, PurePosixPath
15
15
 
16
+ from harnesses.utils import split_versioned_agent_spec
17
+
16
18
  # ── Defaults ─────────────────────────────────────────────────────────────
17
19
 
18
- DEFAULT_RELEASE_REPO = "PrimeIntellect-ai/opencode"
19
- DEFAULT_RELEASE_VERSION = "1.1.63-rl2"
20
- DEFAULT_RELEASE_SHA256 = (
21
- "47f4102796da50769e27d2c9ea6a9cf7941f76898390cb497278cab39c4b6ed4"
22
- )
20
+ DEFAULT_RELEASE = "PrimeIntellect-ai/opencode@1.1.63-rl2"
23
21
  DEFAULT_SYSTEM_PROMPT = (Path(__file__).parent / "prompt.txt").read_text()
24
22
 
25
23
  DEFAULT_DISABLED_TOOLS = [
@@ -49,9 +47,7 @@ DEFAULT_DISABLED_TOOLS = [
49
47
 
50
48
 
51
49
  def build_install_script(
52
- release_repo: str = DEFAULT_RELEASE_REPO,
53
- release_version: str = DEFAULT_RELEASE_VERSION,
54
- release_sha256: str = DEFAULT_RELEASE_SHA256,
50
+ release: str = DEFAULT_RELEASE,
55
51
  install_ripgrep: bool = True,
56
52
  ) -> str:
57
53
  """Build the shell script that installs OpenCode in a sandbox."""
@@ -60,7 +56,15 @@ def build_install_script(
60
56
  if install_ripgrep
61
57
  else ""
62
58
  )
63
- sha256_check = f'echo "{release_sha256} /tmp/opencode.tar.gz" | sha256sum -c -'
59
+ release_repo, release_version = split_versioned_agent_spec(release)
60
+ release_path = "releases/latest/download"
61
+ if release_version and release_version != "latest":
62
+ release_tag = (
63
+ release_version
64
+ if release_version.startswith("v")
65
+ else f"v{release_version}"
66
+ )
67
+ release_path = f"releases/download/{release_tag}"
64
68
  # Acquire::Retries=3 mitigates transient archive.ubuntu.com CDN sync mismatches
65
69
  # (e.g. "File has unexpected size ... Mirror sync in progress?"). See launchpad
66
70
  # bug #1876035. apt's default retries is 0, so one bad fetch fails the rollout.
@@ -69,8 +73,8 @@ set -e
69
73
  apt-get -o Acquire::Retries=3 update -qq && apt-get -o Acquire::Retries=3 install -y -qq curl tar > /dev/null 2>&1
70
74
  {rg_install}
71
75
 
72
- OPENCODE_RELEASE_REPO="{release_repo}"
73
- OPENCODE_RELEASE_VERSION="{release_version}"
76
+ OPENCODE_RELEASE_REPO={shlex.quote(release_repo)}
77
+ OPENCODE_RELEASE_PATH={shlex.quote(release_path)}
74
78
 
75
79
  case "$(uname -m)" in
76
80
  x86_64) OPENCODE_ARCH=x64 ;;
@@ -79,15 +83,13 @@ case "$(uname -m)" in
79
83
  esac
80
84
 
81
85
  OPENCODE_ASSET="opencode-linux-$OPENCODE_ARCH.tar.gz"
82
- OPENCODE_RELEASE_TAG="${{OPENCODE_RELEASE_VERSION#v}}"
83
- OPENCODE_RELEASE_URL="https://github.com/$OPENCODE_RELEASE_REPO/releases/download/v$OPENCODE_RELEASE_TAG/$OPENCODE_ASSET"
86
+ OPENCODE_RELEASE_URL="https://github.com/$OPENCODE_RELEASE_REPO/$OPENCODE_RELEASE_PATH/$OPENCODE_ASSET"
84
87
 
85
88
  mkdir -p "$HOME/.opencode/bin"
86
89
  if [ -x "$HOME/.opencode/bin/opencode" ]; then
87
90
  echo "OpenCode already installed, skipping download"
88
91
  else
89
92
  curl -fsSL "$OPENCODE_RELEASE_URL" -o /tmp/opencode.tar.gz
90
- {sha256_check}
91
93
  tar -xzf /tmp/opencode.tar.gz -C /tmp
92
94
  install -m 755 /tmp/opencode "$HOME/.opencode/bin/opencode"
93
95
  rm -f /tmp/opencode.tar.gz /tmp/opencode
@@ -246,9 +248,7 @@ def opencode_harness(
246
248
  agent_workdir: str = "/app",
247
249
  allow_git: bool = False,
248
250
  disable_compaction: bool = True,
249
- release_repo: str = DEFAULT_RELEASE_REPO,
250
- release_version: str = DEFAULT_RELEASE_VERSION,
251
- release_sha256: str = DEFAULT_RELEASE_SHA256,
251
+ release: str = DEFAULT_RELEASE,
252
252
  instruction_path: str = "/opencode/prompt.txt",
253
253
  system_prompt_path: str = "/opencode/system.txt",
254
254
  log_path: str = "/opencode/logs.txt",
@@ -276,9 +276,7 @@ def opencode_harness(
276
276
 
277
277
  return Harness(
278
278
  install_script=build_install_script(
279
- release_repo=release_repo,
280
- release_version=release_version,
281
- release_sha256=release_sha256,
279
+ release=release,
282
280
  ),
283
281
  run_command=build_opencode_run_command(
284
282
  agent_workdir=agent_workdir,